pngset.c (62083B)
1 /* pngset.c - storage of image information into info struct 2 * 3 * Copyright (c) 2018-2025 Cosmin Truta 4 * Copyright (c) 1998-2018 Glenn Randers-Pehrson 5 * Copyright (c) 1996-1997 Andreas Dilger 6 * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc. 7 * 8 * This code is released under the libpng license. 9 * For conditions of distribution and use, see the disclaimer 10 * and license in png.h 11 * 12 * The functions here are used during reads to store data from the file 13 * into the info struct, and during writes to store application data 14 * into the info struct for writing into the file. This abstracts the 15 * info struct and allows us to change the structure in the future. 16 */ 17 18 #include "pngpriv.h" 19 20 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED) 21 22 #ifdef PNG_bKGD_SUPPORTED 23 void PNGAPI 24 png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr, 25 png_const_color_16p background) 26 { 27 png_debug1(1, "in %s storage function", "bKGD"); 28 29 if (png_ptr == NULL || info_ptr == NULL || background == NULL) 30 return; 31 32 info_ptr->background = *background; 33 info_ptr->valid |= PNG_INFO_bKGD; 34 } 35 #endif 36 37 #ifdef PNG_cHRM_SUPPORTED 38 void PNGFAPI 39 png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr, 40 png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x, 41 png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y, 42 png_fixed_point blue_x, png_fixed_point blue_y) 43 { 44 png_debug1(1, "in %s storage function", "cHRM fixed"); 45 46 if (png_ptr == NULL || info_ptr == NULL) 47 return; 48 49 info_ptr->cHRM.redx = red_x; 50 info_ptr->cHRM.redy = red_y; 51 info_ptr->cHRM.greenx = green_x; 52 info_ptr->cHRM.greeny = green_y; 53 info_ptr->cHRM.bluex = blue_x; 54 info_ptr->cHRM.bluey = blue_y; 55 info_ptr->cHRM.whitex = white_x; 56 info_ptr->cHRM.whitey = white_y; 57 58 info_ptr->valid |= PNG_INFO_cHRM; 59 } 60 61 void PNGFAPI 62 png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr, 63 png_fixed_point int_red_X, png_fixed_point int_red_Y, 64 png_fixed_point int_red_Z, png_fixed_point int_green_X, 65 png_fixed_point int_green_Y, png_fixed_point int_green_Z, 66 png_fixed_point int_blue_X, png_fixed_point int_blue_Y, 67 png_fixed_point int_blue_Z) 68 { 69 png_XYZ XYZ; 70 png_xy xy; 71 72 png_debug1(1, "in %s storage function", "cHRM XYZ fixed"); 73 74 if (png_ptr == NULL || info_ptr == NULL) 75 return; 76 77 XYZ.red_X = int_red_X; 78 XYZ.red_Y = int_red_Y; 79 XYZ.red_Z = int_red_Z; 80 XYZ.green_X = int_green_X; 81 XYZ.green_Y = int_green_Y; 82 XYZ.green_Z = int_green_Z; 83 XYZ.blue_X = int_blue_X; 84 XYZ.blue_Y = int_blue_Y; 85 XYZ.blue_Z = int_blue_Z; 86 87 if (png_xy_from_XYZ(&xy, &XYZ) == 0) 88 { 89 info_ptr->cHRM = xy; 90 info_ptr->valid |= PNG_INFO_cHRM; 91 } 92 93 else 94 png_app_error(png_ptr, "invalid cHRM XYZ"); 95 } 96 97 # ifdef PNG_FLOATING_POINT_SUPPORTED 98 void PNGAPI 99 png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, 100 double white_x, double white_y, double red_x, double red_y, 101 double green_x, double green_y, double blue_x, double blue_y) 102 { 103 png_set_cHRM_fixed(png_ptr, info_ptr, 104 png_fixed(png_ptr, white_x, "cHRM White X"), 105 png_fixed(png_ptr, white_y, "cHRM White Y"), 106 png_fixed(png_ptr, red_x, "cHRM Red X"), 107 png_fixed(png_ptr, red_y, "cHRM Red Y"), 108 png_fixed(png_ptr, green_x, "cHRM Green X"), 109 png_fixed(png_ptr, green_y, "cHRM Green Y"), 110 png_fixed(png_ptr, blue_x, "cHRM Blue X"), 111 png_fixed(png_ptr, blue_y, "cHRM Blue Y")); 112 } 113 114 void PNGAPI 115 png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X, 116 double red_Y, double red_Z, double green_X, double green_Y, double green_Z, 117 double blue_X, double blue_Y, double blue_Z) 118 { 119 png_set_cHRM_XYZ_fixed(png_ptr, info_ptr, 120 png_fixed(png_ptr, red_X, "cHRM Red X"), 121 png_fixed(png_ptr, red_Y, "cHRM Red Y"), 122 png_fixed(png_ptr, red_Z, "cHRM Red Z"), 123 png_fixed(png_ptr, green_X, "cHRM Green X"), 124 png_fixed(png_ptr, green_Y, "cHRM Green Y"), 125 png_fixed(png_ptr, green_Z, "cHRM Green Z"), 126 png_fixed(png_ptr, blue_X, "cHRM Blue X"), 127 png_fixed(png_ptr, blue_Y, "cHRM Blue Y"), 128 png_fixed(png_ptr, blue_Z, "cHRM Blue Z")); 129 } 130 # endif /* FLOATING_POINT */ 131 132 #endif /* cHRM */ 133 134 #ifdef PNG_cICP_SUPPORTED 135 void PNGAPI 136 png_set_cICP(png_const_structrp png_ptr, png_inforp info_ptr, 137 png_byte colour_primaries, png_byte transfer_function, 138 png_byte matrix_coefficients, png_byte video_full_range_flag) 139 { 140 png_debug1(1, "in %s storage function", "cICP"); 141 142 if (png_ptr == NULL || info_ptr == NULL) 143 return; 144 145 info_ptr->cicp_colour_primaries = colour_primaries; 146 info_ptr->cicp_transfer_function = transfer_function; 147 info_ptr->cicp_matrix_coefficients = matrix_coefficients; 148 info_ptr->cicp_video_full_range_flag = video_full_range_flag; 149 150 if (info_ptr->cicp_matrix_coefficients != 0) 151 { 152 png_warning(png_ptr, "Invalid cICP matrix coefficients"); 153 return; 154 } 155 156 info_ptr->valid |= PNG_INFO_cICP; 157 } 158 #endif /* cICP */ 159 160 #ifdef PNG_cLLI_SUPPORTED 161 void PNGFAPI 162 png_set_cLLI_fixed(png_const_structrp png_ptr, png_inforp info_ptr, 163 /* The values below are in cd/m2 (nits) and are scaled by 10,000; not 164 * 100,000 as in the case of png_fixed_point. 165 */ 166 png_uint_32 maxCLL, png_uint_32 maxFALL) 167 { 168 png_debug1(1, "in %s storage function", "cLLI"); 169 170 if (png_ptr == NULL || info_ptr == NULL) 171 return; 172 173 /* Check the light level range: */ 174 if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU) 175 { 176 /* The limit is 200kcd/m2; somewhat bright but not inconceivable because 177 * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2. 178 * 179 * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is 180 * 2kcd/m2. 181 */ 182 png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit", 183 PNG_CHUNK_WRITE_ERROR); 184 return; 185 } 186 187 info_ptr->maxCLL = maxCLL; 188 info_ptr->maxFALL = maxFALL; 189 info_ptr->valid |= PNG_INFO_cLLI; 190 } 191 192 # ifdef PNG_FLOATING_POINT_SUPPORTED 193 void PNGAPI 194 png_set_cLLI(png_const_structrp png_ptr, png_inforp info_ptr, 195 double maxCLL, double maxFALL) 196 { 197 png_set_cLLI_fixed(png_ptr, info_ptr, 198 png_fixed_ITU(png_ptr, maxCLL, "png_set_cLLI(maxCLL)"), 199 png_fixed_ITU(png_ptr, maxFALL, "png_set_cLLI(maxFALL)")); 200 } 201 # endif /* FLOATING_POINT */ 202 #endif /* cLLI */ 203 204 #ifdef PNG_mDCV_SUPPORTED 205 static png_uint_16 206 png_ITU_fixed_16(int *error, png_fixed_point v) 207 { 208 /* Return a safe uint16_t value scaled according to the ITU H273 rules for 209 * 16-bit display chromaticities. Functions like the corresponding 210 * png_fixed() internal function with regard to errors: it's an error on 211 * write, a chunk_benign_error on read: See the definition of 212 * png_chunk_report in pngpriv.h. 213 */ 214 v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */ 215 if (v > 65535 || v < 0) 216 { 217 *error = 1; 218 return 0; 219 } 220 221 return (png_uint_16)/*SAFE*/v; 222 } 223 224 void PNGAPI 225 png_set_mDCV_fixed(png_const_structrp png_ptr, png_inforp info_ptr, 226 png_fixed_point white_x, png_fixed_point white_y, 227 png_fixed_point red_x, png_fixed_point red_y, 228 png_fixed_point green_x, png_fixed_point green_y, 229 png_fixed_point blue_x, png_fixed_point blue_y, 230 png_uint_32 maxDL, 231 png_uint_32 minDL) 232 { 233 png_uint_16 rx, ry, gx, gy, bx, by, wx, wy; 234 int error; 235 236 png_debug1(1, "in %s storage function", "mDCV"); 237 238 if (png_ptr == NULL || info_ptr == NULL) 239 return; 240 241 /* Check the input values to ensure they are in the expected range: */ 242 error = 0; 243 rx = png_ITU_fixed_16(&error, red_x); 244 ry = png_ITU_fixed_16(&error, red_y); 245 gx = png_ITU_fixed_16(&error, green_x); 246 gy = png_ITU_fixed_16(&error, green_y); 247 bx = png_ITU_fixed_16(&error, blue_x); 248 by = png_ITU_fixed_16(&error, blue_y); 249 wx = png_ITU_fixed_16(&error, white_x); 250 wy = png_ITU_fixed_16(&error, white_y); 251 252 if (error) 253 { 254 png_chunk_report(png_ptr, 255 "mDCV chromaticities outside representable range", 256 PNG_CHUNK_WRITE_ERROR); 257 return; 258 } 259 260 /* Check the light level range: */ 261 if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU) 262 { 263 /* The limit is 200kcd/m2; somewhat bright but not inconceivable because 264 * human vision is said to run up to 100Mcd/m2. The sun is about 2Gcd/m2. 265 * 266 * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is 267 * 2kcd/m2. 268 */ 269 png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit", 270 PNG_CHUNK_WRITE_ERROR); 271 return; 272 } 273 274 /* All values are safe, the settings are accepted. 275 * 276 * IMPLEMENTATION NOTE: in practice the values can be checked and assigned 277 * but the result is confusing if a writing app calls png_set_mDCV more than 278 * once, the second time with an invalid value. This approach is more 279 * obviously correct at the cost of typing and a very slight machine 280 * overhead. 281 */ 282 info_ptr->mastering_red_x = rx; 283 info_ptr->mastering_red_y = ry; 284 info_ptr->mastering_green_x = gx; 285 info_ptr->mastering_green_y = gy; 286 info_ptr->mastering_blue_x = bx; 287 info_ptr->mastering_blue_y = by; 288 info_ptr->mastering_white_x = wx; 289 info_ptr->mastering_white_y = wy; 290 info_ptr->mastering_maxDL = maxDL; 291 info_ptr->mastering_minDL = minDL; 292 info_ptr->valid |= PNG_INFO_mDCV; 293 } 294 295 # ifdef PNG_FLOATING_POINT_SUPPORTED 296 void PNGAPI 297 png_set_mDCV(png_const_structrp png_ptr, png_inforp info_ptr, 298 double white_x, double white_y, double red_x, double red_y, double green_x, 299 double green_y, double blue_x, double blue_y, 300 double maxDL, double minDL) 301 { 302 png_set_mDCV_fixed(png_ptr, info_ptr, 303 png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"), 304 png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"), 305 png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"), 306 png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"), 307 png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"), 308 png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"), 309 png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"), 310 png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"), 311 png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"), 312 png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)")); 313 } 314 # endif /* FLOATING_POINT */ 315 #endif /* mDCV */ 316 317 #ifdef PNG_eXIf_SUPPORTED 318 void PNGAPI 319 png_set_eXIf(png_const_structrp png_ptr, png_inforp info_ptr, 320 png_bytep exif) 321 { 322 png_warning(png_ptr, "png_set_eXIf does not work; use png_set_eXIf_1"); 323 PNG_UNUSED(info_ptr) 324 PNG_UNUSED(exif) 325 } 326 327 void PNGAPI 328 png_set_eXIf_1(png_const_structrp png_ptr, png_inforp info_ptr, 329 png_uint_32 num_exif, png_bytep exif) 330 { 331 png_bytep new_exif; 332 333 png_debug1(1, "in %s storage function", "eXIf"); 334 335 if (png_ptr == NULL || info_ptr == NULL || 336 (png_ptr->mode & PNG_WROTE_eXIf) != 0) 337 return; 338 339 new_exif = png_voidcast(png_bytep, png_malloc_warn(png_ptr, num_exif)); 340 341 if (new_exif == NULL) 342 { 343 png_warning(png_ptr, "Insufficient memory for eXIf chunk data"); 344 return; 345 } 346 347 memcpy(new_exif, exif, (size_t)num_exif); 348 349 png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0); 350 351 info_ptr->num_exif = num_exif; 352 info_ptr->exif = new_exif; 353 info_ptr->free_me |= PNG_FREE_EXIF; 354 info_ptr->valid |= PNG_INFO_eXIf; 355 } 356 #endif /* eXIf */ 357 358 #ifdef PNG_gAMA_SUPPORTED 359 void PNGFAPI 360 png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr, 361 png_fixed_point file_gamma) 362 { 363 png_debug1(1, "in %s storage function", "gAMA"); 364 365 if (png_ptr == NULL || info_ptr == NULL) 366 return; 367 368 info_ptr->gamma = file_gamma; 369 info_ptr->valid |= PNG_INFO_gAMA; 370 } 371 372 # ifdef PNG_FLOATING_POINT_SUPPORTED 373 void PNGAPI 374 png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma) 375 { 376 png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma, 377 "png_set_gAMA")); 378 } 379 # endif 380 #endif 381 382 #ifdef PNG_hIST_SUPPORTED 383 void PNGAPI 384 png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr, 385 png_const_uint_16p hist) 386 { 387 int i; 388 389 png_debug1(1, "in %s storage function", "hIST"); 390 391 if (png_ptr == NULL || info_ptr == NULL) 392 return; 393 394 if (info_ptr->num_palette == 0 || info_ptr->num_palette 395 > PNG_MAX_PALETTE_LENGTH) 396 { 397 png_warning(png_ptr, 398 "Invalid palette size, hIST allocation skipped"); 399 400 return; 401 } 402 403 png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0); 404 405 /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in 406 * version 1.2.1 407 */ 408 info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr, 409 PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16)))); 410 411 if (info_ptr->hist == NULL) 412 { 413 png_warning(png_ptr, "Insufficient memory for hIST chunk data"); 414 return; 415 } 416 417 for (i = 0; i < info_ptr->num_palette; i++) 418 info_ptr->hist[i] = hist[i]; 419 420 info_ptr->free_me |= PNG_FREE_HIST; 421 info_ptr->valid |= PNG_INFO_hIST; 422 } 423 #endif 424 425 void PNGAPI 426 png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr, 427 png_uint_32 width, png_uint_32 height, int bit_depth, 428 int color_type, int interlace_type, int compression_type, 429 int filter_type) 430 { 431 png_debug1(1, "in %s storage function", "IHDR"); 432 433 if (png_ptr == NULL || info_ptr == NULL) 434 return; 435 436 info_ptr->width = width; 437 info_ptr->height = height; 438 info_ptr->bit_depth = (png_byte)bit_depth; 439 info_ptr->color_type = (png_byte)color_type; 440 info_ptr->compression_type = (png_byte)compression_type; 441 info_ptr->filter_type = (png_byte)filter_type; 442 info_ptr->interlace_type = (png_byte)interlace_type; 443 444 png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height, 445 info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type, 446 info_ptr->compression_type, info_ptr->filter_type); 447 448 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 449 info_ptr->channels = 1; 450 451 else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0) 452 info_ptr->channels = 3; 453 454 else 455 info_ptr->channels = 1; 456 457 if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0) 458 info_ptr->channels++; 459 460 info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth); 461 462 info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width); 463 464 #ifdef PNG_APNG_SUPPORTED 465 /* for non-animated png. this may be overwritten from an acTL chunk later */ 466 info_ptr->num_frames = 1; 467 #endif 468 } 469 470 #ifdef PNG_oFFs_SUPPORTED 471 void PNGAPI 472 png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr, 473 png_int_32 offset_x, png_int_32 offset_y, int unit_type) 474 { 475 png_debug1(1, "in %s storage function", "oFFs"); 476 477 if (png_ptr == NULL || info_ptr == NULL) 478 return; 479 480 info_ptr->x_offset = offset_x; 481 info_ptr->y_offset = offset_y; 482 info_ptr->offset_unit_type = (png_byte)unit_type; 483 info_ptr->valid |= PNG_INFO_oFFs; 484 } 485 #endif 486 487 #ifdef PNG_pCAL_SUPPORTED 488 void PNGAPI 489 png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr, 490 png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type, 491 int nparams, png_const_charp units, png_charpp params) 492 { 493 size_t length; 494 int i; 495 496 png_debug1(1, "in %s storage function", "pCAL"); 497 498 if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL 499 || (nparams > 0 && params == NULL)) 500 return; 501 502 length = strlen(purpose) + 1; 503 png_debug1(3, "allocating purpose for info (%lu bytes)", 504 (unsigned long)length); 505 506 /* TODO: validate format of calibration name and unit name */ 507 508 /* Check that the type matches the specification. */ 509 if (type < 0 || type > 3) 510 { 511 png_chunk_report(png_ptr, "Invalid pCAL equation type", 512 PNG_CHUNK_WRITE_ERROR); 513 return; 514 } 515 516 if (nparams < 0 || nparams > 255) 517 { 518 png_chunk_report(png_ptr, "Invalid pCAL parameter count", 519 PNG_CHUNK_WRITE_ERROR); 520 return; 521 } 522 523 /* Validate params[nparams] */ 524 for (i=0; i<nparams; ++i) 525 { 526 if (params[i] == NULL || 527 !png_check_fp_string(params[i], strlen(params[i]))) 528 { 529 png_chunk_report(png_ptr, "Invalid format for pCAL parameter", 530 PNG_CHUNK_WRITE_ERROR); 531 return; 532 } 533 } 534 535 info_ptr->pcal_purpose = png_voidcast(png_charp, 536 png_malloc_warn(png_ptr, length)); 537 538 if (info_ptr->pcal_purpose == NULL) 539 { 540 png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose", 541 PNG_CHUNK_WRITE_ERROR); 542 return; 543 } 544 545 memcpy(info_ptr->pcal_purpose, purpose, length); 546 547 info_ptr->free_me |= PNG_FREE_PCAL; 548 549 png_debug(3, "storing X0, X1, type, and nparams in info"); 550 info_ptr->pcal_X0 = X0; 551 info_ptr->pcal_X1 = X1; 552 info_ptr->pcal_type = (png_byte)type; 553 info_ptr->pcal_nparams = (png_byte)nparams; 554 555 length = strlen(units) + 1; 556 png_debug1(3, "allocating units for info (%lu bytes)", 557 (unsigned long)length); 558 559 info_ptr->pcal_units = png_voidcast(png_charp, 560 png_malloc_warn(png_ptr, length)); 561 562 if (info_ptr->pcal_units == NULL) 563 { 564 png_warning(png_ptr, "Insufficient memory for pCAL units"); 565 return; 566 } 567 568 memcpy(info_ptr->pcal_units, units, length); 569 570 info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr, 571 (size_t)(((unsigned int)nparams + 1) * (sizeof (png_charp))))); 572 573 if (info_ptr->pcal_params == NULL) 574 { 575 png_warning(png_ptr, "Insufficient memory for pCAL params"); 576 return; 577 } 578 579 memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) * 580 (sizeof (png_charp))); 581 582 for (i = 0; i < nparams; i++) 583 { 584 length = strlen(params[i]) + 1; 585 png_debug2(3, "allocating parameter %d for info (%lu bytes)", i, 586 (unsigned long)length); 587 588 info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length); 589 590 if (info_ptr->pcal_params[i] == NULL) 591 { 592 png_warning(png_ptr, "Insufficient memory for pCAL parameter"); 593 return; 594 } 595 596 memcpy(info_ptr->pcal_params[i], params[i], length); 597 } 598 599 info_ptr->valid |= PNG_INFO_pCAL; 600 } 601 #endif 602 603 #ifdef PNG_sCAL_SUPPORTED 604 void PNGAPI 605 png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr, 606 int unit, png_const_charp swidth, png_const_charp sheight) 607 { 608 size_t lengthw = 0, lengthh = 0; 609 610 png_debug1(1, "in %s storage function", "sCAL"); 611 612 if (png_ptr == NULL || info_ptr == NULL) 613 return; 614 615 /* Double check the unit (should never get here with an invalid 616 * unit unless this is an API call.) 617 */ 618 if (unit != 1 && unit != 2) 619 png_error(png_ptr, "Invalid sCAL unit"); 620 621 if (swidth == NULL || (lengthw = strlen(swidth)) == 0 || 622 swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw)) 623 png_error(png_ptr, "Invalid sCAL width"); 624 625 if (sheight == NULL || (lengthh = strlen(sheight)) == 0 || 626 sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh)) 627 png_error(png_ptr, "Invalid sCAL height"); 628 629 info_ptr->scal_unit = (png_byte)unit; 630 631 ++lengthw; 632 633 png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw); 634 635 info_ptr->scal_s_width = png_voidcast(png_charp, 636 png_malloc_warn(png_ptr, lengthw)); 637 638 if (info_ptr->scal_s_width == NULL) 639 { 640 png_warning(png_ptr, "Memory allocation failed while processing sCAL"); 641 642 return; 643 } 644 645 memcpy(info_ptr->scal_s_width, swidth, lengthw); 646 647 ++lengthh; 648 649 png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh); 650 651 info_ptr->scal_s_height = png_voidcast(png_charp, 652 png_malloc_warn(png_ptr, lengthh)); 653 654 if (info_ptr->scal_s_height == NULL) 655 { 656 png_free(png_ptr, info_ptr->scal_s_width); 657 info_ptr->scal_s_width = NULL; 658 659 png_warning(png_ptr, "Memory allocation failed while processing sCAL"); 660 return; 661 } 662 663 memcpy(info_ptr->scal_s_height, sheight, lengthh); 664 665 info_ptr->free_me |= PNG_FREE_SCAL; 666 info_ptr->valid |= PNG_INFO_sCAL; 667 } 668 669 # ifdef PNG_FLOATING_POINT_SUPPORTED 670 void PNGAPI 671 png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit, 672 double width, double height) 673 { 674 png_debug1(1, "in %s storage function", "sCAL"); 675 676 /* Check the arguments. */ 677 if (width <= 0) 678 png_warning(png_ptr, "Invalid sCAL width ignored"); 679 680 else if (height <= 0) 681 png_warning(png_ptr, "Invalid sCAL height ignored"); 682 683 else 684 { 685 /* Convert 'width' and 'height' to ASCII. */ 686 char swidth[PNG_sCAL_MAX_DIGITS+1]; 687 char sheight[PNG_sCAL_MAX_DIGITS+1]; 688 689 png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width, 690 PNG_sCAL_PRECISION); 691 png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height, 692 PNG_sCAL_PRECISION); 693 694 png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); 695 } 696 } 697 # endif 698 699 # ifdef PNG_FIXED_POINT_SUPPORTED 700 void PNGAPI 701 png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit, 702 png_fixed_point width, png_fixed_point height) 703 { 704 png_debug1(1, "in %s storage function", "sCAL"); 705 706 /* Check the arguments. */ 707 if (width <= 0) 708 png_warning(png_ptr, "Invalid sCAL width ignored"); 709 710 else if (height <= 0) 711 png_warning(png_ptr, "Invalid sCAL height ignored"); 712 713 else 714 { 715 /* Convert 'width' and 'height' to ASCII. */ 716 char swidth[PNG_sCAL_MAX_DIGITS+1]; 717 char sheight[PNG_sCAL_MAX_DIGITS+1]; 718 719 png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width); 720 png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height); 721 722 png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight); 723 } 724 } 725 # endif 726 #endif 727 728 #ifdef PNG_pHYs_SUPPORTED 729 void PNGAPI 730 png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr, 731 png_uint_32 res_x, png_uint_32 res_y, int unit_type) 732 { 733 png_debug1(1, "in %s storage function", "pHYs"); 734 735 if (png_ptr == NULL || info_ptr == NULL) 736 return; 737 738 info_ptr->x_pixels_per_unit = res_x; 739 info_ptr->y_pixels_per_unit = res_y; 740 info_ptr->phys_unit_type = (png_byte)unit_type; 741 info_ptr->valid |= PNG_INFO_pHYs; 742 } 743 #endif 744 745 void PNGAPI 746 png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr, 747 png_const_colorp palette, int num_palette) 748 { 749 750 png_uint_32 max_palette_length; 751 752 png_debug1(1, "in %s storage function", "PLTE"); 753 754 if (png_ptr == NULL || info_ptr == NULL) 755 return; 756 757 max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ? 758 (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH; 759 760 if (num_palette < 0 || num_palette > (int) max_palette_length) 761 { 762 if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) 763 png_error(png_ptr, "Invalid palette length"); 764 765 else 766 { 767 png_warning(png_ptr, "Invalid palette length"); 768 769 return; 770 } 771 } 772 773 if ((num_palette > 0 && palette == NULL) || 774 (num_palette == 0 775 # ifdef PNG_MNG_FEATURES_SUPPORTED 776 && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0 777 # endif 778 )) 779 { 780 png_error(png_ptr, "Invalid palette"); 781 } 782 783 /* It may not actually be necessary to set png_ptr->palette here; 784 * we do it for backward compatibility with the way the png_handle_tRNS 785 * function used to do the allocation. 786 * 787 * 1.6.0: the above statement appears to be incorrect; something has to set 788 * the palette inside png_struct on read. 789 */ 790 png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0); 791 792 /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead 793 * of num_palette entries, in case of an invalid PNG file or incorrect 794 * call to png_set_PLTE() with too-large sample values. 795 */ 796 png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr, 797 PNG_MAX_PALETTE_LENGTH * (sizeof (png_color)))); 798 799 if (num_palette > 0) 800 memcpy(png_ptr->palette, palette, (unsigned int)num_palette * 801 (sizeof (png_color))); 802 803 info_ptr->palette = png_ptr->palette; 804 info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette; 805 info_ptr->free_me |= PNG_FREE_PLTE; 806 info_ptr->valid |= PNG_INFO_PLTE; 807 } 808 809 #ifdef PNG_sBIT_SUPPORTED 810 void PNGAPI 811 png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr, 812 png_const_color_8p sig_bit) 813 { 814 png_debug1(1, "in %s storage function", "sBIT"); 815 816 if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL) 817 return; 818 819 info_ptr->sig_bit = *sig_bit; 820 info_ptr->valid |= PNG_INFO_sBIT; 821 } 822 #endif 823 824 #ifdef PNG_sRGB_SUPPORTED 825 void PNGAPI 826 png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent) 827 { 828 png_debug1(1, "in %s storage function", "sRGB"); 829 830 if (png_ptr == NULL || info_ptr == NULL) 831 return; 832 833 info_ptr->rendering_intent = srgb_intent; 834 info_ptr->valid |= PNG_INFO_sRGB; 835 } 836 837 void PNGAPI 838 png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr, 839 int srgb_intent) 840 { 841 png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM"); 842 843 if (png_ptr == NULL || info_ptr == NULL) 844 return; 845 846 png_set_sRGB(png_ptr, info_ptr, srgb_intent); 847 848 # ifdef PNG_gAMA_SUPPORTED 849 png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE); 850 # endif /* gAMA */ 851 852 # ifdef PNG_cHRM_SUPPORTED 853 png_set_cHRM_fixed(png_ptr, info_ptr, 854 /* color x y */ 855 /* white */ 31270, 32900, 856 /* red */ 64000, 33000, 857 /* green */ 30000, 60000, 858 /* blue */ 15000, 6000); 859 # endif /* cHRM */ 860 } 861 #endif /* sRGB */ 862 863 864 #ifdef PNG_iCCP_SUPPORTED 865 void PNGAPI 866 png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr, 867 png_const_charp name, int compression_type, 868 png_const_bytep profile, png_uint_32 proflen) 869 { 870 png_charp new_iccp_name; 871 png_bytep new_iccp_profile; 872 size_t length; 873 874 png_debug1(1, "in %s storage function", "iCCP"); 875 876 if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL) 877 return; 878 879 if (compression_type != PNG_COMPRESSION_TYPE_BASE) 880 png_app_error(png_ptr, "Invalid iCCP compression method"); 881 882 length = strlen(name)+1; 883 new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length)); 884 885 if (new_iccp_name == NULL) 886 { 887 png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk"); 888 889 return; 890 } 891 892 memcpy(new_iccp_name, name, length); 893 new_iccp_profile = png_voidcast(png_bytep, 894 png_malloc_warn(png_ptr, proflen)); 895 896 if (new_iccp_profile == NULL) 897 { 898 png_free(png_ptr, new_iccp_name); 899 png_benign_error(png_ptr, 900 "Insufficient memory to process iCCP profile"); 901 902 return; 903 } 904 905 memcpy(new_iccp_profile, profile, proflen); 906 907 png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0); 908 909 info_ptr->iccp_proflen = proflen; 910 info_ptr->iccp_name = new_iccp_name; 911 info_ptr->iccp_profile = new_iccp_profile; 912 info_ptr->free_me |= PNG_FREE_ICCP; 913 info_ptr->valid |= PNG_INFO_iCCP; 914 } 915 #endif 916 917 #ifdef PNG_TEXT_SUPPORTED 918 void PNGAPI 919 png_set_text(png_const_structrp png_ptr, png_inforp info_ptr, 920 png_const_textp text_ptr, int num_text) 921 { 922 int ret; 923 ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text); 924 925 if (ret != 0) 926 png_error(png_ptr, "Insufficient memory to store text"); 927 } 928 929 int /* PRIVATE */ 930 png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr, 931 png_const_textp text_ptr, int num_text) 932 { 933 int i; 934 935 png_debug1(1, "in text storage function, chunk typeid = 0x%lx", 936 png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name); 937 938 if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL) 939 return 0; 940 941 /* Make sure we have enough space in the "text" array in info_struct 942 * to hold all of the incoming text_ptr objects. This compare can't overflow 943 * because max_text >= num_text (anyway, subtract of two positive integers 944 * can't overflow in any case.) 945 */ 946 if (num_text > info_ptr->max_text - info_ptr->num_text) 947 { 948 int old_num_text = info_ptr->num_text; 949 int max_text; 950 png_textp new_text = NULL; 951 952 /* Calculate an appropriate max_text, checking for overflow. */ 953 max_text = old_num_text; 954 if (num_text <= INT_MAX - max_text) 955 { 956 max_text += num_text; 957 958 /* Round up to a multiple of 8 */ 959 if (max_text < INT_MAX-8) 960 max_text = (max_text + 8) & ~0x7; 961 962 else 963 max_text = INT_MAX; 964 965 /* Now allocate a new array and copy the old members in; this does all 966 * the overflow checks. 967 */ 968 new_text = png_voidcast(png_textp,png_realloc_array(png_ptr, 969 info_ptr->text, old_num_text, max_text-old_num_text, 970 sizeof *new_text)); 971 } 972 973 if (new_text == NULL) 974 { 975 png_chunk_report(png_ptr, "too many text chunks", 976 PNG_CHUNK_WRITE_ERROR); 977 978 return 1; 979 } 980 981 png_free(png_ptr, info_ptr->text); 982 983 info_ptr->text = new_text; 984 info_ptr->free_me |= PNG_FREE_TEXT; 985 info_ptr->max_text = max_text; 986 /* num_text is adjusted below as the entries are copied in */ 987 988 png_debug1(3, "allocated %d entries for info_ptr->text", max_text); 989 } 990 991 for (i = 0; i < num_text; i++) 992 { 993 size_t text_length, key_len; 994 size_t lang_len, lang_key_len; 995 png_textp textp = &(info_ptr->text[info_ptr->num_text]); 996 997 if (text_ptr[i].key == NULL) 998 continue; 999 1000 if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE || 1001 text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST) 1002 { 1003 png_chunk_report(png_ptr, "text compression mode is out of range", 1004 PNG_CHUNK_WRITE_ERROR); 1005 continue; 1006 } 1007 1008 key_len = strlen(text_ptr[i].key); 1009 1010 if (text_ptr[i].compression <= 0) 1011 { 1012 lang_len = 0; 1013 lang_key_len = 0; 1014 } 1015 1016 else 1017 # ifdef PNG_iTXt_SUPPORTED 1018 { 1019 /* Set iTXt data */ 1020 1021 if (text_ptr[i].lang != NULL) 1022 lang_len = strlen(text_ptr[i].lang); 1023 1024 else 1025 lang_len = 0; 1026 1027 if (text_ptr[i].lang_key != NULL) 1028 lang_key_len = strlen(text_ptr[i].lang_key); 1029 1030 else 1031 lang_key_len = 0; 1032 } 1033 # else /* iTXt */ 1034 { 1035 png_chunk_report(png_ptr, "iTXt chunk not supported", 1036 PNG_CHUNK_WRITE_ERROR); 1037 continue; 1038 } 1039 # endif 1040 1041 if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0') 1042 { 1043 text_length = 0; 1044 # ifdef PNG_iTXt_SUPPORTED 1045 if (text_ptr[i].compression > 0) 1046 textp->compression = PNG_ITXT_COMPRESSION_NONE; 1047 1048 else 1049 # endif 1050 textp->compression = PNG_TEXT_COMPRESSION_NONE; 1051 } 1052 1053 else 1054 { 1055 text_length = strlen(text_ptr[i].text); 1056 textp->compression = text_ptr[i].compression; 1057 } 1058 1059 textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr, 1060 key_len + text_length + lang_len + lang_key_len + 4)); 1061 1062 if (textp->key == NULL) 1063 { 1064 png_chunk_report(png_ptr, "text chunk: out of memory", 1065 PNG_CHUNK_WRITE_ERROR); 1066 1067 return 1; 1068 } 1069 1070 png_debug2(2, "Allocated %lu bytes at %p in png_set_text", 1071 (unsigned long)(png_uint_32) 1072 (key_len + lang_len + lang_key_len + text_length + 4), 1073 textp->key); 1074 1075 memcpy(textp->key, text_ptr[i].key, key_len); 1076 *(textp->key + key_len) = '\0'; 1077 1078 if (text_ptr[i].compression > 0) 1079 { 1080 textp->lang = textp->key + key_len + 1; 1081 memcpy(textp->lang, text_ptr[i].lang, lang_len); 1082 *(textp->lang + lang_len) = '\0'; 1083 textp->lang_key = textp->lang + lang_len + 1; 1084 memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len); 1085 *(textp->lang_key + lang_key_len) = '\0'; 1086 textp->text = textp->lang_key + lang_key_len + 1; 1087 } 1088 1089 else 1090 { 1091 textp->lang=NULL; 1092 textp->lang_key=NULL; 1093 textp->text = textp->key + key_len + 1; 1094 } 1095 1096 if (text_length != 0) 1097 memcpy(textp->text, text_ptr[i].text, text_length); 1098 1099 *(textp->text + text_length) = '\0'; 1100 1101 # ifdef PNG_iTXt_SUPPORTED 1102 if (textp->compression > 0) 1103 { 1104 textp->text_length = 0; 1105 textp->itxt_length = text_length; 1106 } 1107 1108 else 1109 # endif 1110 { 1111 textp->text_length = text_length; 1112 textp->itxt_length = 0; 1113 } 1114 1115 info_ptr->num_text++; 1116 png_debug1(3, "transferred text chunk %d", info_ptr->num_text); 1117 } 1118 1119 return 0; 1120 } 1121 #endif 1122 1123 #ifdef PNG_tIME_SUPPORTED 1124 void PNGAPI 1125 png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr, 1126 png_const_timep mod_time) 1127 { 1128 png_debug1(1, "in %s storage function", "tIME"); 1129 1130 if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL || 1131 (png_ptr->mode & PNG_WROTE_tIME) != 0) 1132 return; 1133 1134 if (mod_time->month == 0 || mod_time->month > 12 || 1135 mod_time->day == 0 || mod_time->day > 31 || 1136 mod_time->hour > 23 || mod_time->minute > 59 || 1137 mod_time->second > 60) 1138 { 1139 png_warning(png_ptr, "Ignoring invalid time value"); 1140 1141 return; 1142 } 1143 1144 info_ptr->mod_time = *mod_time; 1145 info_ptr->valid |= PNG_INFO_tIME; 1146 } 1147 #endif 1148 1149 #ifdef PNG_tRNS_SUPPORTED 1150 void PNGAPI 1151 png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr, 1152 png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color) 1153 { 1154 png_debug1(1, "in %s storage function", "tRNS"); 1155 1156 if (png_ptr == NULL || info_ptr == NULL) 1157 1158 return; 1159 1160 if (trans_alpha != NULL) 1161 { 1162 /* It may not actually be necessary to set png_ptr->trans_alpha here; 1163 * we do it for backward compatibility with the way the png_handle_tRNS 1164 * function used to do the allocation. 1165 * 1166 * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively 1167 * relies on png_set_tRNS storing the information in png_struct 1168 * (otherwise it won't be there for the code in pngrtran.c). 1169 */ 1170 1171 png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0); 1172 1173 if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH) 1174 { 1175 /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */ 1176 info_ptr->trans_alpha = png_voidcast(png_bytep, 1177 png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH)); 1178 memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans); 1179 1180 info_ptr->free_me |= PNG_FREE_TRNS; 1181 info_ptr->valid |= PNG_INFO_tRNS; 1182 } 1183 png_ptr->trans_alpha = info_ptr->trans_alpha; 1184 } 1185 1186 if (trans_color != NULL) 1187 { 1188 #ifdef PNG_WARNINGS_SUPPORTED 1189 if (info_ptr->bit_depth < 16) 1190 { 1191 int sample_max = (1 << info_ptr->bit_depth) - 1; 1192 1193 if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY && 1194 trans_color->gray > sample_max) || 1195 (info_ptr->color_type == PNG_COLOR_TYPE_RGB && 1196 (trans_color->red > sample_max || 1197 trans_color->green > sample_max || 1198 trans_color->blue > sample_max))) 1199 png_warning(png_ptr, 1200 "tRNS chunk has out-of-range samples for bit_depth"); 1201 } 1202 #endif 1203 1204 info_ptr->trans_color = *trans_color; 1205 1206 if (num_trans == 0) 1207 num_trans = 1; 1208 } 1209 1210 info_ptr->num_trans = (png_uint_16)num_trans; 1211 1212 if (num_trans != 0) 1213 { 1214 info_ptr->free_me |= PNG_FREE_TRNS; 1215 info_ptr->valid |= PNG_INFO_tRNS; 1216 } 1217 } 1218 #endif 1219 1220 #ifdef PNG_sPLT_SUPPORTED 1221 void PNGAPI 1222 png_set_sPLT(png_const_structrp png_ptr, 1223 png_inforp info_ptr, png_const_sPLT_tp entries, int nentries) 1224 /* 1225 * entries - array of png_sPLT_t structures 1226 * to be added to the list of palettes 1227 * in the info structure. 1228 * 1229 * nentries - number of palette structures to be 1230 * added. 1231 */ 1232 { 1233 png_sPLT_tp np; 1234 1235 png_debug1(1, "in %s storage function", "sPLT"); 1236 1237 if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL) 1238 return; 1239 1240 /* Use the internal realloc function, which checks for all the possible 1241 * overflows. Notice that the parameters are (int) and (size_t) 1242 */ 1243 np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr, 1244 info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries, 1245 sizeof *np)); 1246 1247 if (np == NULL) 1248 { 1249 /* Out of memory or too many chunks */ 1250 png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR); 1251 return; 1252 } 1253 1254 png_free(png_ptr, info_ptr->splt_palettes); 1255 1256 info_ptr->splt_palettes = np; 1257 info_ptr->free_me |= PNG_FREE_SPLT; 1258 1259 np += info_ptr->splt_palettes_num; 1260 1261 do 1262 { 1263 size_t length; 1264 1265 /* Skip invalid input entries */ 1266 if (entries->name == NULL || entries->entries == NULL) 1267 { 1268 /* png_handle_sPLT doesn't do this, so this is an app error */ 1269 png_app_error(png_ptr, "png_set_sPLT: invalid sPLT"); 1270 /* Just skip the invalid entry */ 1271 continue; 1272 } 1273 1274 np->depth = entries->depth; 1275 1276 /* In the event of out-of-memory just return - there's no point keeping 1277 * on trying to add sPLT chunks. 1278 */ 1279 length = strlen(entries->name) + 1; 1280 np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length)); 1281 1282 if (np->name == NULL) 1283 break; 1284 1285 memcpy(np->name, entries->name, length); 1286 1287 /* IMPORTANT: we have memory now that won't get freed if something else 1288 * goes wrong; this code must free it. png_malloc_array produces no 1289 * warnings; use a png_chunk_report (below) if there is an error. 1290 */ 1291 np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr, 1292 entries->nentries, sizeof (png_sPLT_entry))); 1293 1294 if (np->entries == NULL) 1295 { 1296 png_free(png_ptr, np->name); 1297 np->name = NULL; 1298 break; 1299 } 1300 1301 np->nentries = entries->nentries; 1302 /* This multiply can't overflow because png_malloc_array has already 1303 * checked it when doing the allocation. 1304 */ 1305 memcpy(np->entries, entries->entries, 1306 (unsigned int)entries->nentries * sizeof (png_sPLT_entry)); 1307 1308 /* Note that 'continue' skips the advance of the out pointer and out 1309 * count, so an invalid entry is not added. 1310 */ 1311 info_ptr->valid |= PNG_INFO_sPLT; 1312 ++(info_ptr->splt_palettes_num); 1313 ++np; 1314 ++entries; 1315 } 1316 while (--nentries); 1317 1318 if (nentries > 0) 1319 png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR); 1320 } 1321 #endif /* sPLT */ 1322 1323 #ifdef PNG_APNG_SUPPORTED 1324 png_uint_32 PNGAPI 1325 png_set_acTL(png_structp png_ptr, png_infop info_ptr, 1326 png_uint_32 num_frames, png_uint_32 num_plays) 1327 { 1328 png_debug1(1, "in %s storage function", "acTL"); 1329 1330 if (png_ptr == NULL || info_ptr == NULL) 1331 { 1332 png_warning(png_ptr, 1333 "Call to png_set_acTL() with NULL png_ptr " 1334 "or info_ptr ignored"); 1335 return (0); 1336 } 1337 if (num_frames == 0) 1338 { 1339 png_warning(png_ptr, 1340 "Ignoring attempt to set acTL with num_frames zero"); 1341 return (0); 1342 } 1343 if (num_frames > PNG_UINT_31_MAX) 1344 { 1345 png_warning(png_ptr, 1346 "Ignoring attempt to set acTL with num_frames > 2^31-1"); 1347 return (0); 1348 } 1349 if (num_plays > PNG_UINT_31_MAX) 1350 { 1351 png_warning(png_ptr, 1352 "Ignoring attempt to set acTL with num_plays > 2^31-1"); 1353 return (0); 1354 } 1355 1356 info_ptr->num_frames = num_frames; 1357 info_ptr->num_plays = num_plays; 1358 1359 info_ptr->valid |= PNG_INFO_acTL; 1360 1361 return (1); 1362 } 1363 1364 /* delay_num and delay_den can hold any 16-bit values including zero */ 1365 png_uint_32 PNGAPI 1366 png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr, 1367 png_uint_32 width, png_uint_32 height, 1368 png_uint_32 x_offset, png_uint_32 y_offset, 1369 png_uint_16 delay_num, png_uint_16 delay_den, 1370 png_byte dispose_op, png_byte blend_op) 1371 { 1372 png_debug1(1, "in %s storage function", "fcTL"); 1373 1374 if (png_ptr == NULL || info_ptr == NULL) 1375 { 1376 png_warning(png_ptr, 1377 "Call to png_set_fcTL() with NULL png_ptr or info_ptr " 1378 "ignored"); 1379 return (0); 1380 } 1381 1382 png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset, 1383 delay_num, delay_den, dispose_op, blend_op); 1384 1385 if (blend_op == PNG_BLEND_OP_OVER) 1386 { 1387 if ((png_ptr->color_type & PNG_COLOR_MASK_ALPHA) == 0 && 1388 png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS) == 0) 1389 { 1390 png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless " 1391 "and wasteful for opaque images, ignored"); 1392 blend_op = PNG_BLEND_OP_SOURCE; 1393 } 1394 } 1395 1396 info_ptr->next_frame_width = width; 1397 info_ptr->next_frame_height = height; 1398 info_ptr->next_frame_x_offset = x_offset; 1399 info_ptr->next_frame_y_offset = y_offset; 1400 info_ptr->next_frame_delay_num = delay_num; 1401 info_ptr->next_frame_delay_den = delay_den; 1402 info_ptr->next_frame_dispose_op = dispose_op; 1403 info_ptr->next_frame_blend_op = blend_op; 1404 1405 info_ptr->valid |= PNG_INFO_fcTL; 1406 1407 return (1); 1408 } 1409 1410 void /* PRIVATE */ 1411 png_ensure_fcTL_is_valid(png_structp png_ptr, 1412 png_uint_32 width, png_uint_32 height, 1413 png_uint_32 x_offset, png_uint_32 y_offset, 1414 png_uint_16 delay_num, png_uint_16 delay_den, 1415 png_byte dispose_op, png_byte blend_op) 1416 { 1417 if (width == 0 || width > PNG_UINT_31_MAX) 1418 png_error(png_ptr, "invalid width in fcTL (0 or > 2^31-1)"); 1419 if (height == 0 || height > PNG_UINT_31_MAX) 1420 png_error(png_ptr, "invalid height in fcTL (0 or > 2^31-1)"); 1421 if (x_offset > PNG_UINT_31_MAX) 1422 png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)"); 1423 if (y_offset > PNG_UINT_31_MAX) 1424 png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)"); 1425 if (width + x_offset > png_ptr->first_frame_width || 1426 height + y_offset > png_ptr->first_frame_height) 1427 png_error(png_ptr, "dimensions of a frame are greater than " 1428 "the ones in IHDR"); 1429 1430 if (dispose_op != PNG_DISPOSE_OP_NONE && 1431 dispose_op != PNG_DISPOSE_OP_BACKGROUND && 1432 dispose_op != PNG_DISPOSE_OP_PREVIOUS) 1433 png_error(png_ptr, "invalid dispose_op in fcTL"); 1434 1435 if (blend_op != PNG_BLEND_OP_SOURCE && 1436 blend_op != PNG_BLEND_OP_OVER) 1437 png_error(png_ptr, "invalid blend_op in fcTL"); 1438 1439 PNG_UNUSED(delay_num) 1440 PNG_UNUSED(delay_den) 1441 } 1442 1443 png_uint_32 PNGAPI 1444 png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr, 1445 png_byte is_hidden) 1446 { 1447 png_debug(1, "in png_first_frame_is_hidden()"); 1448 1449 if (png_ptr == NULL) 1450 return 0; 1451 1452 if (is_hidden != 0) 1453 png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN; 1454 else 1455 png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN; 1456 1457 PNG_UNUSED(info_ptr) 1458 1459 return 1; 1460 } 1461 #endif /* APNG */ 1462 1463 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED 1464 static png_byte 1465 check_location(png_const_structrp png_ptr, int location) 1466 { 1467 location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT); 1468 1469 /* New in 1.6.0; copy the location and check it. This is an API 1470 * change; previously the app had to use the 1471 * png_set_unknown_chunk_location API below for each chunk. 1472 */ 1473 if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0) 1474 { 1475 /* Write struct, so unknown chunks come from the app */ 1476 png_app_warning(png_ptr, 1477 "png_set_unknown_chunks now expects a valid location"); 1478 /* Use the old behavior */ 1479 location = (png_byte)(png_ptr->mode & 1480 (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)); 1481 } 1482 1483 /* This need not be an internal error - if the app calls 1484 * png_set_unknown_chunks on a read pointer it must get the location right. 1485 */ 1486 if (location == 0) 1487 png_error(png_ptr, "invalid location in png_set_unknown_chunks"); 1488 1489 /* Now reduce the location to the top-most set bit by removing each least 1490 * significant bit in turn. 1491 */ 1492 while (location != (location & -location)) 1493 location &= ~(location & -location); 1494 1495 /* The cast is safe because 'location' is a bit mask and only the low four 1496 * bits are significant. 1497 */ 1498 return (png_byte)location; 1499 } 1500 1501 void PNGAPI 1502 png_set_unknown_chunks(png_const_structrp png_ptr, 1503 png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns) 1504 { 1505 png_unknown_chunkp np; 1506 1507 if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 || 1508 unknowns == NULL) 1509 return; 1510 1511 /* Check for the failure cases where support has been disabled at compile 1512 * time. This code is hardly ever compiled - it's here because 1513 * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this 1514 * code) but may be meaningless if the read or write handling of unknown 1515 * chunks is not compiled in. 1516 */ 1517 # if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \ 1518 defined(PNG_READ_SUPPORTED) 1519 if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) 1520 { 1521 png_app_error(png_ptr, "no unknown chunk support on read"); 1522 1523 return; 1524 } 1525 # endif 1526 # if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \ 1527 defined(PNG_WRITE_SUPPORTED) 1528 if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) 1529 { 1530 png_app_error(png_ptr, "no unknown chunk support on write"); 1531 1532 return; 1533 } 1534 # endif 1535 1536 /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that 1537 * unknown critical chunks could be lost with just a warning resulting in 1538 * undefined behavior. Now png_chunk_report is used to provide behavior 1539 * appropriate to read or write. 1540 */ 1541 np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr, 1542 info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns, 1543 sizeof *np)); 1544 1545 if (np == NULL) 1546 { 1547 png_chunk_report(png_ptr, "too many unknown chunks", 1548 PNG_CHUNK_WRITE_ERROR); 1549 return; 1550 } 1551 1552 png_free(png_ptr, info_ptr->unknown_chunks); 1553 1554 info_ptr->unknown_chunks = np; /* safe because it is initialized */ 1555 info_ptr->free_me |= PNG_FREE_UNKN; 1556 1557 np += info_ptr->unknown_chunks_num; 1558 1559 /* Increment unknown_chunks_num each time round the loop to protect the 1560 * just-allocated chunk data. 1561 */ 1562 for (; num_unknowns > 0; --num_unknowns, ++unknowns) 1563 { 1564 memcpy(np->name, unknowns->name, (sizeof np->name)); 1565 np->name[(sizeof np->name)-1] = '\0'; 1566 np->location = check_location(png_ptr, unknowns->location); 1567 1568 if (unknowns->size == 0) 1569 { 1570 np->data = NULL; 1571 np->size = 0; 1572 } 1573 1574 else 1575 { 1576 np->data = png_voidcast(png_bytep, 1577 png_malloc_base(png_ptr, unknowns->size)); 1578 1579 if (np->data == NULL) 1580 { 1581 png_chunk_report(png_ptr, "unknown chunk: out of memory", 1582 PNG_CHUNK_WRITE_ERROR); 1583 /* But just skip storing the unknown chunk */ 1584 continue; 1585 } 1586 1587 memcpy(np->data, unknowns->data, unknowns->size); 1588 np->size = unknowns->size; 1589 } 1590 1591 /* These increments are skipped on out-of-memory for the data - the 1592 * unknown chunk entry gets overwritten if the png_chunk_report returns. 1593 * This is correct in the read case (the chunk is just dropped.) 1594 */ 1595 ++np; 1596 ++(info_ptr->unknown_chunks_num); 1597 } 1598 } 1599 1600 void PNGAPI 1601 png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr, 1602 int chunk, int location) 1603 { 1604 /* This API is pretty pointless in 1.6.0 because the location can be set 1605 * before the call to png_set_unknown_chunks. 1606 * 1607 * TODO: add a png_app_warning in 1.7 1608 */ 1609 if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && 1610 chunk < info_ptr->unknown_chunks_num) 1611 { 1612 if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0) 1613 { 1614 png_app_error(png_ptr, "invalid unknown chunk location"); 1615 /* Fake out the pre 1.6.0 behavior: */ 1616 if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */ 1617 location = PNG_AFTER_IDAT; 1618 1619 else 1620 location = PNG_HAVE_IHDR; /* also undocumented */ 1621 } 1622 1623 info_ptr->unknown_chunks[chunk].location = 1624 check_location(png_ptr, location); 1625 } 1626 } 1627 #endif /* STORE_UNKNOWN_CHUNKS */ 1628 1629 #ifdef PNG_MNG_FEATURES_SUPPORTED 1630 png_uint_32 PNGAPI 1631 png_permit_mng_features(png_structrp png_ptr, png_uint_32 mng_features) 1632 { 1633 png_debug(1, "in png_permit_mng_features"); 1634 1635 if (png_ptr == NULL) 1636 return 0; 1637 1638 png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES; 1639 1640 return png_ptr->mng_features_permitted; 1641 } 1642 #endif 1643 1644 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED 1645 static unsigned int 1646 add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep) 1647 { 1648 unsigned int i; 1649 1650 /* Utility function: update the 'keep' state of a chunk if it is already in 1651 * the list, otherwise add it to the list. 1652 */ 1653 for (i=0; i<count; ++i, list += 5) 1654 { 1655 if (memcmp(list, add, 4) == 0) 1656 { 1657 list[4] = (png_byte)keep; 1658 1659 return count; 1660 } 1661 } 1662 1663 if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT) 1664 { 1665 ++count; 1666 memcpy(list, add, 4); 1667 list[4] = (png_byte)keep; 1668 } 1669 1670 return count; 1671 } 1672 1673 void PNGAPI 1674 png_set_keep_unknown_chunks(png_structrp png_ptr, int keep, 1675 png_const_bytep chunk_list, int num_chunks_in) 1676 { 1677 png_bytep new_list; 1678 unsigned int num_chunks, old_num_chunks; 1679 1680 if (png_ptr == NULL) 1681 return; 1682 1683 if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST) 1684 { 1685 png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep"); 1686 1687 return; 1688 } 1689 1690 if (num_chunks_in <= 0) 1691 { 1692 png_ptr->unknown_default = keep; 1693 1694 /* '0' means just set the flags, so stop here */ 1695 if (num_chunks_in == 0) 1696 return; 1697 } 1698 1699 if (num_chunks_in < 0) 1700 { 1701 /* Ignore all unknown chunks and all chunks recognized by 1702 * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND 1703 */ 1704 static const png_byte chunks_to_ignore[] = { 1705 98, 75, 71, 68, '\0', /* bKGD */ 1706 99, 72, 82, 77, '\0', /* cHRM */ 1707 99, 73, 67, 80, '\0', /* cICP */ 1708 99, 76, 76, 73, '\0', /* cLLI */ 1709 101, 88, 73, 102, '\0', /* eXIf */ 1710 103, 65, 77, 65, '\0', /* gAMA */ 1711 104, 73, 83, 84, '\0', /* hIST */ 1712 105, 67, 67, 80, '\0', /* iCCP */ 1713 105, 84, 88, 116, '\0', /* iTXt */ 1714 109, 68, 67, 86, '\0', /* mDCV */ 1715 111, 70, 70, 115, '\0', /* oFFs */ 1716 112, 67, 65, 76, '\0', /* pCAL */ 1717 112, 72, 89, 115, '\0', /* pHYs */ 1718 115, 66, 73, 84, '\0', /* sBIT */ 1719 115, 67, 65, 76, '\0', /* sCAL */ 1720 115, 80, 76, 84, '\0', /* sPLT */ 1721 115, 84, 69, 82, '\0', /* sTER */ 1722 115, 82, 71, 66, '\0', /* sRGB */ 1723 116, 69, 88, 116, '\0', /* tEXt */ 1724 116, 73, 77, 69, '\0', /* tIME */ 1725 122, 84, 88, 116, '\0' /* zTXt */ 1726 }; 1727 1728 chunk_list = chunks_to_ignore; 1729 num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U; 1730 } 1731 1732 else /* num_chunks_in > 0 */ 1733 { 1734 if (chunk_list == NULL) 1735 { 1736 /* Prior to 1.6.0 this was silently ignored, now it is an app_error 1737 * which can be switched off. 1738 */ 1739 png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list"); 1740 1741 return; 1742 } 1743 1744 num_chunks = (unsigned int)num_chunks_in; 1745 } 1746 1747 old_num_chunks = png_ptr->num_chunk_list; 1748 if (png_ptr->chunk_list == NULL) 1749 old_num_chunks = 0; 1750 1751 /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow. 1752 */ 1753 if (num_chunks + old_num_chunks > UINT_MAX/5) 1754 { 1755 png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks"); 1756 1757 return; 1758 } 1759 1760 /* If these chunks are being reset to the default then no more memory is 1761 * required because add_one_chunk above doesn't extend the list if the 'keep' 1762 * parameter is the default. 1763 */ 1764 if (keep != 0) 1765 { 1766 new_list = png_voidcast(png_bytep, png_malloc(png_ptr, 1767 5 * (num_chunks + old_num_chunks))); 1768 1769 if (old_num_chunks > 0) 1770 memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks); 1771 } 1772 1773 else if (old_num_chunks > 0) 1774 new_list = png_ptr->chunk_list; 1775 1776 else 1777 new_list = NULL; 1778 1779 /* Add the new chunks together with each one's handling code. If the chunk 1780 * already exists the code is updated, otherwise the chunk is added to the 1781 * end. (In libpng 1.6.0 order no longer matters because this code enforces 1782 * the earlier convention that the last setting is the one that is used.) 1783 */ 1784 if (new_list != NULL) 1785 { 1786 png_const_bytep inlist; 1787 png_bytep outlist; 1788 unsigned int i; 1789 1790 for (i=0; i<num_chunks; ++i) 1791 { 1792 old_num_chunks = add_one_chunk(new_list, old_num_chunks, 1793 chunk_list+5*i, keep); 1794 } 1795 1796 /* Now remove any spurious 'default' entries. */ 1797 num_chunks = 0; 1798 for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5) 1799 { 1800 if (inlist[4]) 1801 { 1802 if (outlist != inlist) 1803 memcpy(outlist, inlist, 5); 1804 outlist += 5; 1805 ++num_chunks; 1806 } 1807 } 1808 1809 /* This means the application has removed all the specialized handling. */ 1810 if (num_chunks == 0) 1811 { 1812 if (png_ptr->chunk_list != new_list) 1813 png_free(png_ptr, new_list); 1814 1815 new_list = NULL; 1816 } 1817 } 1818 1819 else 1820 num_chunks = 0; 1821 1822 png_ptr->num_chunk_list = num_chunks; 1823 1824 if (png_ptr->chunk_list != new_list) 1825 { 1826 if (png_ptr->chunk_list != NULL) 1827 png_free(png_ptr, png_ptr->chunk_list); 1828 1829 png_ptr->chunk_list = new_list; 1830 } 1831 } 1832 #endif 1833 1834 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED 1835 void PNGAPI 1836 png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr, 1837 png_user_chunk_ptr read_user_chunk_fn) 1838 { 1839 png_debug(1, "in png_set_read_user_chunk_fn"); 1840 1841 if (png_ptr == NULL) 1842 return; 1843 1844 png_ptr->read_user_chunk_fn = read_user_chunk_fn; 1845 png_ptr->user_chunk_ptr = user_chunk_ptr; 1846 } 1847 #endif 1848 1849 #ifdef PNG_INFO_IMAGE_SUPPORTED 1850 void PNGAPI 1851 png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr, 1852 png_bytepp row_pointers) 1853 { 1854 png_debug(1, "in png_set_rows"); 1855 1856 if (png_ptr == NULL || info_ptr == NULL) 1857 return; 1858 1859 if (info_ptr->row_pointers != NULL && 1860 (info_ptr->row_pointers != row_pointers)) 1861 png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0); 1862 1863 info_ptr->row_pointers = row_pointers; 1864 1865 if (row_pointers != NULL) 1866 info_ptr->valid |= PNG_INFO_IDAT; 1867 } 1868 #endif 1869 1870 void PNGAPI 1871 png_set_compression_buffer_size(png_structrp png_ptr, size_t size) 1872 { 1873 png_debug(1, "in png_set_compression_buffer_size"); 1874 1875 if (png_ptr == NULL) 1876 return; 1877 1878 if (size == 0 || size > PNG_UINT_31_MAX) 1879 png_error(png_ptr, "invalid compression buffer size"); 1880 1881 # ifdef PNG_SEQUENTIAL_READ_SUPPORTED 1882 if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0) 1883 { 1884 png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */ 1885 return; 1886 } 1887 # endif 1888 1889 # ifdef PNG_WRITE_SUPPORTED 1890 if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0) 1891 { 1892 if (png_ptr->zowner != 0) 1893 { 1894 png_warning(png_ptr, 1895 "Compression buffer size cannot be changed because it is in use"); 1896 1897 return; 1898 } 1899 1900 #ifndef __COVERITY__ 1901 /* Some compilers complain that this is always false. However, it 1902 * can be true when integer overflow happens. 1903 */ 1904 if (size > ZLIB_IO_MAX) 1905 { 1906 png_warning(png_ptr, 1907 "Compression buffer size limited to system maximum"); 1908 size = ZLIB_IO_MAX; /* must fit */ 1909 } 1910 #endif 1911 1912 if (size < 6) 1913 { 1914 /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH 1915 * if this is permitted. 1916 */ 1917 png_warning(png_ptr, 1918 "Compression buffer size cannot be reduced below 6"); 1919 1920 return; 1921 } 1922 1923 if (png_ptr->zbuffer_size != size) 1924 { 1925 png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list); 1926 png_ptr->zbuffer_size = (uInt)size; 1927 } 1928 } 1929 # endif 1930 } 1931 1932 void PNGAPI 1933 png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask) 1934 { 1935 if (png_ptr != NULL && info_ptr != NULL) 1936 info_ptr->valid &= (unsigned int)(~mask); 1937 } 1938 1939 1940 #ifdef PNG_SET_USER_LIMITS_SUPPORTED 1941 /* This function was added to libpng 1.2.6 */ 1942 void PNGAPI 1943 png_set_user_limits(png_structrp png_ptr, png_uint_32 user_width_max, 1944 png_uint_32 user_height_max) 1945 { 1946 png_debug(1, "in png_set_user_limits"); 1947 1948 /* Images with dimensions larger than these limits will be 1949 * rejected by png_set_IHDR(). To accept any PNG datastream 1950 * regardless of dimensions, set both limits to 0x7fffffff. 1951 */ 1952 if (png_ptr == NULL) 1953 return; 1954 1955 png_ptr->user_width_max = user_width_max; 1956 png_ptr->user_height_max = user_height_max; 1957 } 1958 1959 /* This function was added to libpng 1.4.0 */ 1960 void PNGAPI 1961 png_set_chunk_cache_max(png_structrp png_ptr, png_uint_32 user_chunk_cache_max) 1962 { 1963 png_debug(1, "in png_set_chunk_cache_max"); 1964 1965 if (png_ptr != NULL) 1966 png_ptr->user_chunk_cache_max = user_chunk_cache_max; 1967 } 1968 1969 /* This function was added to libpng 1.4.1 */ 1970 void PNGAPI 1971 png_set_chunk_malloc_max(png_structrp png_ptr, 1972 png_alloc_size_t user_chunk_malloc_max) 1973 { 1974 png_debug(1, "in png_set_chunk_malloc_max"); 1975 1976 /* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in 1977 * png.c. This API supports '0' for unlimited, make sure the correct 1978 * (unlimited) value is set here to avoid a need to check for 0 everywhere 1979 * the parameter is used. 1980 */ 1981 if (png_ptr != NULL) 1982 { 1983 if (user_chunk_malloc_max == 0U) /* unlimited */ 1984 { 1985 # ifdef PNG_MAX_MALLOC_64K 1986 png_ptr->user_chunk_malloc_max = 65536U; 1987 # else 1988 png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX; 1989 # endif 1990 } 1991 else 1992 png_ptr->user_chunk_malloc_max = user_chunk_malloc_max; 1993 } 1994 } 1995 #endif /* ?SET_USER_LIMITS */ 1996 1997 1998 #ifdef PNG_BENIGN_ERRORS_SUPPORTED 1999 void PNGAPI 2000 png_set_benign_errors(png_structrp png_ptr, int allowed) 2001 { 2002 png_debug(1, "in png_set_benign_errors"); 2003 2004 /* If allowed is 1, png_benign_error() is treated as a warning. 2005 * 2006 * If allowed is 0, png_benign_error() is treated as an error (which 2007 * is the default behavior if png_set_benign_errors() is not called). 2008 */ 2009 2010 if (allowed != 0) 2011 png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN | 2012 PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN; 2013 2014 else 2015 png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN | 2016 PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN); 2017 } 2018 #endif /* BENIGN_ERRORS */ 2019 2020 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED 2021 /* Whether to report invalid palette index; added at libng-1.5.10. 2022 * It is possible for an indexed (color-type==3) PNG file to contain 2023 * pixels with invalid (out-of-range) indexes if the PLTE chunk has 2024 * fewer entries than the image's bit-depth would allow. We recover 2025 * from this gracefully by filling any incomplete palette with zeros 2026 * (opaque black). By default, when this occurs libpng will issue 2027 * a benign error. This API can be used to override that behavior. 2028 */ 2029 void PNGAPI 2030 png_set_check_for_invalid_index(png_structrp png_ptr, int allowed) 2031 { 2032 png_debug(1, "in png_set_check_for_invalid_index"); 2033 2034 if (allowed > 0) 2035 png_ptr->num_palette_max = 0; 2036 2037 else 2038 png_ptr->num_palette_max = -1; 2039 } 2040 #endif 2041 2042 #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \ 2043 defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED) 2044 /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification, 2045 * and if invalid, correct the keyword rather than discarding the entire 2046 * chunk. The PNG 1.0 specification requires keywords 1-79 characters in 2047 * length, forbids leading or trailing whitespace, multiple internal spaces, 2048 * and the non-break space (0x80) from ISO 8859-1. Returns keyword length. 2049 * 2050 * The 'new_key' buffer must be 80 characters in size (for the keyword plus a 2051 * trailing '\0'). If this routine returns 0 then there was no keyword, or a 2052 * valid one could not be generated, and the caller must png_error. 2053 */ 2054 png_uint_32 /* PRIVATE */ 2055 png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key) 2056 { 2057 #ifdef PNG_WARNINGS_SUPPORTED 2058 png_const_charp orig_key = key; 2059 #endif 2060 png_uint_32 key_len = 0; 2061 int bad_character = 0; 2062 int space = 1; 2063 2064 png_debug(1, "in png_check_keyword"); 2065 2066 if (key == NULL) 2067 { 2068 *new_key = 0; 2069 return 0; 2070 } 2071 2072 while (*key && key_len < 79) 2073 { 2074 png_byte ch = (png_byte)*key++; 2075 2076 if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/)) 2077 { 2078 *new_key++ = ch; ++key_len; space = 0; 2079 } 2080 2081 else if (space == 0) 2082 { 2083 /* A space or an invalid character when one wasn't seen immediately 2084 * before; output just a space. 2085 */ 2086 *new_key++ = 32; ++key_len; space = 1; 2087 2088 /* If the character was not a space then it is invalid. */ 2089 if (ch != 32) 2090 bad_character = ch; 2091 } 2092 2093 else if (bad_character == 0) 2094 bad_character = ch; /* just skip it, record the first error */ 2095 } 2096 2097 if (key_len > 0 && space != 0) /* trailing space */ 2098 { 2099 --key_len; --new_key; 2100 if (bad_character == 0) 2101 bad_character = 32; 2102 } 2103 2104 /* Terminate the keyword */ 2105 *new_key = 0; 2106 2107 if (key_len == 0) 2108 return 0; 2109 2110 #ifdef PNG_WARNINGS_SUPPORTED 2111 /* Try to only output one warning per keyword: */ 2112 if (*key != 0) /* keyword too long */ 2113 png_warning(png_ptr, "keyword truncated"); 2114 2115 else if (bad_character != 0) 2116 { 2117 PNG_WARNING_PARAMETERS(p) 2118 2119 png_warning_parameter(p, 1, orig_key); 2120 png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character); 2121 2122 png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'"); 2123 } 2124 #else /* !WARNINGS */ 2125 PNG_UNUSED(png_ptr) 2126 #endif /* !WARNINGS */ 2127 2128 return key_len; 2129 } 2130 #endif /* TEXT || pCAL || iCCP || sPLT */ 2131 #endif /* READ || WRITE */