media/libpng/pngset.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

     2 /* pngset.c - storage of image information into info struct
     3  *
     4  * Last changed in libpng 1.6.8 [December 19, 2013]
     5  * Copyright (c) 1998-2013 Glenn Randers-Pehrson
     6  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
     7  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
     8  *
     9  * This code is released under the libpng license.
    10  * For conditions of distribution and use, see the disclaimer
    11  * and license in png.h
    12  *
    13  * The functions here are used during reads to store data from the file
    14  * into the info struct, and during writes to store application data
    15  * into the info struct for writing into the file.  This abstracts the
    16  * info struct and allows us to change the structure in the future.
    17  */
    19 #include "pngpriv.h"
    21 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
    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");
    30    if (png_ptr == NULL || info_ptr == NULL || background == NULL)
    31       return;
    33    info_ptr->background = *background;
    34    info_ptr->valid |= PNG_INFO_bKGD;
    35 }
    36 #endif
    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;
    47    png_debug1(1, "in %s storage function", "cHRM fixed");
    49    if (png_ptr == NULL || info_ptr == NULL)
    50       return;
    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;
    61    if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,
    62       2/* override with app values*/))
    63       info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
    65    png_colorspace_sync_info(png_ptr, info_ptr);
    66 }
    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;
    78    png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
    80    if (png_ptr == NULL || info_ptr == NULL)
    81       return;
    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;
    93    if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2))
    94       info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
    96    png_colorspace_sync_info(png_ptr, info_ptr);
    97 }
    99 #  ifdef PNG_FLOATING_POINT_SUPPORTED
   100 void PNGAPI
   101 png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
   102     double white_x, double white_y, double red_x, double red_y,
   103     double green_x, double green_y, double blue_x, double blue_y)
   104 {
   105    png_set_cHRM_fixed(png_ptr, info_ptr,
   106       png_fixed(png_ptr, white_x, "cHRM White X"),
   107       png_fixed(png_ptr, white_y, "cHRM White Y"),
   108       png_fixed(png_ptr, red_x, "cHRM Red X"),
   109       png_fixed(png_ptr, red_y, "cHRM Red Y"),
   110       png_fixed(png_ptr, green_x, "cHRM Green X"),
   111       png_fixed(png_ptr, green_y, "cHRM Green Y"),
   112       png_fixed(png_ptr, blue_x, "cHRM Blue X"),
   113       png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
   114 }
   116 void PNGAPI
   117 png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
   118     double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
   119     double blue_X, double blue_Y, double blue_Z)
   120 {
   121    png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
   122       png_fixed(png_ptr, red_X, "cHRM Red X"),
   123       png_fixed(png_ptr, red_Y, "cHRM Red Y"),
   124       png_fixed(png_ptr, red_Z, "cHRM Red Z"),
   125       png_fixed(png_ptr, green_X, "cHRM Red X"),
   126       png_fixed(png_ptr, green_Y, "cHRM Red Y"),
   127       png_fixed(png_ptr, green_Z, "cHRM Red Z"),
   128       png_fixed(png_ptr, blue_X, "cHRM Red X"),
   129       png_fixed(png_ptr, blue_Y, "cHRM Red Y"),
   130       png_fixed(png_ptr, blue_Z, "cHRM Red Z"));
   131 }
   132 #  endif /* PNG_FLOATING_POINT_SUPPORTED */
   134 #endif /* PNG_cHRM_SUPPORTED */
   136 #ifdef PNG_gAMA_SUPPORTED
   137 void PNGFAPI
   138 png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
   139     png_fixed_point file_gamma)
   140 {
   141    png_debug1(1, "in %s storage function", "gAMA");
   143    if (png_ptr == NULL || info_ptr == NULL)
   144       return;
   146    png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
   147    png_colorspace_sync_info(png_ptr, info_ptr);
   148 }
   150 #  ifdef PNG_FLOATING_POINT_SUPPORTED
   151 void PNGAPI
   152 png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)
   153 {
   154    png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
   155        "png_set_gAMA"));
   156 }
   157 #  endif
   158 #endif
   160 #ifdef PNG_hIST_SUPPORTED
   161 void PNGAPI
   162 png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
   163     png_const_uint_16p hist)
   164 {
   165    int i;
   167    png_debug1(1, "in %s storage function", "hIST");
   169    if (png_ptr == NULL || info_ptr == NULL)
   170       return;
   172    if (info_ptr->num_palette == 0 || info_ptr->num_palette
   173        > PNG_MAX_PALETTE_LENGTH)
   174    {
   175       png_warning(png_ptr,
   176           "Invalid palette size, hIST allocation skipped");
   178       return;
   179    }
   181    png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
   183    /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
   184     * version 1.2.1
   185     */
   186    info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
   187        PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
   189    if (info_ptr->hist == NULL)
   190    {
   191       png_warning(png_ptr, "Insufficient memory for hIST chunk data");
   192       return;
   193    }
   195    info_ptr->free_me |= PNG_FREE_HIST;
   197    for (i = 0; i < info_ptr->num_palette; i++)
   198       info_ptr->hist[i] = hist[i];
   200    info_ptr->valid |= PNG_INFO_hIST;
   201 }
   202 #endif
   204 void PNGAPI
   205 png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
   206     png_uint_32 width, png_uint_32 height, int bit_depth,
   207     int color_type, int interlace_type, int compression_type,
   208     int filter_type)
   209 {
   210    png_debug1(1, "in %s storage function", "IHDR");
   212    if (png_ptr == NULL || info_ptr == NULL)
   213       return;
   215    info_ptr->width = width;
   216    info_ptr->height = height;
   217    info_ptr->bit_depth = (png_byte)bit_depth;
   218    info_ptr->color_type = (png_byte)color_type;
   219    info_ptr->compression_type = (png_byte)compression_type;
   220    info_ptr->filter_type = (png_byte)filter_type;
   221    info_ptr->interlace_type = (png_byte)interlace_type;
   223    png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
   224        info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
   225        info_ptr->compression_type, info_ptr->filter_type);
   227    if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   228       info_ptr->channels = 1;
   230    else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
   231       info_ptr->channels = 3;
   233    else
   234       info_ptr->channels = 1;
   236    if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
   237       info_ptr->channels++;
   239    info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
   241    info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
   243 #ifdef PNG_APNG_SUPPORTED
   244    /* for non-animated png. this may be overwritten from an acTL chunk later */
   245    info_ptr->num_frames = 1;
   246 #endif
   247 }
   249 #ifdef PNG_oFFs_SUPPORTED
   250 void PNGAPI
   251 png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,
   252     png_int_32 offset_x, png_int_32 offset_y, int unit_type)
   253 {
   254    png_debug1(1, "in %s storage function", "oFFs");
   256    if (png_ptr == NULL || info_ptr == NULL)
   257       return;
   259    info_ptr->x_offset = offset_x;
   260    info_ptr->y_offset = offset_y;
   261    info_ptr->offset_unit_type = (png_byte)unit_type;
   262    info_ptr->valid |= PNG_INFO_oFFs;
   263 }
   264 #endif
   266 #ifdef PNG_pCAL_SUPPORTED
   267 void PNGAPI
   268 png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
   269     png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
   270     int nparams, png_const_charp units, png_charpp params)
   271 {
   272    png_size_t length;
   273    int i;
   275    png_debug1(1, "in %s storage function", "pCAL");
   277    if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
   278       || (nparams > 0 && params == NULL))
   279       return;
   281    length = strlen(purpose) + 1;
   282    png_debug1(3, "allocating purpose for info (%lu bytes)",
   283        (unsigned long)length);
   285    /* TODO: validate format of calibration name and unit name */
   287    /* Check that the type matches the specification. */
   288    if (type < 0 || type > 3)
   289       png_error(png_ptr, "Invalid pCAL equation type");
   291    if (nparams < 0 || nparams > 255)
   292       png_error(png_ptr, "Invalid pCAL parameter count");
   294    /* Validate params[nparams] */
   295    for (i=0; i<nparams; ++i)
   296       if (params[i] == NULL ||
   297          !png_check_fp_string(params[i], strlen(params[i])))
   298          png_error(png_ptr, "Invalid format for pCAL parameter");
   300    info_ptr->pcal_purpose = png_voidcast(png_charp,
   301       png_malloc_warn(png_ptr, length));
   303    if (info_ptr->pcal_purpose == NULL)
   304    {
   305       png_warning(png_ptr, "Insufficient memory for pCAL purpose");
   306       return;
   307    }
   309    memcpy(info_ptr->pcal_purpose, purpose, length);
   311    png_debug(3, "storing X0, X1, type, and nparams in info");
   312    info_ptr->pcal_X0 = X0;
   313    info_ptr->pcal_X1 = X1;
   314    info_ptr->pcal_type = (png_byte)type;
   315    info_ptr->pcal_nparams = (png_byte)nparams;
   317    length = strlen(units) + 1;
   318    png_debug1(3, "allocating units for info (%lu bytes)",
   319      (unsigned long)length);
   321    info_ptr->pcal_units = png_voidcast(png_charp,
   322       png_malloc_warn(png_ptr, length));
   324    if (info_ptr->pcal_units == NULL)
   325    {
   326       png_warning(png_ptr, "Insufficient memory for pCAL units");
   327       return;
   328    }
   330    memcpy(info_ptr->pcal_units, units, length);
   332    info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
   333        (png_size_t)((nparams + 1) * (sizeof (png_charp)))));
   335    if (info_ptr->pcal_params == NULL)
   336    {
   337       png_warning(png_ptr, "Insufficient memory for pCAL params");
   338       return;
   339    }
   341    memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp)));
   343    for (i = 0; i < nparams; i++)
   344    {
   345       length = strlen(params[i]) + 1;
   346       png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
   347           (unsigned long)length);
   349       info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
   351       if (info_ptr->pcal_params[i] == NULL)
   352       {
   353          png_warning(png_ptr, "Insufficient memory for pCAL parameter");
   354          return;
   355       }
   357       memcpy(info_ptr->pcal_params[i], params[i], length);
   358    }
   360    info_ptr->valid |= PNG_INFO_pCAL;
   361    info_ptr->free_me |= PNG_FREE_PCAL;
   362 }
   363 #endif
   365 #ifdef PNG_sCAL_SUPPORTED
   366 void PNGAPI
   367 png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
   368     int unit, png_const_charp swidth, png_const_charp sheight)
   369 {
   370    png_size_t lengthw = 0, lengthh = 0;
   372    png_debug1(1, "in %s storage function", "sCAL");
   374    if (png_ptr == NULL || info_ptr == NULL)
   375       return;
   377    /* Double check the unit (should never get here with an invalid
   378     * unit unless this is an API call.)
   379     */
   380    if (unit != 1 && unit != 2)
   381       png_error(png_ptr, "Invalid sCAL unit");
   383    if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||
   384        swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
   385       png_error(png_ptr, "Invalid sCAL width");
   387    if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||
   388        sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
   389       png_error(png_ptr, "Invalid sCAL height");
   391    info_ptr->scal_unit = (png_byte)unit;
   393    ++lengthw;
   395    png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);
   397    info_ptr->scal_s_width = png_voidcast(png_charp,
   398       png_malloc_warn(png_ptr, lengthw));
   400    if (info_ptr->scal_s_width == NULL)
   401    {
   402       png_warning(png_ptr, "Memory allocation failed while processing sCAL");
   403       return;
   404    }
   406    memcpy(info_ptr->scal_s_width, swidth, lengthw);
   408    ++lengthh;
   410    png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);
   412    info_ptr->scal_s_height = png_voidcast(png_charp,
   413       png_malloc_warn(png_ptr, lengthh));
   415    if (info_ptr->scal_s_height == NULL)
   416    {
   417       png_free (png_ptr, info_ptr->scal_s_width);
   418       info_ptr->scal_s_width = NULL;
   420       png_warning(png_ptr, "Memory allocation failed while processing sCAL");
   421       return;
   422    }
   424    memcpy(info_ptr->scal_s_height, sheight, lengthh);
   426    info_ptr->valid |= PNG_INFO_sCAL;
   427    info_ptr->free_me |= PNG_FREE_SCAL;
   428 }
   430 #  ifdef PNG_FLOATING_POINT_SUPPORTED
   431 void PNGAPI
   432 png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
   433     double width, double height)
   434 {
   435    png_debug1(1, "in %s storage function", "sCAL");
   437    /* Check the arguments. */
   438    if (width <= 0)
   439       png_warning(png_ptr, "Invalid sCAL width ignored");
   441    else if (height <= 0)
   442       png_warning(png_ptr, "Invalid sCAL height ignored");
   444    else
   445    {
   446       /* Convert 'width' and 'height' to ASCII. */
   447       char swidth[PNG_sCAL_MAX_DIGITS+1];
   448       char sheight[PNG_sCAL_MAX_DIGITS+1];
   450       png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
   451          PNG_sCAL_PRECISION);
   452       png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
   453          PNG_sCAL_PRECISION);
   455       png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   456    }
   457 }
   458 #  endif
   460 #  ifdef PNG_FIXED_POINT_SUPPORTED
   461 void PNGAPI
   462 png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
   463     png_fixed_point width, png_fixed_point height)
   464 {
   465    png_debug1(1, "in %s storage function", "sCAL");
   467    /* Check the arguments. */
   468    if (width <= 0)
   469       png_warning(png_ptr, "Invalid sCAL width ignored");
   471    else if (height <= 0)
   472       png_warning(png_ptr, "Invalid sCAL height ignored");
   474    else
   475    {
   476       /* Convert 'width' and 'height' to ASCII. */
   477       char swidth[PNG_sCAL_MAX_DIGITS+1];
   478       char sheight[PNG_sCAL_MAX_DIGITS+1];
   480       png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
   481       png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
   483       png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   484    }
   485 }
   486 #  endif
   487 #endif
   489 #ifdef PNG_pHYs_SUPPORTED
   490 void PNGAPI
   491 png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,
   492     png_uint_32 res_x, png_uint_32 res_y, int unit_type)
   493 {
   494    png_debug1(1, "in %s storage function", "pHYs");
   496    if (png_ptr == NULL || info_ptr == NULL)
   497       return;
   499    info_ptr->x_pixels_per_unit = res_x;
   500    info_ptr->y_pixels_per_unit = res_y;
   501    info_ptr->phys_unit_type = (png_byte)unit_type;
   502    info_ptr->valid |= PNG_INFO_pHYs;
   503 }
   504 #endif
   506 void PNGAPI
   507 png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
   508     png_const_colorp palette, int num_palette)
   509 {
   511    png_debug1(1, "in %s storage function", "PLTE");
   513    if (png_ptr == NULL || info_ptr == NULL)
   514       return;
   516    if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
   517    {
   518       if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   519          png_error(png_ptr, "Invalid palette length");
   521       else
   522       {
   523          png_warning(png_ptr, "Invalid palette length");
   524          return;
   525       }
   526    }
   528    if ((num_palette > 0 && palette == NULL) ||
   529       (num_palette == 0
   530 #        ifdef PNG_MNG_FEATURES_SUPPORTED
   531             && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
   532 #        endif
   533       ))
   534    {
   535       png_error(png_ptr, "Invalid palette");
   536       return;
   537    }
   539    /* It may not actually be necessary to set png_ptr->palette here;
   540     * we do it for backward compatibility with the way the png_handle_tRNS
   541     * function used to do the allocation.
   542     *
   543     * 1.6.0: the above statement appears to be incorrect; something has to set
   544     * the palette inside png_struct on read.
   545     */
   546    png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
   548    /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
   549     * of num_palette entries, in case of an invalid PNG file that has
   550     * too-large sample values.
   551     */
   552    png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
   553        PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
   555    if (num_palette > 0)
   556       memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));
   557    info_ptr->palette = png_ptr->palette;
   558    info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
   560    info_ptr->free_me |= PNG_FREE_PLTE;
   562    info_ptr->valid |= PNG_INFO_PLTE;
   563 }
   565 #ifdef PNG_sBIT_SUPPORTED
   566 void PNGAPI
   567 png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
   568     png_const_color_8p sig_bit)
   569 {
   570    png_debug1(1, "in %s storage function", "sBIT");
   572    if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
   573       return;
   575    info_ptr->sig_bit = *sig_bit;
   576    info_ptr->valid |= PNG_INFO_sBIT;
   577 }
   578 #endif
   580 #ifdef PNG_sRGB_SUPPORTED
   581 void PNGAPI
   582 png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
   583 {
   584    png_debug1(1, "in %s storage function", "sRGB");
   586    if (png_ptr == NULL || info_ptr == NULL)
   587       return;
   589    (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
   590    png_colorspace_sync_info(png_ptr, info_ptr);
   591 }
   593 void PNGAPI
   594 png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
   595     int srgb_intent)
   596 {
   597    png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
   599    if (png_ptr == NULL || info_ptr == NULL)
   600       return;
   602    if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent))
   603    {
   604       /* This causes the gAMA and cHRM to be written too */
   605       info_ptr->colorspace.flags |=
   606          PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   607    }
   609    png_colorspace_sync_info(png_ptr, info_ptr);
   610 }
   611 #endif /* sRGB */
   614 #ifdef PNG_iCCP_SUPPORTED
   615 void PNGAPI
   616 png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
   617     png_const_charp name, int compression_type,
   618     png_const_bytep profile, png_uint_32 proflen)
   619 {
   620    png_charp new_iccp_name;
   621    png_bytep new_iccp_profile;
   622    png_size_t length;
   624    png_debug1(1, "in %s storage function", "iCCP");
   626    if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
   627       return;
   629    if (compression_type != PNG_COMPRESSION_TYPE_BASE)
   630       png_app_error(png_ptr, "Invalid iCCP compression method");
   632    /* Set the colorspace first because this validates the profile; do not
   633     * override previously set app cHRM or gAMA here (because likely as not the
   634     * application knows better than libpng what the correct values are.)  Pass
   635     * the info_ptr color_type field to png_colorspace_set_ICC because in the
   636     * write case it has not yet been stored in png_ptr.
   637     */
   638    {
   639       int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
   640          proflen, profile, info_ptr->color_type);
   642       png_colorspace_sync_info(png_ptr, info_ptr);
   644       /* Don't do any of the copying if the profile was bad, or inconsistent. */
   645       if (!result)
   646          return;
   648       /* But do write the gAMA and cHRM chunks from the profile. */
   649       info_ptr->colorspace.flags |=
   650          PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   651    }
   653    length = strlen(name)+1;
   654    new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
   656    if (new_iccp_name == NULL)
   657    {
   658       png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
   659       return;
   660    }
   662    memcpy(new_iccp_name, name, length);
   663    new_iccp_profile = png_voidcast(png_bytep,
   664       png_malloc_warn(png_ptr, proflen));
   666    if (new_iccp_profile == NULL)
   667    {
   668       png_free(png_ptr, new_iccp_name);
   669       png_benign_error(png_ptr,
   670           "Insufficient memory to process iCCP profile");
   671       return;
   672    }
   674    memcpy(new_iccp_profile, profile, proflen);
   676    png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
   678    info_ptr->iccp_proflen = proflen;
   679    info_ptr->iccp_name = new_iccp_name;
   680    info_ptr->iccp_profile = new_iccp_profile;
   681    info_ptr->free_me |= PNG_FREE_ICCP;
   682    info_ptr->valid |= PNG_INFO_iCCP;
   683 }
   684 #endif
   686 #ifdef PNG_TEXT_SUPPORTED
   687 void PNGAPI
   688 png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,
   689     png_const_textp text_ptr, int num_text)
   690 {
   691    int ret;
   692    ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
   694    if (ret)
   695       png_error(png_ptr, "Insufficient memory to store text");
   696 }
   698 int /* PRIVATE */
   699 png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
   700     png_const_textp text_ptr, int num_text)
   701 {
   702    int i;
   704    png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" :
   705       (unsigned long)png_ptr->chunk_name);
   707    if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
   708       return(0);
   710    /* Make sure we have enough space in the "text" array in info_struct
   711     * to hold all of the incoming text_ptr objects.  This compare can't overflow
   712     * because max_text >= num_text (anyway, subtract of two positive integers
   713     * can't overflow in any case.)
   714     */
   715    if (num_text > info_ptr->max_text - info_ptr->num_text)
   716    {
   717       int old_num_text = info_ptr->num_text;
   718       int max_text;
   719       png_textp new_text = NULL;
   721       /* Calculate an appropriate max_text, checking for overflow. */
   722       max_text = old_num_text;
   723       if (num_text <= INT_MAX - max_text)
   724       {
   725          max_text += num_text;
   727          /* Round up to a multiple of 8 */
   728          if (max_text < INT_MAX-8)
   729             max_text = (max_text + 8) & ~0x7;
   731          else
   732             max_text = INT_MAX;
   734          /* Now allocate a new array and copy the old members in, this does all
   735           * the overflow checks.
   736           */
   737          new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,
   738             info_ptr->text, old_num_text, max_text-old_num_text,
   739             sizeof *new_text));
   740       }
   742       if (new_text == NULL)
   743       {
   744          png_chunk_report(png_ptr, "too many text chunks",
   745             PNG_CHUNK_WRITE_ERROR);
   746          return 1;
   747       }
   749       png_free(png_ptr, info_ptr->text);
   751       info_ptr->text = new_text;
   752       info_ptr->free_me |= PNG_FREE_TEXT;
   753       info_ptr->max_text = max_text;
   754       /* num_text is adjusted below as the entries are copied in */
   756       png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
   757    }
   759    for (i = 0; i < num_text; i++)
   760    {
   761       size_t text_length, key_len;
   762       size_t lang_len, lang_key_len;
   763       png_textp textp = &(info_ptr->text[info_ptr->num_text]);
   765       if (text_ptr[i].key == NULL)
   766           continue;
   768       if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
   769           text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
   770       {
   771          png_chunk_report(png_ptr, "text compression mode is out of range",
   772             PNG_CHUNK_WRITE_ERROR);
   773          continue;
   774       }
   776       key_len = strlen(text_ptr[i].key);
   778       if (text_ptr[i].compression <= 0)
   779       {
   780          lang_len = 0;
   781          lang_key_len = 0;
   782       }
   784       else
   785 #  ifdef PNG_iTXt_SUPPORTED
   786       {
   787          /* Set iTXt data */
   789          if (text_ptr[i].lang != NULL)
   790             lang_len = strlen(text_ptr[i].lang);
   792          else
   793             lang_len = 0;
   795          if (text_ptr[i].lang_key != NULL)
   796             lang_key_len = strlen(text_ptr[i].lang_key);
   798          else
   799             lang_key_len = 0;
   800       }
   801 #  else /* PNG_iTXt_SUPPORTED */
   802       {
   803          png_chunk_report(png_ptr, "iTXt chunk not supported",
   804             PNG_CHUNK_WRITE_ERROR);
   805          continue;
   806       }
   807 #  endif
   809       if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
   810       {
   811          text_length = 0;
   812 #  ifdef PNG_iTXt_SUPPORTED
   813          if (text_ptr[i].compression > 0)
   814             textp->compression = PNG_ITXT_COMPRESSION_NONE;
   816          else
   817 #  endif
   818             textp->compression = PNG_TEXT_COMPRESSION_NONE;
   819       }
   821       else
   822       {
   823          text_length = strlen(text_ptr[i].text);
   824          textp->compression = text_ptr[i].compression;
   825       }
   827       textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,
   828           key_len + text_length + lang_len + lang_key_len + 4));
   830       if (textp->key == NULL)
   831       {
   832          png_chunk_report(png_ptr, "text chunk: out of memory",
   833                PNG_CHUNK_WRITE_ERROR);
   834          return 1;
   835       }
   837       png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
   838           (unsigned long)(png_uint_32)
   839           (key_len + lang_len + lang_key_len + text_length + 4),
   840           textp->key);
   842       memcpy(textp->key, text_ptr[i].key, key_len);
   843       *(textp->key + key_len) = '\0';
   845       if (text_ptr[i].compression > 0)
   846       {
   847          textp->lang = textp->key + key_len + 1;
   848          memcpy(textp->lang, text_ptr[i].lang, lang_len);
   849          *(textp->lang + lang_len) = '\0';
   850          textp->lang_key = textp->lang + lang_len + 1;
   851          memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
   852          *(textp->lang_key + lang_key_len) = '\0';
   853          textp->text = textp->lang_key + lang_key_len + 1;
   854       }
   856       else
   857       {
   858          textp->lang=NULL;
   859          textp->lang_key=NULL;
   860          textp->text = textp->key + key_len + 1;
   861       }
   863       if (text_length)
   864          memcpy(textp->text, text_ptr[i].text, text_length);
   866       *(textp->text + text_length) = '\0';
   868 #  ifdef PNG_iTXt_SUPPORTED
   869       if (textp->compression > 0)
   870       {
   871          textp->text_length = 0;
   872          textp->itxt_length = text_length;
   873       }
   875       else
   876 #  endif
   877       {
   878          textp->text_length = text_length;
   879          textp->itxt_length = 0;
   880       }
   882       info_ptr->num_text++;
   883       png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
   884    }
   886    return(0);
   887 }
   888 #endif
   890 #ifdef PNG_tIME_SUPPORTED
   891 void PNGAPI
   892 png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
   893     png_const_timep mod_time)
   894 {
   895    png_debug1(1, "in %s storage function", "tIME");
   897    if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
   898        (png_ptr->mode & PNG_WROTE_tIME))
   899       return;
   901    if (mod_time->month == 0   || mod_time->month > 12  ||
   902        mod_time->day   == 0   || mod_time->day   > 31  ||
   903        mod_time->hour  > 23   || mod_time->minute > 59 ||
   904        mod_time->second > 60)
   905    {
   906       png_warning(png_ptr, "Ignoring invalid time value");
   907       return;
   908    }
   910    info_ptr->mod_time = *mod_time;
   911    info_ptr->valid |= PNG_INFO_tIME;
   912 }
   913 #endif
   915 #ifdef PNG_tRNS_SUPPORTED
   916 void PNGAPI
   917 png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
   918     png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
   919 {
   920    png_debug1(1, "in %s storage function", "tRNS");
   922    if (png_ptr == NULL || info_ptr == NULL)
   923       return;
   925    if (trans_alpha != NULL)
   926    {
   927        /* It may not actually be necessary to set png_ptr->trans_alpha here;
   928         * we do it for backward compatibility with the way the png_handle_tRNS
   929         * function used to do the allocation.
   930         *
   931         * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
   932         * relies on png_set_tRNS storing the information in png_struct
   933         * (otherwise it won't be there for the code in pngrtran.c).
   934         */
   936        png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
   938        /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
   939        png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,
   940          png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
   942        if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
   943           memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
   944    }
   946    if (trans_color != NULL)
   947    {
   948       int sample_max = (1 << info_ptr->bit_depth);
   950       if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
   951           trans_color->gray > sample_max) ||
   952           (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
   953           (trans_color->red > sample_max ||
   954           trans_color->green > sample_max ||
   955           trans_color->blue > sample_max)))
   956          png_warning(png_ptr,
   957             "tRNS chunk has out-of-range samples for bit_depth");
   959       info_ptr->trans_color = *trans_color;
   961       if (num_trans == 0)
   962          num_trans = 1;
   963    }
   965    info_ptr->num_trans = (png_uint_16)num_trans;
   967    if (num_trans != 0)
   968    {
   969       info_ptr->valid |= PNG_INFO_tRNS;
   970       info_ptr->free_me |= PNG_FREE_TRNS;
   971    }
   972 }
   973 #endif
   975 #ifdef PNG_sPLT_SUPPORTED
   976 void PNGAPI
   977 png_set_sPLT(png_const_structrp png_ptr,
   978     png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
   979 /*
   980  *  entries        - array of png_sPLT_t structures
   981  *                   to be added to the list of palettes
   982  *                   in the info structure.
   983  *
   984  *  nentries       - number of palette structures to be
   985  *                   added.
   986  */
   987 {
   988    png_sPLT_tp np;
   990    if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
   991       return;
   993    /* Use the internal realloc function, which checks for all the possible
   994     * overflows.  Notice that the parameters are (int) and (size_t)
   995     */
   996    np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
   997       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
   998       sizeof *np));
  1000    if (np == NULL)
  1002       /* Out of memory or too many chunks */
  1003       png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
  1004       return;
  1007    png_free(png_ptr, info_ptr->splt_palettes);
  1008    info_ptr->splt_palettes = np;
  1009    info_ptr->free_me |= PNG_FREE_SPLT;
  1011    np += info_ptr->splt_palettes_num;
  1013    do
  1015       png_size_t length;
  1017       /* Skip invalid input entries */
  1018       if (entries->name == NULL || entries->entries == NULL)
  1020          /* png_handle_sPLT doesn't do this, so this is an app error */
  1021          png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
  1022          /* Just skip the invalid entry */
  1023          continue;
  1026       np->depth = entries->depth;
  1028       /* In the even of out-of-memory just return - there's no point keeping on
  1029        * trying to add sPLT chunks.
  1030        */
  1031       length = strlen(entries->name) + 1;
  1032       np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));
  1034       if (np->name == NULL)
  1035          break;
  1037       memcpy(np->name, entries->name, length);
  1039       /* IMPORTANT: we have memory now that won't get freed if something else
  1040        * goes wrong, this code must free it.  png_malloc_array produces no
  1041        * warnings, use a png_chunk_report (below) if there is an error.
  1042        */
  1043       np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
  1044           entries->nentries, sizeof (png_sPLT_entry)));
  1046       if (np->entries == NULL)
  1048          png_free(png_ptr, np->name);
  1049          break;
  1052       np->nentries = entries->nentries;
  1053       /* This multiply can't overflow because png_malloc_array has already
  1054        * checked it when doing the allocation.
  1055        */
  1056       memcpy(np->entries, entries->entries,
  1057          entries->nentries * sizeof (png_sPLT_entry));
  1059       /* Note that 'continue' skips the advance of the out pointer and out
  1060        * count, so an invalid entry is not added.
  1061        */
  1062       info_ptr->valid |= PNG_INFO_sPLT;
  1063       ++(info_ptr->splt_palettes_num);
  1064       ++np;
  1066    while (++entries, --nentries);
  1068    if (nentries > 0)
  1069       png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
  1071 #endif /* PNG_sPLT_SUPPORTED */
  1073 #ifdef PNG_APNG_SUPPORTED
  1074 png_uint_32 PNGAPI
  1075 png_set_acTL(png_structp png_ptr, png_infop info_ptr,
  1076     png_uint_32 num_frames, png_uint_32 num_plays)
  1078     png_debug1(1, "in %s storage function", "acTL");
  1080     if (png_ptr == NULL || info_ptr == NULL)
  1082         png_warning(png_ptr,
  1083                     "Call to png_set_acTL() with NULL png_ptr "
  1084                     "or info_ptr ignored");
  1085         return (0);
  1087     if (num_frames == 0)
  1089         png_warning(png_ptr,
  1090                     "Ignoring attempt to set acTL with num_frames zero");
  1091         return (0);
  1093     if (num_frames > PNG_UINT_31_MAX)
  1095         png_warning(png_ptr,
  1096                     "Ignoring attempt to set acTL with num_frames > 2^31-1");
  1097         return (0);
  1099     if (num_plays > PNG_UINT_31_MAX)
  1101         png_warning(png_ptr,
  1102                     "Ignoring attempt to set acTL with num_plays "
  1103                     "> 2^31-1");
  1104         return (0);
  1107     info_ptr->num_frames = num_frames;
  1108     info_ptr->num_plays = num_plays;
  1110     info_ptr->valid |= PNG_INFO_acTL;
  1112     return (1);
  1115 /* delay_num and delay_den can hold any 16-bit values including zero */
  1116 png_uint_32 PNGAPI
  1117 png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
  1118     png_uint_32 width, png_uint_32 height,
  1119     png_uint_32 x_offset, png_uint_32 y_offset,
  1120     png_uint_16 delay_num, png_uint_16 delay_den,
  1121     png_byte dispose_op, png_byte blend_op)
  1123     png_debug1(1, "in %s storage function", "fcTL");
  1125     if (png_ptr == NULL || info_ptr == NULL)
  1127         png_warning(png_ptr,
  1128                     "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
  1129                     "ignored");
  1130         return (0);
  1133     png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
  1134                              delay_num, delay_den, dispose_op, blend_op);
  1136     if (blend_op == PNG_BLEND_OP_OVER)
  1138         if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
  1139             !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
  1141           png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
  1142                                "and wasteful for opaque images, ignored");
  1143           blend_op = PNG_BLEND_OP_SOURCE;
  1147     info_ptr->next_frame_width = width;
  1148     info_ptr->next_frame_height = height;
  1149     info_ptr->next_frame_x_offset = x_offset;
  1150     info_ptr->next_frame_y_offset = y_offset;
  1151     info_ptr->next_frame_delay_num = delay_num;
  1152     info_ptr->next_frame_delay_den = delay_den;
  1153     info_ptr->next_frame_dispose_op = dispose_op;
  1154     info_ptr->next_frame_blend_op = blend_op;
  1156     info_ptr->valid |= PNG_INFO_fcTL;
  1158     return (1);
  1161 void /* PRIVATE */
  1162 png_ensure_fcTL_is_valid(png_structp png_ptr,
  1163     png_uint_32 width, png_uint_32 height,
  1164     png_uint_32 x_offset, png_uint_32 y_offset,
  1165     png_uint_16 delay_num, png_uint_16 delay_den,
  1166     png_byte dispose_op, png_byte blend_op)
  1168     if (width > PNG_UINT_31_MAX)
  1169         png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
  1170     if (height > PNG_UINT_31_MAX)
  1171         png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
  1172     if (x_offset > PNG_UINT_31_MAX)
  1173         png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
  1174     if (y_offset > PNG_UINT_31_MAX)
  1175         png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
  1176     if (width + x_offset > png_ptr->first_frame_width ||
  1177         height + y_offset > png_ptr->first_frame_height)
  1178         png_error(png_ptr, "dimensions of a frame are greater than"
  1179                            "the ones in IHDR");
  1181     if (dispose_op != PNG_DISPOSE_OP_NONE &&
  1182         dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
  1183         dispose_op != PNG_DISPOSE_OP_PREVIOUS)
  1184         png_error(png_ptr, "invalid dispose_op in fcTL");
  1186     if (blend_op != PNG_BLEND_OP_SOURCE &&
  1187         blend_op != PNG_BLEND_OP_OVER)
  1188         png_error(png_ptr, "invalid blend_op in fcTL");
  1190     PNG_UNUSED(delay_num)
  1191     PNG_UNUSED(delay_den)
  1194 png_uint_32 PNGAPI
  1195 png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
  1196                               png_byte is_hidden)
  1198     png_debug(1, "in png_first_frame_is_hidden()");
  1200     if (png_ptr == NULL)
  1201         return 0;
  1203     if (is_hidden)
  1204         png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
  1205     else
  1206         png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
  1208     PNG_UNUSED(info_ptr)
  1210     return 1;
  1212 #endif /* PNG_APNG_SUPPORTED */
  1214 #ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
  1215 static png_byte
  1216 check_location(png_const_structrp png_ptr, int location)
  1218    location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
  1220    /* New in 1.6.0; copy the location and check it.  This is an API
  1221     * change, previously the app had to use the
  1222     * png_set_unknown_chunk_location API below for each chunk.
  1223     */
  1224    if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT))
  1226       /* Write struct, so unknown chunks come from the app */
  1227       png_app_warning(png_ptr,
  1228          "png_set_unknown_chunks now expects a valid location");
  1229       /* Use the old behavior */
  1230       location = (png_byte)(png_ptr->mode &
  1231          (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
  1234    /* This need not be an internal error - if the app calls
  1235     * png_set_unknown_chunks on a read pointer it must get the location right.
  1236     */
  1237    if (location == 0)
  1238       png_error(png_ptr, "invalid location in png_set_unknown_chunks");
  1240    /* Now reduce the location to the top-most set bit by removing each least
  1241     * significant bit in turn.
  1242     */
  1243    while (location != (location & -location))
  1244       location &= ~(location & -location);
  1246    /* The cast is safe because 'location' is a bit mask and only the low four
  1247     * bits are significant.
  1248     */
  1249    return (png_byte)location;
  1252 void PNGAPI
  1253 png_set_unknown_chunks(png_const_structrp png_ptr,
  1254    png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
  1256    png_unknown_chunkp np;
  1258    if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
  1259       unknowns == NULL)
  1260       return;
  1262    /* Check for the failure cases where support has been disabled at compile
  1263     * time.  This code is hardly ever compiled - it's here because
  1264     * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
  1265     * code) but may be meaningless if the read or write handling of unknown
  1266     * chunks is not compiled in.
  1267     */
  1268 #  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
  1269       defined(PNG_READ_SUPPORTED)
  1270       if (png_ptr->mode & PNG_IS_READ_STRUCT)
  1272          png_app_error(png_ptr, "no unknown chunk support on read");
  1273          return;
  1275 #  endif
  1276 #  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
  1277       defined(PNG_WRITE_SUPPORTED)
  1278       if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
  1280          png_app_error(png_ptr, "no unknown chunk support on write");
  1281          return;
  1283 #  endif
  1285    /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
  1286     * unknown critical chunks could be lost with just a warning resulting in
  1287     * undefined behavior.  Now png_chunk_report is used to provide behavior
  1288     * appropriate to read or write.
  1289     */
  1290    np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
  1291          info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
  1292          sizeof *np));
  1294    if (np == NULL)
  1296       png_chunk_report(png_ptr, "too many unknown chunks",
  1297          PNG_CHUNK_WRITE_ERROR);
  1298       return;
  1301    png_free(png_ptr, info_ptr->unknown_chunks);
  1302    info_ptr->unknown_chunks = np; /* safe because it is initialized */
  1303    info_ptr->free_me |= PNG_FREE_UNKN;
  1305    np += info_ptr->unknown_chunks_num;
  1307    /* Increment unknown_chunks_num each time round the loop to protect the
  1308     * just-allocated chunk data.
  1309     */
  1310    for (; num_unknowns > 0; --num_unknowns, ++unknowns)
  1312       memcpy(np->name, unknowns->name, (sizeof np->name));
  1313       np->name[(sizeof np->name)-1] = '\0';
  1314       np->location = check_location(png_ptr, unknowns->location);
  1316       if (unknowns->size == 0)
  1318          np->data = NULL;
  1319          np->size = 0;
  1322       else
  1324          np->data = png_voidcast(png_bytep,
  1325             png_malloc_base(png_ptr, unknowns->size));
  1327          if (np->data == NULL)
  1329             png_chunk_report(png_ptr, "unknown chunk: out of memory",
  1330                PNG_CHUNK_WRITE_ERROR);
  1331             /* But just skip storing the unknown chunk */
  1332             continue;
  1335          memcpy(np->data, unknowns->data, unknowns->size);
  1336          np->size = unknowns->size;
  1339       /* These increments are skipped on out-of-memory for the data - the
  1340        * unknown chunk entry gets overwritten if the png_chunk_report returns.
  1341        * This is correct in the read case (the chunk is just dropped.)
  1342        */
  1343       ++np;
  1344       ++(info_ptr->unknown_chunks_num);
  1348 void PNGAPI
  1349 png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
  1350     int chunk, int location)
  1352    /* This API is pretty pointless in 1.6.0 because the location can be set
  1353     * before the call to png_set_unknown_chunks.
  1355     * TODO: add a png_app_warning in 1.7
  1356     */
  1357    if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
  1358       chunk < info_ptr->unknown_chunks_num)
  1360       if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
  1362          png_app_error(png_ptr, "invalid unknown chunk location");
  1363          /* Fake out the pre 1.6.0 behavior: */
  1364          if ((location & PNG_HAVE_IDAT)) /* undocumented! */
  1365             location = PNG_AFTER_IDAT;
  1367          else
  1368             location = PNG_HAVE_IHDR; /* also undocumented */
  1371       info_ptr->unknown_chunks[chunk].location =
  1372          check_location(png_ptr, location);
  1375 #endif
  1378 #ifdef PNG_MNG_FEATURES_SUPPORTED
  1379 png_uint_32 PNGAPI
  1380 png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
  1382    png_debug(1, "in png_permit_mng_features");
  1384    if (png_ptr == NULL)
  1385       return 0;
  1387    png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
  1389    return png_ptr->mng_features_permitted;
  1391 #endif
  1393 #ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
  1394 static unsigned int
  1395 add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
  1397    unsigned int i;
  1399    /* Utility function: update the 'keep' state of a chunk if it is already in
  1400     * the list, otherwise add it to the list.
  1401     */
  1402    for (i=0; i<count; ++i, list += 5) if (memcmp(list, add, 4) == 0)
  1404       list[4] = (png_byte)keep;
  1405       return count;
  1408    if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
  1410       ++count;
  1411       memcpy(list, add, 4);
  1412       list[4] = (png_byte)keep;
  1415    return count;
  1418 void PNGAPI
  1419 png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
  1420     png_const_bytep chunk_list, int num_chunks_in)
  1422    png_bytep new_list;
  1423    unsigned int num_chunks, old_num_chunks;
  1425    if (png_ptr == NULL)
  1426       return;
  1428    if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
  1430       png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
  1431       return;
  1434    if (num_chunks_in <= 0)
  1436       png_ptr->unknown_default = keep;
  1438       /* '0' means just set the flags, so stop here */
  1439       if (num_chunks_in == 0)
  1440         return;
  1443    if (num_chunks_in < 0)
  1445       /* Ignore all unknown chunks and all chunks recognized by
  1446        * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
  1447        */
  1448       static PNG_CONST png_byte chunks_to_ignore[] = {
  1449          98,  75,  71,  68, '\0',  /* bKGD */
  1450          99,  72,  82,  77, '\0',  /* cHRM */
  1451         103,  65,  77,  65, '\0',  /* gAMA */
  1452         104,  73,  83,  84, '\0',  /* hIST */
  1453         105,  67,  67,  80, '\0',  /* iCCP */
  1454         105,  84,  88, 116, '\0',  /* iTXt */
  1455         111,  70,  70, 115, '\0',  /* oFFs */
  1456         112,  67,  65,  76, '\0',  /* pCAL */
  1457         112,  72,  89, 115, '\0',  /* pHYs */
  1458         115,  66,  73,  84, '\0',  /* sBIT */
  1459         115,  67,  65,  76, '\0',  /* sCAL */
  1460         115,  80,  76,  84, '\0',  /* sPLT */
  1461         115,  84,  69,  82, '\0',  /* sTER */
  1462         115,  82,  71,  66, '\0',  /* sRGB */
  1463         116,  69,  88, 116, '\0',  /* tEXt */
  1464         116,  73,  77,  69, '\0',  /* tIME */
  1465         122,  84,  88, 116, '\0'   /* zTXt */
  1466       };
  1468       chunk_list = chunks_to_ignore;
  1469       num_chunks = (sizeof chunks_to_ignore)/5;
  1472    else /* num_chunks_in > 0 */
  1474       if (chunk_list == NULL)
  1476          /* Prior to 1.6.0 this was silently ignored, now it is an app_error
  1477           * which can be switched off.
  1478           */
  1479          png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
  1480          return;
  1483       num_chunks = num_chunks_in;
  1486    old_num_chunks = png_ptr->num_chunk_list;
  1487    if (png_ptr->chunk_list == NULL)
  1488       old_num_chunks = 0;
  1490    /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
  1491     */
  1492    if (num_chunks + old_num_chunks > UINT_MAX/5)
  1494       png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
  1495       return;
  1498    /* If these chunks are being reset to the default then no more memory is
  1499     * required because add_one_chunk above doesn't extend the list if the 'keep'
  1500     * parameter is the default.
  1501     */
  1502    if (keep)
  1504       new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
  1505           5 * (num_chunks + old_num_chunks)));
  1507       if (old_num_chunks > 0)
  1508          memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
  1511    else if (old_num_chunks > 0)
  1512       new_list = png_ptr->chunk_list;
  1514    else
  1515       new_list = NULL;
  1517    /* Add the new chunks together with each one's handling code.  If the chunk
  1518     * already exists the code is updated, otherwise the chunk is added to the
  1519     * end.  (In libpng 1.6.0 order no longer matters because this code enforces
  1520     * the earlier convention that the last setting is the one that is used.)
  1521     */
  1522    if (new_list != NULL)
  1524       png_const_bytep inlist;
  1525       png_bytep outlist;
  1526       unsigned int i;
  1528       for (i=0; i<num_chunks; ++i)
  1529          old_num_chunks = add_one_chunk(new_list, old_num_chunks,
  1530             chunk_list+5*i, keep);
  1532       /* Now remove any spurious 'default' entries. */
  1533       num_chunks = 0;
  1534       for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
  1535          if (inlist[4])
  1537             if (outlist != inlist)
  1538                memcpy(outlist, inlist, 5);
  1539             outlist += 5;
  1540             ++num_chunks;
  1543       /* This means the application has removed all the specialized handling. */
  1544       if (num_chunks == 0)
  1546          if (png_ptr->chunk_list != new_list)
  1547             png_free(png_ptr, new_list);
  1549          new_list = NULL;
  1553    else
  1554       num_chunks = 0;
  1556    png_ptr->num_chunk_list = num_chunks;
  1558    if (png_ptr->chunk_list != new_list)
  1560       if (png_ptr->chunk_list != NULL)
  1561          png_free(png_ptr, png_ptr->chunk_list);
  1563       png_ptr->chunk_list = new_list;
  1566 #endif
  1568 #ifdef PNG_READ_USER_CHUNKS_SUPPORTED
  1569 void PNGAPI
  1570 png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
  1571     png_user_chunk_ptr read_user_chunk_fn)
  1573    png_debug(1, "in png_set_read_user_chunk_fn");
  1575    if (png_ptr == NULL)
  1576       return;
  1578    png_ptr->read_user_chunk_fn = read_user_chunk_fn;
  1579    png_ptr->user_chunk_ptr = user_chunk_ptr;
  1581 #endif
  1583 #ifdef PNG_INFO_IMAGE_SUPPORTED
  1584 void PNGAPI
  1585 png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
  1586     png_bytepp row_pointers)
  1588    png_debug1(1, "in %s storage function", "rows");
  1590    if (png_ptr == NULL || info_ptr == NULL)
  1591       return;
  1593    if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
  1594       png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
  1596    info_ptr->row_pointers = row_pointers;
  1598    if (row_pointers)
  1599       info_ptr->valid |= PNG_INFO_IDAT;
  1601 #endif
  1603 void PNGAPI
  1604 png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
  1606     if (png_ptr == NULL)
  1607        return;
  1609     if (size == 0 || size > PNG_UINT_31_MAX)
  1610        png_error(png_ptr, "invalid compression buffer size");
  1612 #  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
  1613       if (png_ptr->mode & PNG_IS_READ_STRUCT)
  1615          png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
  1616          return;
  1618 #  endif
  1620 #  ifdef PNG_WRITE_SUPPORTED
  1621       if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
  1623          if (png_ptr->zowner != 0)
  1625             png_warning(png_ptr,
  1626               "Compression buffer size cannot be changed because it is in use");
  1627             return;
  1630          if (size > ZLIB_IO_MAX)
  1632             png_warning(png_ptr,
  1633                "Compression buffer size limited to system maximum");
  1634             size = ZLIB_IO_MAX; /* must fit */
  1637          else if (size < 6)
  1639             /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
  1640              * if this is permitted.
  1641              */
  1642             png_warning(png_ptr,
  1643                "Compression buffer size cannot be reduced below 6");
  1644             return;
  1647          if (png_ptr->zbuffer_size != size)
  1649             png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
  1650             png_ptr->zbuffer_size = (uInt)size;
  1653 #  endif
  1656 void PNGAPI
  1657 png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
  1659    if (png_ptr && info_ptr)
  1660       info_ptr->valid &= ~mask;
  1664 #ifdef PNG_SET_USER_LIMITS_SUPPORTED
  1665 /* This function was added to libpng 1.2.6 */
  1666 void PNGAPI
  1667 png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
  1668     png_uint_32 user_height_max)
  1670    /* Images with dimensions larger than these limits will be
  1671     * rejected by png_set_IHDR().  To accept any PNG datastream
  1672     * regardless of dimensions, set both limits to 0x7ffffffL.
  1673     */
  1674    if (png_ptr == NULL)
  1675       return;
  1677    png_ptr->user_width_max = user_width_max;
  1678    png_ptr->user_height_max = user_height_max;
  1681 /* This function was added to libpng 1.4.0 */
  1682 void PNGAPI
  1683 png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
  1685     if (png_ptr)
  1686        png_ptr->user_chunk_cache_max = user_chunk_cache_max;
  1689 /* This function was added to libpng 1.4.1 */
  1690 void PNGAPI
  1691 png_set_chunk_malloc_max (png_structrp png_ptr,
  1692     png_alloc_size_t user_chunk_malloc_max)
  1694    if (png_ptr)
  1695       png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
  1697 #endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
  1700 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
  1701 void PNGAPI
  1702 png_set_benign_errors(png_structrp png_ptr, int allowed)
  1704    png_debug(1, "in png_set_benign_errors");
  1706    /* If allowed is 1, png_benign_error() is treated as a warning.
  1708     * If allowed is 0, png_benign_error() is treated as an error (which
  1709     * is the default behavior if png_set_benign_errors() is not called).
  1710     */
  1712    if (allowed)
  1713       png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
  1714          PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
  1716    else
  1717       png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
  1718          PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
  1720 #endif /* PNG_BENIGN_ERRORS_SUPPORTED */
  1722 #ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
  1723    /* Whether to report invalid palette index; added at libng-1.5.10.
  1724     * It is possible for an indexed (color-type==3) PNG file to contain
  1725     * pixels with invalid (out-of-range) indexes if the PLTE chunk has
  1726     * fewer entries than the image's bit-depth would allow. We recover
  1727     * from this gracefully by filling any incomplete palette with zeroes
  1728     * (opaque black).  By default, when this occurs libpng will issue
  1729     * a benign error.  This API can be used to override that behavior.
  1730     */
  1731 void PNGAPI
  1732 png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
  1734    png_debug(1, "in png_set_check_for_invalid_index");
  1736    if (allowed > 0)
  1737       png_ptr->num_palette_max = 0;
  1739    else
  1740       png_ptr->num_palette_max = -1;
  1742 #endif
  1743 #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

mercurial