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