"Fossies" - the Fresh Open Source Software Archive

Member "pngcrush-1.8.13/pngset.c" (29 Aug 2017, 51471 Bytes) of package /linux/privat/pngcrush-1.8.13.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "pngset.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 1.8.12_vs_1.8.13.

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