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