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