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.23 [June 9, 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       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        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
 984        {
 985          /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
 986           info_ptr->trans_alpha = png_voidcast(png_bytep,
 987              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));


 988           memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
 989        }
 990        png_ptr->trans_alpha = info_ptr->trans_alpha;
 991    }
 992 
 993    if (trans_color != NULL)
 994    {
 995 #ifdef PNG_WARNINGS_SUPPORTED
 996       if (info_ptr->bit_depth < 16)
 997       {
 998          int sample_max = (1 << info_ptr->bit_depth) - 1;
 999 
1000          if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1001              trans_color->gray > sample_max) ||
1002              (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1003              (trans_color->red > sample_max ||
1004              trans_color->green > sample_max ||
1005              trans_color->blue > sample_max)))
1006             png_warning(png_ptr,
1007                "tRNS chunk has out-of-range samples for bit_depth");
1008       }
1009 #endif
1010 
1011       info_ptr->trans_color = *trans_color;
1012 
1013       if (num_trans == 0)
1014          num_trans = 1;
1015    }
1016 
1017    info_ptr->num_trans = (png_uint_16)num_trans;
1018 
1019    if (num_trans != 0)
1020    {
1021       info_ptr->valid |= PNG_INFO_tRNS;
1022       info_ptr->free_me |= PNG_FREE_TRNS;
1023    }
1024 }
1025 #endif
1026 
1027 #ifdef PNG_sPLT_SUPPORTED
1028 void PNGAPI
1029 png_set_sPLT(png_const_structrp png_ptr,
1030     png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
1031 /*
1032  *  entries        - array of png_sPLT_t structures
1033  *                   to be added to the list of palettes
1034  *                   in the info structure.
1035  *
1036  *  nentries       - number of palette structures to be
1037  *                   added.
1038  */
1039 {
1040    png_sPLT_tp np;
1041 
1042    if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
1043       return;
1044 
1045    /* Use the internal realloc function, which checks for all the possible
1046     * overflows.  Notice that the parameters are (int) and (size_t)
1047     */
1048    np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
1049       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
1050       sizeof *np));
1051 
1052    if (np == NULL)
1053    {
1054       /* Out of memory or too many chunks */
1055       png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
1056 
1057       return;
1058    }
1059 
1060    png_free(png_ptr, info_ptr->splt_palettes);
1061    info_ptr->splt_palettes = np;
1062    info_ptr->free_me |= PNG_FREE_SPLT;
1063 
1064    np += info_ptr->splt_palettes_num;
1065 
1066    do
1067    {
1068       png_size_t length;
1069 
1070       /* Skip invalid input entries */
1071       if (entries->name == NULL || entries->entries == NULL)
1072       {
1073          /* png_handle_sPLT doesn't do this, so this is an app error */
1074          png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
1075          /* Just skip the invalid entry */
1076          continue;
1077       }
1078 
1079       np->depth = entries->depth;
1080 
1081       /* In the event of out-of-memory just return - there's no point keeping
1082        * on trying to add sPLT chunks.
1083        */
1084       length = strlen(entries->name) + 1;
1085       np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));
1086 
1087       if (np->name == NULL)
1088          break;
1089 
1090       memcpy(np->name, entries->name, length);
1091 
1092       /* IMPORTANT: we have memory now that won't get freed if something else
1093        * goes wrong; this code must free it.  png_malloc_array produces no
1094        * warnings; use a png_chunk_report (below) if there is an error.
1095        */
1096       np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
1097           entries->nentries, sizeof (png_sPLT_entry)));
1098 
1099       if (np->entries == NULL)
1100       {
1101          png_free(png_ptr, np->name);
1102          np->name = NULL;
1103          break;
1104       }
1105 
1106       np->nentries = entries->nentries;
1107       /* This multiply can't overflow because png_malloc_array has already
1108        * checked it when doing the allocation.
1109        */
1110       memcpy(np->entries, entries->entries,
1111          entries->nentries * sizeof (png_sPLT_entry));
1112 
1113       /* Note that 'continue' skips the advance of the out pointer and out
1114        * count, so an invalid entry is not added.
1115        */
1116       info_ptr->valid |= PNG_INFO_sPLT;
1117       ++(info_ptr->splt_palettes_num);
1118       ++np;
1119    }
1120    while (++entries, --nentries);
1121 
1122    if (nentries > 0)
1123       png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
1124 }
1125 #endif /* sPLT */
1126 
1127 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1128 static png_byte
1129 check_location(png_const_structrp png_ptr, int location)
1130 {
1131    location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
1132 
1133    /* New in 1.6.0; copy the location and check it.  This is an API
1134     * change; previously the app had to use the
1135     * png_set_unknown_chunk_location API below for each chunk.
1136     */
1137    if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1138    {
1139       /* Write struct, so unknown chunks come from the app */
1140       png_app_warning(png_ptr,
1141          "png_set_unknown_chunks now expects a valid location");
1142       /* Use the old behavior */
1143       location = (png_byte)(png_ptr->mode &
1144          (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
1145    }
1146 
1147    /* This need not be an internal error - if the app calls
1148     * png_set_unknown_chunks on a read pointer it must get the location right.
1149     */
1150    if (location == 0)
1151       png_error(png_ptr, "invalid location in png_set_unknown_chunks");
1152 
1153    /* Now reduce the location to the top-most set bit by removing each least
1154     * significant bit in turn.
1155     */
1156    while (location != (location & -location))
1157       location &= ~(location & -location);
1158 
1159    /* The cast is safe because 'location' is a bit mask and only the low four
1160     * bits are significant.
1161     */
1162    return (png_byte)location;
1163 }
1164 
1165 void PNGAPI
1166 png_set_unknown_chunks(png_const_structrp png_ptr,
1167    png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
1168 {
1169    png_unknown_chunkp np;
1170 
1171    if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
1172        unknowns == NULL)
1173       return;
1174 
1175    /* Check for the failure cases where support has been disabled at compile
1176     * time.  This code is hardly ever compiled - it's here because
1177     * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
1178     * code) but may be meaningless if the read or write handling of unknown
1179     * chunks is not compiled in.
1180     */
1181 #  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
1182       defined(PNG_READ_SUPPORTED)
1183       if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1184       {
1185          png_app_error(png_ptr, "no unknown chunk support on read");
1186 
1187          return;
1188       }
1189 #  endif
1190 #  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
1191       defined(PNG_WRITE_SUPPORTED)
1192       if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1193       {
1194          png_app_error(png_ptr, "no unknown chunk support on write");
1195 
1196          return;
1197       }
1198 #  endif
1199 
1200    /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
1201     * unknown critical chunks could be lost with just a warning resulting in
1202     * undefined behavior.  Now png_chunk_report is used to provide behavior
1203     * appropriate to read or write.
1204     */
1205    np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
1206          info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
1207          sizeof *np));
1208 
1209    if (np == NULL)
1210    {
1211       png_chunk_report(png_ptr, "too many unknown chunks",
1212          PNG_CHUNK_WRITE_ERROR);
1213 
1214       return;
1215    }
1216 
1217    png_free(png_ptr, info_ptr->unknown_chunks);
1218    info_ptr->unknown_chunks = np; /* safe because it is initialized */
1219    info_ptr->free_me |= PNG_FREE_UNKN;
1220 
1221    np += info_ptr->unknown_chunks_num;
1222 
1223    /* Increment unknown_chunks_num each time round the loop to protect the
1224     * just-allocated chunk data.
1225     */
1226    for (; num_unknowns > 0; --num_unknowns, ++unknowns)
1227    {
1228       memcpy(np->name, unknowns->name, (sizeof np->name));
1229       np->name[(sizeof np->name)-1] = '\0';
1230       np->location = check_location(png_ptr, unknowns->location);
1231 
1232       if (unknowns->size == 0)
1233       {
1234          np->data = NULL;
1235          np->size = 0;
1236       }
1237 
1238       else
1239       {
1240          np->data = png_voidcast(png_bytep,
1241             png_malloc_base(png_ptr, unknowns->size));
1242 
1243          if (np->data == NULL)
1244          {
1245             png_chunk_report(png_ptr, "unknown chunk: out of memory",
1246                PNG_CHUNK_WRITE_ERROR);
1247             /* But just skip storing the unknown chunk */
1248             continue;
1249          }
1250 
1251          memcpy(np->data, unknowns->data, unknowns->size);
1252          np->size = unknowns->size;
1253       }
1254 
1255       /* These increments are skipped on out-of-memory for the data - the
1256        * unknown chunk entry gets overwritten if the png_chunk_report returns.
1257        * This is correct in the read case (the chunk is just dropped.)
1258        */
1259       ++np;
1260       ++(info_ptr->unknown_chunks_num);
1261    }
1262 }
1263 
1264 void PNGAPI
1265 png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
1266     int chunk, int location)
1267 {
1268    /* This API is pretty pointless in 1.6.0 because the location can be set
1269     * before the call to png_set_unknown_chunks.
1270     *
1271     * TODO: add a png_app_warning in 1.7
1272     */
1273    if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
1274       chunk < info_ptr->unknown_chunks_num)
1275    {
1276       if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
1277       {
1278          png_app_error(png_ptr, "invalid unknown chunk location");
1279          /* Fake out the pre 1.6.0 behavior: */
1280          if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */
1281             location = PNG_AFTER_IDAT;
1282 
1283          else
1284             location = PNG_HAVE_IHDR; /* also undocumented */
1285       }
1286 
1287       info_ptr->unknown_chunks[chunk].location =
1288          check_location(png_ptr, location);
1289    }
1290 }
1291 #endif /* STORE_UNKNOWN_CHUNKS */
1292 
1293 #ifdef PNG_MNG_FEATURES_SUPPORTED
1294 png_uint_32 PNGAPI
1295 png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
1296 {
1297    png_debug(1, "in png_permit_mng_features");
1298 
1299    if (png_ptr == NULL)
1300       return 0;
1301 
1302    png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1303 
1304    return png_ptr->mng_features_permitted;
1305 }
1306 #endif
1307 
1308 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1309 static unsigned int
1310 add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
1311 {
1312    unsigned int i;
1313 
1314    /* Utility function: update the 'keep' state of a chunk if it is already in
1315     * the list, otherwise add it to the list.
1316     */
1317    for (i=0; i<count; ++i, list += 5)
1318    {
1319       if (memcmp(list, add, 4) == 0)
1320       {
1321          list[4] = (png_byte)keep;
1322 
1323          return count;
1324       }
1325    }
1326 
1327    if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
1328    {
1329       ++count;
1330       memcpy(list, add, 4);
1331       list[4] = (png_byte)keep;
1332    }
1333 
1334    return count;
1335 }
1336 
1337 void PNGAPI
1338 png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
1339     png_const_bytep chunk_list, int num_chunks_in)
1340 {
1341    png_bytep new_list;
1342    unsigned int num_chunks, old_num_chunks;
1343 
1344    if (png_ptr == NULL)
1345       return;
1346 
1347    if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
1348    {
1349       png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
1350 
1351       return;
1352    }
1353 
1354    if (num_chunks_in <= 0)
1355    {
1356       png_ptr->unknown_default = keep;
1357 
1358       /* '0' means just set the flags, so stop here */
1359       if (num_chunks_in == 0)
1360         return;
1361    }
1362 
1363    if (num_chunks_in < 0)
1364    {
1365       /* Ignore all unknown chunks and all chunks recognized by
1366        * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
1367        */
1368       static PNG_CONST png_byte chunks_to_ignore[] = {
1369          98,  75,  71,  68, '\0',  /* bKGD */
1370          99,  72,  82,  77, '\0',  /* cHRM */
1371         103,  65,  77,  65, '\0',  /* gAMA */
1372         104,  73,  83,  84, '\0',  /* hIST */
1373         105,  67,  67,  80, '\0',  /* iCCP */
1374         105,  84,  88, 116, '\0',  /* iTXt */
1375         111,  70,  70, 115, '\0',  /* oFFs */
1376         112,  67,  65,  76, '\0',  /* pCAL */
1377         112,  72,  89, 115, '\0',  /* pHYs */
1378         115,  66,  73,  84, '\0',  /* sBIT */
1379         115,  67,  65,  76, '\0',  /* sCAL */
1380         115,  80,  76,  84, '\0',  /* sPLT */
1381         115,  84,  69,  82, '\0',  /* sTER */
1382         115,  82,  71,  66, '\0',  /* sRGB */
1383         116,  69,  88, 116, '\0',  /* tEXt */
1384         116,  73,  77,  69, '\0',  /* tIME */
1385         122,  84,  88, 116, '\0'   /* zTXt */
1386       };
1387 
1388       chunk_list = chunks_to_ignore;
1389       num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U;
1390    }
1391 
1392    else /* num_chunks_in > 0 */
1393    {
1394       if (chunk_list == NULL)
1395       {
1396          /* Prior to 1.6.0 this was silently ignored, now it is an app_error
1397           * which can be switched off.
1398           */
1399          png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
1400 
1401          return;
1402       }
1403 
1404       num_chunks = num_chunks_in;
1405    }
1406 
1407    old_num_chunks = png_ptr->num_chunk_list;
1408    if (png_ptr->chunk_list == NULL)
1409       old_num_chunks = 0;
1410 
1411    /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
1412     */
1413    if (num_chunks + old_num_chunks > UINT_MAX/5)
1414    {
1415       png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
1416 
1417       return;
1418    }
1419 
1420    /* If these chunks are being reset to the default then no more memory is
1421     * required because add_one_chunk above doesn't extend the list if the 'keep'
1422     * parameter is the default.
1423     */
1424    if (keep != 0)
1425    {
1426       new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
1427           5 * (num_chunks + old_num_chunks)));
1428 
1429       if (old_num_chunks > 0)
1430          memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1431    }
1432 
1433    else if (old_num_chunks > 0)
1434       new_list = png_ptr->chunk_list;
1435 
1436    else
1437       new_list = NULL;
1438 
1439    /* Add the new chunks together with each one's handling code.  If the chunk
1440     * already exists the code is updated, otherwise the chunk is added to the
1441     * end.  (In libpng 1.6.0 order no longer matters because this code enforces
1442     * the earlier convention that the last setting is the one that is used.)
1443     */
1444    if (new_list != NULL)
1445    {
1446       png_const_bytep inlist;
1447       png_bytep outlist;
1448       unsigned int i;
1449 
1450       for (i=0; i<num_chunks; ++i)
1451       {
1452          old_num_chunks = add_one_chunk(new_list, old_num_chunks,
1453             chunk_list+5*i, keep);
1454       }
1455 
1456       /* Now remove any spurious 'default' entries. */
1457       num_chunks = 0;
1458       for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1459       {
1460          if (inlist[4])
1461          {
1462             if (outlist != inlist)
1463                memcpy(outlist, inlist, 5);
1464             outlist += 5;
1465             ++num_chunks;
1466          }
1467       }
1468 
1469       /* This means the application has removed all the specialized handling. */
1470       if (num_chunks == 0)
1471       {
1472          if (png_ptr->chunk_list != new_list)
1473             png_free(png_ptr, new_list);
1474 
1475          new_list = NULL;
1476       }
1477    }
1478 
1479    else
1480       num_chunks = 0;
1481 
1482    png_ptr->num_chunk_list = num_chunks;
1483 
1484    if (png_ptr->chunk_list != new_list)
1485    {
1486       if (png_ptr->chunk_list != NULL)
1487          png_free(png_ptr, png_ptr->chunk_list);
1488 
1489       png_ptr->chunk_list = new_list;
1490    }
1491 }
1492 #endif
1493 
1494 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1495 void PNGAPI
1496 png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
1497     png_user_chunk_ptr read_user_chunk_fn)
1498 {
1499    png_debug(1, "in png_set_read_user_chunk_fn");
1500 
1501    if (png_ptr == NULL)
1502       return;
1503 
1504    png_ptr->read_user_chunk_fn = read_user_chunk_fn;
1505    png_ptr->user_chunk_ptr = user_chunk_ptr;
1506 }
1507 #endif
1508 
1509 #ifdef PNG_INFO_IMAGE_SUPPORTED
1510 void PNGAPI
1511 png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
1512     png_bytepp row_pointers)
1513 {
1514    png_debug1(1, "in %s storage function", "rows");
1515 
1516    if (png_ptr == NULL || info_ptr == NULL)
1517       return;
1518 
1519    if (info_ptr->row_pointers != NULL &&
1520        (info_ptr->row_pointers != row_pointers))
1521       png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1522 
1523    info_ptr->row_pointers = row_pointers;
1524 
1525    if (row_pointers != NULL)
1526       info_ptr->valid |= PNG_INFO_IDAT;
1527 }
1528 #endif
1529 
1530 void PNGAPI
1531 png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
1532 {
1533     if (png_ptr == NULL)
1534        return;
1535 
1536     if (size == 0 || size > PNG_UINT_31_MAX)
1537        png_error(png_ptr, "invalid compression buffer size");
1538 
1539 #  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1540       if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1541       {
1542          png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
1543          return;
1544       }
1545 #  endif
1546 
1547 #  ifdef PNG_WRITE_SUPPORTED
1548       if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1549       {
1550          if (png_ptr->zowner != 0)
1551          {
1552             png_warning(png_ptr,
1553               "Compression buffer size cannot be changed because it is in use");
1554 
1555             return;
1556          }
1557 
1558 #ifndef __COVERITY__
1559          /* Some compilers complain that this is always false.  However, it
1560           * can be true when integer overflow happens.
1561           */
1562          if (size > ZLIB_IO_MAX)
1563          {
1564             png_warning(png_ptr,
1565                "Compression buffer size limited to system maximum");
1566             size = ZLIB_IO_MAX; /* must fit */
1567          }
1568 #endif
1569 
1570          if (size < 6)
1571          {
1572             /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
1573              * if this is permitted.
1574              */
1575             png_warning(png_ptr,
1576                "Compression buffer size cannot be reduced below 6");
1577 
1578             return;
1579          }
1580 
1581          if (png_ptr->zbuffer_size != size)
1582          {
1583             png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
1584             png_ptr->zbuffer_size = (uInt)size;
1585          }
1586       }
1587 #  endif
1588 }
1589 
1590 void PNGAPI
1591 png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
1592 {
1593    if (png_ptr != NULL && info_ptr != NULL)
1594       info_ptr->valid &= ~mask;
1595 }
1596 
1597 
1598 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
1599 /* This function was added to libpng 1.2.6 */
1600 void PNGAPI
1601 png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
1602     png_uint_32 user_height_max)
1603 {
1604    /* Images with dimensions larger than these limits will be
1605     * rejected by png_set_IHDR().  To accept any PNG datastream
1606     * regardless of dimensions, set both limits to 0x7fffffff.
1607     */
1608    if (png_ptr == NULL)
1609       return;
1610 
1611    png_ptr->user_width_max = user_width_max;
1612    png_ptr->user_height_max = user_height_max;
1613 }
1614 
1615 /* This function was added to libpng 1.4.0 */
1616 void PNGAPI
1617 png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
1618 {
1619    if (png_ptr != NULL)
1620       png_ptr->user_chunk_cache_max = user_chunk_cache_max;
1621 }
1622 
1623 /* This function was added to libpng 1.4.1 */
1624 void PNGAPI
1625 png_set_chunk_malloc_max (png_structrp png_ptr,
1626     png_alloc_size_t user_chunk_malloc_max)
1627 {
1628    if (png_ptr != NULL)
1629       png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
1630 }
1631 #endif /* ?SET_USER_LIMITS */
1632 
1633 
1634 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
1635 void PNGAPI
1636 png_set_benign_errors(png_structrp png_ptr, int allowed)
1637 {
1638    png_debug(1, "in png_set_benign_errors");
1639 
1640    /* If allowed is 1, png_benign_error() is treated as a warning.
1641     *
1642     * If allowed is 0, png_benign_error() is treated as an error (which
1643     * is the default behavior if png_set_benign_errors() is not called).
1644     */
1645 
1646    if (allowed != 0)
1647       png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
1648          PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
1649 
1650    else
1651       png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
1652          PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
1653 }
1654 #endif /* BENIGN_ERRORS */
1655 
1656 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
1657    /* Whether to report invalid palette index; added at libng-1.5.10.
1658     * It is possible for an indexed (color-type==3) PNG file to contain
1659     * pixels with invalid (out-of-range) indexes if the PLTE chunk has
1660     * fewer entries than the image's bit-depth would allow. We recover
1661     * from this gracefully by filling any incomplete palette with zeros
1662     * (opaque black).  By default, when this occurs libpng will issue
1663     * a benign error.  This API can be used to override that behavior.
1664     */
1665 void PNGAPI
1666 png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
1667 {
1668    png_debug(1, "in png_set_check_for_invalid_index");
1669 
1670    if (allowed > 0)
1671       png_ptr->num_palette_max = 0;
1672 
1673    else
1674       png_ptr->num_palette_max = -1;
1675 }
1676 #endif
1677 
1678 #if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \
1679     defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
1680 /* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
1681  * and if invalid, correct the keyword rather than discarding the entire
1682  * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
1683  * length, forbids leading or trailing whitespace, multiple internal spaces,
1684  * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
1685  *
1686  * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
1687  * trailing '\0').  If this routine returns 0 then there was no keyword, or a
1688  * valid one could not be generated, and the caller must png_error.
1689  */
1690 png_uint_32 /* PRIVATE */
1691 png_check_keyword(png_structrp png_ptr, png_const_charp key, png_bytep new_key)
1692 {
1693    png_const_charp orig_key = key;
1694    png_uint_32 key_len = 0;
1695    int bad_character = 0;
1696    int space = 1;
1697 
1698    png_debug(1, "in png_check_keyword");
1699 
1700    if (key == NULL)
1701    {
1702       *new_key = 0;
1703       return 0;
1704    }
1705 
1706    while (*key && key_len < 79)
1707    {
1708       png_byte ch = (png_byte)*key++;
1709 
1710       if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
1711          *new_key++ = ch, ++key_len, space = 0;
1712 
1713       else if (space == 0)
1714       {
1715          /* A space or an invalid character when one wasn't seen immediately
1716           * before; output just a space.
1717           */
1718          *new_key++ = 32, ++key_len, space = 1;
1719 
1720          /* If the character was not a space then it is invalid. */
1721          if (ch != 32)
1722             bad_character = ch;
1723       }
1724 
1725       else if (bad_character == 0)
1726          bad_character = ch; /* just skip it, record the first error */
1727    }
1728 
1729    if (key_len > 0 && space != 0) /* trailing space */
1730    {
1731       --key_len, --new_key;
1732       if (bad_character == 0)
1733          bad_character = 32;
1734    }
1735 
1736    /* Terminate the keyword */
1737    *new_key = 0;
1738 
1739    if (key_len == 0)
1740       return 0;
1741 
1742 #ifdef PNG_WARNINGS_SUPPORTED
1743    /* Try to only output one warning per keyword: */
1744    if (*key != 0) /* keyword too long */
1745       png_warning(png_ptr, "keyword truncated");
1746 
1747    else if (bad_character != 0)
1748    {
1749       PNG_WARNING_PARAMETERS(p)
1750 
1751       png_warning_parameter(p, 1, orig_key);
1752       png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
1753 
1754       png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
1755    }
1756 #endif /* WARNINGS */
1757 
1758    return key_len;
1759 }
1760 #endif /* TEXT || pCAL || iCCP || sPLT */
1761 #endif /* READ || WRITE */
--- EOF ---