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