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