media/libpng/pngset.c

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/media/libpng/pngset.c	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1743 @@
     1.4 +
     1.5 +/* pngset.c - storage of image information into info struct
     1.6 + *
     1.7 + * Last changed in libpng 1.6.8 [December 19, 2013]
     1.8 + * Copyright (c) 1998-2013 Glenn Randers-Pehrson
     1.9 + * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
    1.10 + * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
    1.11 + *
    1.12 + * This code is released under the libpng license.
    1.13 + * For conditions of distribution and use, see the disclaimer
    1.14 + * and license in png.h
    1.15 + *
    1.16 + * The functions here are used during reads to store data from the file
    1.17 + * into the info struct, and during writes to store application data
    1.18 + * into the info struct for writing into the file.  This abstracts the
    1.19 + * info struct and allows us to change the structure in the future.
    1.20 + */
    1.21 +
    1.22 +#include "pngpriv.h"
    1.23 +
    1.24 +#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
    1.25 +
    1.26 +#ifdef PNG_bKGD_SUPPORTED
    1.27 +void PNGAPI
    1.28 +png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
    1.29 +    png_const_color_16p background)
    1.30 +{
    1.31 +   png_debug1(1, "in %s storage function", "bKGD");
    1.32 +
    1.33 +   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
    1.34 +      return;
    1.35 +
    1.36 +   info_ptr->background = *background;
    1.37 +   info_ptr->valid |= PNG_INFO_bKGD;
    1.38 +}
    1.39 +#endif
    1.40 +
    1.41 +#ifdef PNG_cHRM_SUPPORTED
    1.42 +void PNGFAPI
    1.43 +png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
    1.44 +    png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
    1.45 +    png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
    1.46 +    png_fixed_point blue_x, png_fixed_point blue_y)
    1.47 +{
    1.48 +   png_xy xy;
    1.49 +
    1.50 +   png_debug1(1, "in %s storage function", "cHRM fixed");
    1.51 +
    1.52 +   if (png_ptr == NULL || info_ptr == NULL)
    1.53 +      return;
    1.54 +
    1.55 +   xy.redx = red_x;
    1.56 +   xy.redy = red_y;
    1.57 +   xy.greenx = green_x;
    1.58 +   xy.greeny = green_y;
    1.59 +   xy.bluex = blue_x;
    1.60 +   xy.bluey = blue_y;
    1.61 +   xy.whitex = white_x;
    1.62 +   xy.whitey = white_y;
    1.63 +
    1.64 +   if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,
    1.65 +      2/* override with app values*/))
    1.66 +      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
    1.67 +
    1.68 +   png_colorspace_sync_info(png_ptr, info_ptr);
    1.69 +}
    1.70 +
    1.71 +void PNGFAPI
    1.72 +png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
    1.73 +    png_fixed_point int_red_X, png_fixed_point int_red_Y,
    1.74 +    png_fixed_point int_red_Z, png_fixed_point int_green_X,
    1.75 +    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
    1.76 +    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
    1.77 +    png_fixed_point int_blue_Z)
    1.78 +{
    1.79 +   png_XYZ XYZ;
    1.80 +
    1.81 +   png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
    1.82 +
    1.83 +   if (png_ptr == NULL || info_ptr == NULL)
    1.84 +      return;
    1.85 +
    1.86 +   XYZ.red_X = int_red_X;
    1.87 +   XYZ.red_Y = int_red_Y;
    1.88 +   XYZ.red_Z = int_red_Z;
    1.89 +   XYZ.green_X = int_green_X;
    1.90 +   XYZ.green_Y = int_green_Y;
    1.91 +   XYZ.green_Z = int_green_Z;
    1.92 +   XYZ.blue_X = int_blue_X;
    1.93 +   XYZ.blue_Y = int_blue_Y;
    1.94 +   XYZ.blue_Z = int_blue_Z;
    1.95 +
    1.96 +   if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2))
    1.97 +      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
    1.98 +
    1.99 +   png_colorspace_sync_info(png_ptr, info_ptr);
   1.100 +}
   1.101 +
   1.102 +#  ifdef PNG_FLOATING_POINT_SUPPORTED
   1.103 +void PNGAPI
   1.104 +png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
   1.105 +    double white_x, double white_y, double red_x, double red_y,
   1.106 +    double green_x, double green_y, double blue_x, double blue_y)
   1.107 +{
   1.108 +   png_set_cHRM_fixed(png_ptr, info_ptr,
   1.109 +      png_fixed(png_ptr, white_x, "cHRM White X"),
   1.110 +      png_fixed(png_ptr, white_y, "cHRM White Y"),
   1.111 +      png_fixed(png_ptr, red_x, "cHRM Red X"),
   1.112 +      png_fixed(png_ptr, red_y, "cHRM Red Y"),
   1.113 +      png_fixed(png_ptr, green_x, "cHRM Green X"),
   1.114 +      png_fixed(png_ptr, green_y, "cHRM Green Y"),
   1.115 +      png_fixed(png_ptr, blue_x, "cHRM Blue X"),
   1.116 +      png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
   1.117 +}
   1.118 +
   1.119 +void PNGAPI
   1.120 +png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
   1.121 +    double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
   1.122 +    double blue_X, double blue_Y, double blue_Z)
   1.123 +{
   1.124 +   png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
   1.125 +      png_fixed(png_ptr, red_X, "cHRM Red X"),
   1.126 +      png_fixed(png_ptr, red_Y, "cHRM Red Y"),
   1.127 +      png_fixed(png_ptr, red_Z, "cHRM Red Z"),
   1.128 +      png_fixed(png_ptr, green_X, "cHRM Red X"),
   1.129 +      png_fixed(png_ptr, green_Y, "cHRM Red Y"),
   1.130 +      png_fixed(png_ptr, green_Z, "cHRM Red Z"),
   1.131 +      png_fixed(png_ptr, blue_X, "cHRM Red X"),
   1.132 +      png_fixed(png_ptr, blue_Y, "cHRM Red Y"),
   1.133 +      png_fixed(png_ptr, blue_Z, "cHRM Red Z"));
   1.134 +}
   1.135 +#  endif /* PNG_FLOATING_POINT_SUPPORTED */
   1.136 +
   1.137 +#endif /* PNG_cHRM_SUPPORTED */
   1.138 +
   1.139 +#ifdef PNG_gAMA_SUPPORTED
   1.140 +void PNGFAPI
   1.141 +png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
   1.142 +    png_fixed_point file_gamma)
   1.143 +{
   1.144 +   png_debug1(1, "in %s storage function", "gAMA");
   1.145 +
   1.146 +   if (png_ptr == NULL || info_ptr == NULL)
   1.147 +      return;
   1.148 +
   1.149 +   png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
   1.150 +   png_colorspace_sync_info(png_ptr, info_ptr);
   1.151 +}
   1.152 +
   1.153 +#  ifdef PNG_FLOATING_POINT_SUPPORTED
   1.154 +void PNGAPI
   1.155 +png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)
   1.156 +{
   1.157 +   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
   1.158 +       "png_set_gAMA"));
   1.159 +}
   1.160 +#  endif
   1.161 +#endif
   1.162 +
   1.163 +#ifdef PNG_hIST_SUPPORTED
   1.164 +void PNGAPI
   1.165 +png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
   1.166 +    png_const_uint_16p hist)
   1.167 +{
   1.168 +   int i;
   1.169 +
   1.170 +   png_debug1(1, "in %s storage function", "hIST");
   1.171 +
   1.172 +   if (png_ptr == NULL || info_ptr == NULL)
   1.173 +      return;
   1.174 +
   1.175 +   if (info_ptr->num_palette == 0 || info_ptr->num_palette
   1.176 +       > PNG_MAX_PALETTE_LENGTH)
   1.177 +   {
   1.178 +      png_warning(png_ptr,
   1.179 +          "Invalid palette size, hIST allocation skipped");
   1.180 +
   1.181 +      return;
   1.182 +   }
   1.183 +
   1.184 +   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
   1.185 +
   1.186 +   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
   1.187 +    * version 1.2.1
   1.188 +    */
   1.189 +   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
   1.190 +       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
   1.191 +
   1.192 +   if (info_ptr->hist == NULL)
   1.193 +   {
   1.194 +      png_warning(png_ptr, "Insufficient memory for hIST chunk data");
   1.195 +      return;
   1.196 +   }
   1.197 +
   1.198 +   info_ptr->free_me |= PNG_FREE_HIST;
   1.199 +
   1.200 +   for (i = 0; i < info_ptr->num_palette; i++)
   1.201 +      info_ptr->hist[i] = hist[i];
   1.202 +
   1.203 +   info_ptr->valid |= PNG_INFO_hIST;
   1.204 +}
   1.205 +#endif
   1.206 +
   1.207 +void PNGAPI
   1.208 +png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
   1.209 +    png_uint_32 width, png_uint_32 height, int bit_depth,
   1.210 +    int color_type, int interlace_type, int compression_type,
   1.211 +    int filter_type)
   1.212 +{
   1.213 +   png_debug1(1, "in %s storage function", "IHDR");
   1.214 +
   1.215 +   if (png_ptr == NULL || info_ptr == NULL)
   1.216 +      return;
   1.217 +
   1.218 +   info_ptr->width = width;
   1.219 +   info_ptr->height = height;
   1.220 +   info_ptr->bit_depth = (png_byte)bit_depth;
   1.221 +   info_ptr->color_type = (png_byte)color_type;
   1.222 +   info_ptr->compression_type = (png_byte)compression_type;
   1.223 +   info_ptr->filter_type = (png_byte)filter_type;
   1.224 +   info_ptr->interlace_type = (png_byte)interlace_type;
   1.225 +
   1.226 +   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
   1.227 +       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
   1.228 +       info_ptr->compression_type, info_ptr->filter_type);
   1.229 +
   1.230 +   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   1.231 +      info_ptr->channels = 1;
   1.232 +
   1.233 +   else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
   1.234 +      info_ptr->channels = 3;
   1.235 +
   1.236 +   else
   1.237 +      info_ptr->channels = 1;
   1.238 +
   1.239 +   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
   1.240 +      info_ptr->channels++;
   1.241 +
   1.242 +   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
   1.243 +
   1.244 +   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
   1.245 +
   1.246 +#ifdef PNG_APNG_SUPPORTED
   1.247 +   /* for non-animated png. this may be overwritten from an acTL chunk later */
   1.248 +   info_ptr->num_frames = 1;
   1.249 +#endif
   1.250 +}
   1.251 +
   1.252 +#ifdef PNG_oFFs_SUPPORTED
   1.253 +void PNGAPI
   1.254 +png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,
   1.255 +    png_int_32 offset_x, png_int_32 offset_y, int unit_type)
   1.256 +{
   1.257 +   png_debug1(1, "in %s storage function", "oFFs");
   1.258 +
   1.259 +   if (png_ptr == NULL || info_ptr == NULL)
   1.260 +      return;
   1.261 +
   1.262 +   info_ptr->x_offset = offset_x;
   1.263 +   info_ptr->y_offset = offset_y;
   1.264 +   info_ptr->offset_unit_type = (png_byte)unit_type;
   1.265 +   info_ptr->valid |= PNG_INFO_oFFs;
   1.266 +}
   1.267 +#endif
   1.268 +
   1.269 +#ifdef PNG_pCAL_SUPPORTED
   1.270 +void PNGAPI
   1.271 +png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
   1.272 +    png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
   1.273 +    int nparams, png_const_charp units, png_charpp params)
   1.274 +{
   1.275 +   png_size_t length;
   1.276 +   int i;
   1.277 +
   1.278 +   png_debug1(1, "in %s storage function", "pCAL");
   1.279 +
   1.280 +   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
   1.281 +      || (nparams > 0 && params == NULL))
   1.282 +      return;
   1.283 +
   1.284 +   length = strlen(purpose) + 1;
   1.285 +   png_debug1(3, "allocating purpose for info (%lu bytes)",
   1.286 +       (unsigned long)length);
   1.287 +
   1.288 +   /* TODO: validate format of calibration name and unit name */
   1.289 +
   1.290 +   /* Check that the type matches the specification. */
   1.291 +   if (type < 0 || type > 3)
   1.292 +      png_error(png_ptr, "Invalid pCAL equation type");
   1.293 +
   1.294 +   if (nparams < 0 || nparams > 255)
   1.295 +      png_error(png_ptr, "Invalid pCAL parameter count");
   1.296 +
   1.297 +   /* Validate params[nparams] */
   1.298 +   for (i=0; i<nparams; ++i)
   1.299 +      if (params[i] == NULL ||
   1.300 +         !png_check_fp_string(params[i], strlen(params[i])))
   1.301 +         png_error(png_ptr, "Invalid format for pCAL parameter");
   1.302 +
   1.303 +   info_ptr->pcal_purpose = png_voidcast(png_charp,
   1.304 +      png_malloc_warn(png_ptr, length));
   1.305 +
   1.306 +   if (info_ptr->pcal_purpose == NULL)
   1.307 +   {
   1.308 +      png_warning(png_ptr, "Insufficient memory for pCAL purpose");
   1.309 +      return;
   1.310 +   }
   1.311 +
   1.312 +   memcpy(info_ptr->pcal_purpose, purpose, length);
   1.313 +
   1.314 +   png_debug(3, "storing X0, X1, type, and nparams in info");
   1.315 +   info_ptr->pcal_X0 = X0;
   1.316 +   info_ptr->pcal_X1 = X1;
   1.317 +   info_ptr->pcal_type = (png_byte)type;
   1.318 +   info_ptr->pcal_nparams = (png_byte)nparams;
   1.319 +
   1.320 +   length = strlen(units) + 1;
   1.321 +   png_debug1(3, "allocating units for info (%lu bytes)",
   1.322 +     (unsigned long)length);
   1.323 +
   1.324 +   info_ptr->pcal_units = png_voidcast(png_charp,
   1.325 +      png_malloc_warn(png_ptr, length));
   1.326 +
   1.327 +   if (info_ptr->pcal_units == NULL)
   1.328 +   {
   1.329 +      png_warning(png_ptr, "Insufficient memory for pCAL units");
   1.330 +      return;
   1.331 +   }
   1.332 +
   1.333 +   memcpy(info_ptr->pcal_units, units, length);
   1.334 +
   1.335 +   info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
   1.336 +       (png_size_t)((nparams + 1) * (sizeof (png_charp)))));
   1.337 +
   1.338 +   if (info_ptr->pcal_params == NULL)
   1.339 +   {
   1.340 +      png_warning(png_ptr, "Insufficient memory for pCAL params");
   1.341 +      return;
   1.342 +   }
   1.343 +
   1.344 +   memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp)));
   1.345 +
   1.346 +   for (i = 0; i < nparams; i++)
   1.347 +   {
   1.348 +      length = strlen(params[i]) + 1;
   1.349 +      png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
   1.350 +          (unsigned long)length);
   1.351 +
   1.352 +      info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
   1.353 +
   1.354 +      if (info_ptr->pcal_params[i] == NULL)
   1.355 +      {
   1.356 +         png_warning(png_ptr, "Insufficient memory for pCAL parameter");
   1.357 +         return;
   1.358 +      }
   1.359 +
   1.360 +      memcpy(info_ptr->pcal_params[i], params[i], length);
   1.361 +   }
   1.362 +
   1.363 +   info_ptr->valid |= PNG_INFO_pCAL;
   1.364 +   info_ptr->free_me |= PNG_FREE_PCAL;
   1.365 +}
   1.366 +#endif
   1.367 +
   1.368 +#ifdef PNG_sCAL_SUPPORTED
   1.369 +void PNGAPI
   1.370 +png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
   1.371 +    int unit, png_const_charp swidth, png_const_charp sheight)
   1.372 +{
   1.373 +   png_size_t lengthw = 0, lengthh = 0;
   1.374 +
   1.375 +   png_debug1(1, "in %s storage function", "sCAL");
   1.376 +
   1.377 +   if (png_ptr == NULL || info_ptr == NULL)
   1.378 +      return;
   1.379 +
   1.380 +   /* Double check the unit (should never get here with an invalid
   1.381 +    * unit unless this is an API call.)
   1.382 +    */
   1.383 +   if (unit != 1 && unit != 2)
   1.384 +      png_error(png_ptr, "Invalid sCAL unit");
   1.385 +
   1.386 +   if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||
   1.387 +       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
   1.388 +      png_error(png_ptr, "Invalid sCAL width");
   1.389 +
   1.390 +   if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||
   1.391 +       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
   1.392 +      png_error(png_ptr, "Invalid sCAL height");
   1.393 +
   1.394 +   info_ptr->scal_unit = (png_byte)unit;
   1.395 +
   1.396 +   ++lengthw;
   1.397 +
   1.398 +   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);
   1.399 +
   1.400 +   info_ptr->scal_s_width = png_voidcast(png_charp,
   1.401 +      png_malloc_warn(png_ptr, lengthw));
   1.402 +
   1.403 +   if (info_ptr->scal_s_width == NULL)
   1.404 +   {
   1.405 +      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
   1.406 +      return;
   1.407 +   }
   1.408 +
   1.409 +   memcpy(info_ptr->scal_s_width, swidth, lengthw);
   1.410 +
   1.411 +   ++lengthh;
   1.412 +
   1.413 +   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);
   1.414 +
   1.415 +   info_ptr->scal_s_height = png_voidcast(png_charp,
   1.416 +      png_malloc_warn(png_ptr, lengthh));
   1.417 +
   1.418 +   if (info_ptr->scal_s_height == NULL)
   1.419 +   {
   1.420 +      png_free (png_ptr, info_ptr->scal_s_width);
   1.421 +      info_ptr->scal_s_width = NULL;
   1.422 +
   1.423 +      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
   1.424 +      return;
   1.425 +   }
   1.426 +
   1.427 +   memcpy(info_ptr->scal_s_height, sheight, lengthh);
   1.428 +
   1.429 +   info_ptr->valid |= PNG_INFO_sCAL;
   1.430 +   info_ptr->free_me |= PNG_FREE_SCAL;
   1.431 +}
   1.432 +
   1.433 +#  ifdef PNG_FLOATING_POINT_SUPPORTED
   1.434 +void PNGAPI
   1.435 +png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
   1.436 +    double width, double height)
   1.437 +{
   1.438 +   png_debug1(1, "in %s storage function", "sCAL");
   1.439 +
   1.440 +   /* Check the arguments. */
   1.441 +   if (width <= 0)
   1.442 +      png_warning(png_ptr, "Invalid sCAL width ignored");
   1.443 +
   1.444 +   else if (height <= 0)
   1.445 +      png_warning(png_ptr, "Invalid sCAL height ignored");
   1.446 +
   1.447 +   else
   1.448 +   {
   1.449 +      /* Convert 'width' and 'height' to ASCII. */
   1.450 +      char swidth[PNG_sCAL_MAX_DIGITS+1];
   1.451 +      char sheight[PNG_sCAL_MAX_DIGITS+1];
   1.452 +
   1.453 +      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
   1.454 +         PNG_sCAL_PRECISION);
   1.455 +      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
   1.456 +         PNG_sCAL_PRECISION);
   1.457 +
   1.458 +      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   1.459 +   }
   1.460 +}
   1.461 +#  endif
   1.462 +
   1.463 +#  ifdef PNG_FIXED_POINT_SUPPORTED
   1.464 +void PNGAPI
   1.465 +png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
   1.466 +    png_fixed_point width, png_fixed_point height)
   1.467 +{
   1.468 +   png_debug1(1, "in %s storage function", "sCAL");
   1.469 +
   1.470 +   /* Check the arguments. */
   1.471 +   if (width <= 0)
   1.472 +      png_warning(png_ptr, "Invalid sCAL width ignored");
   1.473 +
   1.474 +   else if (height <= 0)
   1.475 +      png_warning(png_ptr, "Invalid sCAL height ignored");
   1.476 +
   1.477 +   else
   1.478 +   {
   1.479 +      /* Convert 'width' and 'height' to ASCII. */
   1.480 +      char swidth[PNG_sCAL_MAX_DIGITS+1];
   1.481 +      char sheight[PNG_sCAL_MAX_DIGITS+1];
   1.482 +
   1.483 +      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
   1.484 +      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
   1.485 +
   1.486 +      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   1.487 +   }
   1.488 +}
   1.489 +#  endif
   1.490 +#endif
   1.491 +
   1.492 +#ifdef PNG_pHYs_SUPPORTED
   1.493 +void PNGAPI
   1.494 +png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,
   1.495 +    png_uint_32 res_x, png_uint_32 res_y, int unit_type)
   1.496 +{
   1.497 +   png_debug1(1, "in %s storage function", "pHYs");
   1.498 +
   1.499 +   if (png_ptr == NULL || info_ptr == NULL)
   1.500 +      return;
   1.501 +
   1.502 +   info_ptr->x_pixels_per_unit = res_x;
   1.503 +   info_ptr->y_pixels_per_unit = res_y;
   1.504 +   info_ptr->phys_unit_type = (png_byte)unit_type;
   1.505 +   info_ptr->valid |= PNG_INFO_pHYs;
   1.506 +}
   1.507 +#endif
   1.508 +
   1.509 +void PNGAPI
   1.510 +png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
   1.511 +    png_const_colorp palette, int num_palette)
   1.512 +{
   1.513 +
   1.514 +   png_debug1(1, "in %s storage function", "PLTE");
   1.515 +
   1.516 +   if (png_ptr == NULL || info_ptr == NULL)
   1.517 +      return;
   1.518 +
   1.519 +   if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
   1.520 +   {
   1.521 +      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
   1.522 +         png_error(png_ptr, "Invalid palette length");
   1.523 +
   1.524 +      else
   1.525 +      {
   1.526 +         png_warning(png_ptr, "Invalid palette length");
   1.527 +         return;
   1.528 +      }
   1.529 +   }
   1.530 +
   1.531 +   if ((num_palette > 0 && palette == NULL) ||
   1.532 +      (num_palette == 0
   1.533 +#        ifdef PNG_MNG_FEATURES_SUPPORTED
   1.534 +            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
   1.535 +#        endif
   1.536 +      ))
   1.537 +   {
   1.538 +      png_error(png_ptr, "Invalid palette");
   1.539 +      return;
   1.540 +   }
   1.541 +
   1.542 +   /* It may not actually be necessary to set png_ptr->palette here;
   1.543 +    * we do it for backward compatibility with the way the png_handle_tRNS
   1.544 +    * function used to do the allocation.
   1.545 +    *
   1.546 +    * 1.6.0: the above statement appears to be incorrect; something has to set
   1.547 +    * the palette inside png_struct on read.
   1.548 +    */
   1.549 +   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
   1.550 +
   1.551 +   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
   1.552 +    * of num_palette entries, in case of an invalid PNG file that has
   1.553 +    * too-large sample values.
   1.554 +    */
   1.555 +   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
   1.556 +       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
   1.557 +
   1.558 +   if (num_palette > 0)
   1.559 +      memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));
   1.560 +   info_ptr->palette = png_ptr->palette;
   1.561 +   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;
   1.562 +
   1.563 +   info_ptr->free_me |= PNG_FREE_PLTE;
   1.564 +
   1.565 +   info_ptr->valid |= PNG_INFO_PLTE;
   1.566 +}
   1.567 +
   1.568 +#ifdef PNG_sBIT_SUPPORTED
   1.569 +void PNGAPI
   1.570 +png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
   1.571 +    png_const_color_8p sig_bit)
   1.572 +{
   1.573 +   png_debug1(1, "in %s storage function", "sBIT");
   1.574 +
   1.575 +   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
   1.576 +      return;
   1.577 +
   1.578 +   info_ptr->sig_bit = *sig_bit;
   1.579 +   info_ptr->valid |= PNG_INFO_sBIT;
   1.580 +}
   1.581 +#endif
   1.582 +
   1.583 +#ifdef PNG_sRGB_SUPPORTED
   1.584 +void PNGAPI
   1.585 +png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
   1.586 +{
   1.587 +   png_debug1(1, "in %s storage function", "sRGB");
   1.588 +
   1.589 +   if (png_ptr == NULL || info_ptr == NULL)
   1.590 +      return;
   1.591 +
   1.592 +   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
   1.593 +   png_colorspace_sync_info(png_ptr, info_ptr);
   1.594 +}
   1.595 +
   1.596 +void PNGAPI
   1.597 +png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
   1.598 +    int srgb_intent)
   1.599 +{
   1.600 +   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
   1.601 +
   1.602 +   if (png_ptr == NULL || info_ptr == NULL)
   1.603 +      return;
   1.604 +
   1.605 +   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent))
   1.606 +   {
   1.607 +      /* This causes the gAMA and cHRM to be written too */
   1.608 +      info_ptr->colorspace.flags |=
   1.609 +         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   1.610 +   }
   1.611 +
   1.612 +   png_colorspace_sync_info(png_ptr, info_ptr);
   1.613 +}
   1.614 +#endif /* sRGB */
   1.615 +
   1.616 +
   1.617 +#ifdef PNG_iCCP_SUPPORTED
   1.618 +void PNGAPI
   1.619 +png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
   1.620 +    png_const_charp name, int compression_type,
   1.621 +    png_const_bytep profile, png_uint_32 proflen)
   1.622 +{
   1.623 +   png_charp new_iccp_name;
   1.624 +   png_bytep new_iccp_profile;
   1.625 +   png_size_t length;
   1.626 +
   1.627 +   png_debug1(1, "in %s storage function", "iCCP");
   1.628 +
   1.629 +   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
   1.630 +      return;
   1.631 +
   1.632 +   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
   1.633 +      png_app_error(png_ptr, "Invalid iCCP compression method");
   1.634 +
   1.635 +   /* Set the colorspace first because this validates the profile; do not
   1.636 +    * override previously set app cHRM or gAMA here (because likely as not the
   1.637 +    * application knows better than libpng what the correct values are.)  Pass
   1.638 +    * the info_ptr color_type field to png_colorspace_set_ICC because in the
   1.639 +    * write case it has not yet been stored in png_ptr.
   1.640 +    */
   1.641 +   {
   1.642 +      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
   1.643 +         proflen, profile, info_ptr->color_type);
   1.644 +
   1.645 +      png_colorspace_sync_info(png_ptr, info_ptr);
   1.646 +
   1.647 +      /* Don't do any of the copying if the profile was bad, or inconsistent. */
   1.648 +      if (!result)
   1.649 +         return;
   1.650 +
   1.651 +      /* But do write the gAMA and cHRM chunks from the profile. */
   1.652 +      info_ptr->colorspace.flags |=
   1.653 +         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   1.654 +   }
   1.655 +
   1.656 +   length = strlen(name)+1;
   1.657 +   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
   1.658 +
   1.659 +   if (new_iccp_name == NULL)
   1.660 +   {
   1.661 +      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
   1.662 +      return;
   1.663 +   }
   1.664 +
   1.665 +   memcpy(new_iccp_name, name, length);
   1.666 +   new_iccp_profile = png_voidcast(png_bytep,
   1.667 +      png_malloc_warn(png_ptr, proflen));
   1.668 +
   1.669 +   if (new_iccp_profile == NULL)
   1.670 +   {
   1.671 +      png_free(png_ptr, new_iccp_name);
   1.672 +      png_benign_error(png_ptr,
   1.673 +          "Insufficient memory to process iCCP profile");
   1.674 +      return;
   1.675 +   }
   1.676 +
   1.677 +   memcpy(new_iccp_profile, profile, proflen);
   1.678 +
   1.679 +   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
   1.680 +
   1.681 +   info_ptr->iccp_proflen = proflen;
   1.682 +   info_ptr->iccp_name = new_iccp_name;
   1.683 +   info_ptr->iccp_profile = new_iccp_profile;
   1.684 +   info_ptr->free_me |= PNG_FREE_ICCP;
   1.685 +   info_ptr->valid |= PNG_INFO_iCCP;
   1.686 +}
   1.687 +#endif
   1.688 +
   1.689 +#ifdef PNG_TEXT_SUPPORTED
   1.690 +void PNGAPI
   1.691 +png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,
   1.692 +    png_const_textp text_ptr, int num_text)
   1.693 +{
   1.694 +   int ret;
   1.695 +   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
   1.696 +
   1.697 +   if (ret)
   1.698 +      png_error(png_ptr, "Insufficient memory to store text");
   1.699 +}
   1.700 +
   1.701 +int /* PRIVATE */
   1.702 +png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
   1.703 +    png_const_textp text_ptr, int num_text)
   1.704 +{
   1.705 +   int i;
   1.706 +
   1.707 +   png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" :
   1.708 +      (unsigned long)png_ptr->chunk_name);
   1.709 +
   1.710 +   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
   1.711 +      return(0);
   1.712 +
   1.713 +   /* Make sure we have enough space in the "text" array in info_struct
   1.714 +    * to hold all of the incoming text_ptr objects.  This compare can't overflow
   1.715 +    * because max_text >= num_text (anyway, subtract of two positive integers
   1.716 +    * can't overflow in any case.)
   1.717 +    */
   1.718 +   if (num_text > info_ptr->max_text - info_ptr->num_text)
   1.719 +   {
   1.720 +      int old_num_text = info_ptr->num_text;
   1.721 +      int max_text;
   1.722 +      png_textp new_text = NULL;
   1.723 +
   1.724 +      /* Calculate an appropriate max_text, checking for overflow. */
   1.725 +      max_text = old_num_text;
   1.726 +      if (num_text <= INT_MAX - max_text)
   1.727 +      {
   1.728 +         max_text += num_text;
   1.729 +
   1.730 +         /* Round up to a multiple of 8 */
   1.731 +         if (max_text < INT_MAX-8)
   1.732 +            max_text = (max_text + 8) & ~0x7;
   1.733 +
   1.734 +         else
   1.735 +            max_text = INT_MAX;
   1.736 +
   1.737 +         /* Now allocate a new array and copy the old members in, this does all
   1.738 +          * the overflow checks.
   1.739 +          */
   1.740 +         new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,
   1.741 +            info_ptr->text, old_num_text, max_text-old_num_text,
   1.742 +            sizeof *new_text));
   1.743 +      }
   1.744 +
   1.745 +      if (new_text == NULL)
   1.746 +      {
   1.747 +         png_chunk_report(png_ptr, "too many text chunks",
   1.748 +            PNG_CHUNK_WRITE_ERROR);
   1.749 +         return 1;
   1.750 +      }
   1.751 +
   1.752 +      png_free(png_ptr, info_ptr->text);
   1.753 +
   1.754 +      info_ptr->text = new_text;
   1.755 +      info_ptr->free_me |= PNG_FREE_TEXT;
   1.756 +      info_ptr->max_text = max_text;
   1.757 +      /* num_text is adjusted below as the entries are copied in */
   1.758 +
   1.759 +      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
   1.760 +   }
   1.761 +
   1.762 +   for (i = 0; i < num_text; i++)
   1.763 +   {
   1.764 +      size_t text_length, key_len;
   1.765 +      size_t lang_len, lang_key_len;
   1.766 +      png_textp textp = &(info_ptr->text[info_ptr->num_text]);
   1.767 +
   1.768 +      if (text_ptr[i].key == NULL)
   1.769 +          continue;
   1.770 +
   1.771 +      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
   1.772 +          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
   1.773 +      {
   1.774 +         png_chunk_report(png_ptr, "text compression mode is out of range",
   1.775 +            PNG_CHUNK_WRITE_ERROR);
   1.776 +         continue;
   1.777 +      }
   1.778 +
   1.779 +      key_len = strlen(text_ptr[i].key);
   1.780 +
   1.781 +      if (text_ptr[i].compression <= 0)
   1.782 +      {
   1.783 +         lang_len = 0;
   1.784 +         lang_key_len = 0;
   1.785 +      }
   1.786 +
   1.787 +      else
   1.788 +#  ifdef PNG_iTXt_SUPPORTED
   1.789 +      {
   1.790 +         /* Set iTXt data */
   1.791 +
   1.792 +         if (text_ptr[i].lang != NULL)
   1.793 +            lang_len = strlen(text_ptr[i].lang);
   1.794 +
   1.795 +         else
   1.796 +            lang_len = 0;
   1.797 +
   1.798 +         if (text_ptr[i].lang_key != NULL)
   1.799 +            lang_key_len = strlen(text_ptr[i].lang_key);
   1.800 +
   1.801 +         else
   1.802 +            lang_key_len = 0;
   1.803 +      }
   1.804 +#  else /* PNG_iTXt_SUPPORTED */
   1.805 +      {
   1.806 +         png_chunk_report(png_ptr, "iTXt chunk not supported",
   1.807 +            PNG_CHUNK_WRITE_ERROR);
   1.808 +         continue;
   1.809 +      }
   1.810 +#  endif
   1.811 +
   1.812 +      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
   1.813 +      {
   1.814 +         text_length = 0;
   1.815 +#  ifdef PNG_iTXt_SUPPORTED
   1.816 +         if (text_ptr[i].compression > 0)
   1.817 +            textp->compression = PNG_ITXT_COMPRESSION_NONE;
   1.818 +
   1.819 +         else
   1.820 +#  endif
   1.821 +            textp->compression = PNG_TEXT_COMPRESSION_NONE;
   1.822 +      }
   1.823 +
   1.824 +      else
   1.825 +      {
   1.826 +         text_length = strlen(text_ptr[i].text);
   1.827 +         textp->compression = text_ptr[i].compression;
   1.828 +      }
   1.829 +
   1.830 +      textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,
   1.831 +          key_len + text_length + lang_len + lang_key_len + 4));
   1.832 +
   1.833 +      if (textp->key == NULL)
   1.834 +      {
   1.835 +         png_chunk_report(png_ptr, "text chunk: out of memory",
   1.836 +               PNG_CHUNK_WRITE_ERROR);
   1.837 +         return 1;
   1.838 +      }
   1.839 +
   1.840 +      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
   1.841 +          (unsigned long)(png_uint_32)
   1.842 +          (key_len + lang_len + lang_key_len + text_length + 4),
   1.843 +          textp->key);
   1.844 +
   1.845 +      memcpy(textp->key, text_ptr[i].key, key_len);
   1.846 +      *(textp->key + key_len) = '\0';
   1.847 +
   1.848 +      if (text_ptr[i].compression > 0)
   1.849 +      {
   1.850 +         textp->lang = textp->key + key_len + 1;
   1.851 +         memcpy(textp->lang, text_ptr[i].lang, lang_len);
   1.852 +         *(textp->lang + lang_len) = '\0';
   1.853 +         textp->lang_key = textp->lang + lang_len + 1;
   1.854 +         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
   1.855 +         *(textp->lang_key + lang_key_len) = '\0';
   1.856 +         textp->text = textp->lang_key + lang_key_len + 1;
   1.857 +      }
   1.858 +
   1.859 +      else
   1.860 +      {
   1.861 +         textp->lang=NULL;
   1.862 +         textp->lang_key=NULL;
   1.863 +         textp->text = textp->key + key_len + 1;
   1.864 +      }
   1.865 +
   1.866 +      if (text_length)
   1.867 +         memcpy(textp->text, text_ptr[i].text, text_length);
   1.868 +
   1.869 +      *(textp->text + text_length) = '\0';
   1.870 +
   1.871 +#  ifdef PNG_iTXt_SUPPORTED
   1.872 +      if (textp->compression > 0)
   1.873 +      {
   1.874 +         textp->text_length = 0;
   1.875 +         textp->itxt_length = text_length;
   1.876 +      }
   1.877 +
   1.878 +      else
   1.879 +#  endif
   1.880 +      {
   1.881 +         textp->text_length = text_length;
   1.882 +         textp->itxt_length = 0;
   1.883 +      }
   1.884 +
   1.885 +      info_ptr->num_text++;
   1.886 +      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
   1.887 +   }
   1.888 +
   1.889 +   return(0);
   1.890 +}
   1.891 +#endif
   1.892 +
   1.893 +#ifdef PNG_tIME_SUPPORTED
   1.894 +void PNGAPI
   1.895 +png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
   1.896 +    png_const_timep mod_time)
   1.897 +{
   1.898 +   png_debug1(1, "in %s storage function", "tIME");
   1.899 +
   1.900 +   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
   1.901 +       (png_ptr->mode & PNG_WROTE_tIME))
   1.902 +      return;
   1.903 +
   1.904 +   if (mod_time->month == 0   || mod_time->month > 12  ||
   1.905 +       mod_time->day   == 0   || mod_time->day   > 31  ||
   1.906 +       mod_time->hour  > 23   || mod_time->minute > 59 ||
   1.907 +       mod_time->second > 60)
   1.908 +   {
   1.909 +      png_warning(png_ptr, "Ignoring invalid time value");
   1.910 +      return;
   1.911 +   }
   1.912 +
   1.913 +   info_ptr->mod_time = *mod_time;
   1.914 +   info_ptr->valid |= PNG_INFO_tIME;
   1.915 +}
   1.916 +#endif
   1.917 +
   1.918 +#ifdef PNG_tRNS_SUPPORTED
   1.919 +void PNGAPI
   1.920 +png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
   1.921 +    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
   1.922 +{
   1.923 +   png_debug1(1, "in %s storage function", "tRNS");
   1.924 +
   1.925 +   if (png_ptr == NULL || info_ptr == NULL)
   1.926 +      return;
   1.927 +
   1.928 +   if (trans_alpha != NULL)
   1.929 +   {
   1.930 +       /* It may not actually be necessary to set png_ptr->trans_alpha here;
   1.931 +        * we do it for backward compatibility with the way the png_handle_tRNS
   1.932 +        * function used to do the allocation.
   1.933 +        *
   1.934 +        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
   1.935 +        * relies on png_set_tRNS storing the information in png_struct
   1.936 +        * (otherwise it won't be there for the code in pngrtran.c).
   1.937 +        */
   1.938 +
   1.939 +       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
   1.940 +
   1.941 +       /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
   1.942 +       png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,
   1.943 +         png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
   1.944 +
   1.945 +       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
   1.946 +          memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
   1.947 +   }
   1.948 +
   1.949 +   if (trans_color != NULL)
   1.950 +   {
   1.951 +      int sample_max = (1 << info_ptr->bit_depth);
   1.952 +
   1.953 +      if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
   1.954 +          trans_color->gray > sample_max) ||
   1.955 +          (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
   1.956 +          (trans_color->red > sample_max ||
   1.957 +          trans_color->green > sample_max ||
   1.958 +          trans_color->blue > sample_max)))
   1.959 +         png_warning(png_ptr,
   1.960 +            "tRNS chunk has out-of-range samples for bit_depth");
   1.961 +
   1.962 +      info_ptr->trans_color = *trans_color;
   1.963 +
   1.964 +      if (num_trans == 0)
   1.965 +         num_trans = 1;
   1.966 +   }
   1.967 +
   1.968 +   info_ptr->num_trans = (png_uint_16)num_trans;
   1.969 +
   1.970 +   if (num_trans != 0)
   1.971 +   {
   1.972 +      info_ptr->valid |= PNG_INFO_tRNS;
   1.973 +      info_ptr->free_me |= PNG_FREE_TRNS;
   1.974 +   }
   1.975 +}
   1.976 +#endif
   1.977 +
   1.978 +#ifdef PNG_sPLT_SUPPORTED
   1.979 +void PNGAPI
   1.980 +png_set_sPLT(png_const_structrp png_ptr,
   1.981 +    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
   1.982 +/*
   1.983 + *  entries        - array of png_sPLT_t structures
   1.984 + *                   to be added to the list of palettes
   1.985 + *                   in the info structure.
   1.986 + *
   1.987 + *  nentries       - number of palette structures to be
   1.988 + *                   added.
   1.989 + */
   1.990 +{
   1.991 +   png_sPLT_tp np;
   1.992 +
   1.993 +   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
   1.994 +      return;
   1.995 +
   1.996 +   /* Use the internal realloc function, which checks for all the possible
   1.997 +    * overflows.  Notice that the parameters are (int) and (size_t)
   1.998 +    */
   1.999 +   np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
  1.1000 +      info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
  1.1001 +      sizeof *np));
  1.1002 +
  1.1003 +   if (np == NULL)
  1.1004 +   {
  1.1005 +      /* Out of memory or too many chunks */
  1.1006 +      png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
  1.1007 +      return;
  1.1008 +   }
  1.1009 +
  1.1010 +   png_free(png_ptr, info_ptr->splt_palettes);
  1.1011 +   info_ptr->splt_palettes = np;
  1.1012 +   info_ptr->free_me |= PNG_FREE_SPLT;
  1.1013 +
  1.1014 +   np += info_ptr->splt_palettes_num;
  1.1015 +
  1.1016 +   do
  1.1017 +   {
  1.1018 +      png_size_t length;
  1.1019 +
  1.1020 +      /* Skip invalid input entries */
  1.1021 +      if (entries->name == NULL || entries->entries == NULL)
  1.1022 +      {
  1.1023 +         /* png_handle_sPLT doesn't do this, so this is an app error */
  1.1024 +         png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
  1.1025 +         /* Just skip the invalid entry */
  1.1026 +         continue;
  1.1027 +      }
  1.1028 +
  1.1029 +      np->depth = entries->depth;
  1.1030 +
  1.1031 +      /* In the even of out-of-memory just return - there's no point keeping on
  1.1032 +       * trying to add sPLT chunks.
  1.1033 +       */
  1.1034 +      length = strlen(entries->name) + 1;
  1.1035 +      np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));
  1.1036 +
  1.1037 +      if (np->name == NULL)
  1.1038 +         break;
  1.1039 +
  1.1040 +      memcpy(np->name, entries->name, length);
  1.1041 +
  1.1042 +      /* IMPORTANT: we have memory now that won't get freed if something else
  1.1043 +       * goes wrong, this code must free it.  png_malloc_array produces no
  1.1044 +       * warnings, use a png_chunk_report (below) if there is an error.
  1.1045 +       */
  1.1046 +      np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
  1.1047 +          entries->nentries, sizeof (png_sPLT_entry)));
  1.1048 +
  1.1049 +      if (np->entries == NULL)
  1.1050 +      {
  1.1051 +         png_free(png_ptr, np->name);
  1.1052 +         break;
  1.1053 +      }
  1.1054 +
  1.1055 +      np->nentries = entries->nentries;
  1.1056 +      /* This multiply can't overflow because png_malloc_array has already
  1.1057 +       * checked it when doing the allocation.
  1.1058 +       */
  1.1059 +      memcpy(np->entries, entries->entries,
  1.1060 +         entries->nentries * sizeof (png_sPLT_entry));
  1.1061 +
  1.1062 +      /* Note that 'continue' skips the advance of the out pointer and out
  1.1063 +       * count, so an invalid entry is not added.
  1.1064 +       */
  1.1065 +      info_ptr->valid |= PNG_INFO_sPLT;
  1.1066 +      ++(info_ptr->splt_palettes_num);
  1.1067 +      ++np;
  1.1068 +   }
  1.1069 +   while (++entries, --nentries);
  1.1070 +
  1.1071 +   if (nentries > 0)
  1.1072 +      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
  1.1073 +}
  1.1074 +#endif /* PNG_sPLT_SUPPORTED */
  1.1075 +
  1.1076 +#ifdef PNG_APNG_SUPPORTED
  1.1077 +png_uint_32 PNGAPI
  1.1078 +png_set_acTL(png_structp png_ptr, png_infop info_ptr,
  1.1079 +    png_uint_32 num_frames, png_uint_32 num_plays)
  1.1080 +{
  1.1081 +    png_debug1(1, "in %s storage function", "acTL");
  1.1082 +
  1.1083 +    if (png_ptr == NULL || info_ptr == NULL)
  1.1084 +    {
  1.1085 +        png_warning(png_ptr,
  1.1086 +                    "Call to png_set_acTL() with NULL png_ptr "
  1.1087 +                    "or info_ptr ignored");
  1.1088 +        return (0);
  1.1089 +    }
  1.1090 +    if (num_frames == 0)
  1.1091 +    {
  1.1092 +        png_warning(png_ptr,
  1.1093 +                    "Ignoring attempt to set acTL with num_frames zero");
  1.1094 +        return (0);
  1.1095 +    }
  1.1096 +    if (num_frames > PNG_UINT_31_MAX)
  1.1097 +    {
  1.1098 +        png_warning(png_ptr,
  1.1099 +                    "Ignoring attempt to set acTL with num_frames > 2^31-1");
  1.1100 +        return (0);
  1.1101 +    }
  1.1102 +    if (num_plays > PNG_UINT_31_MAX)
  1.1103 +    {
  1.1104 +        png_warning(png_ptr,
  1.1105 +                    "Ignoring attempt to set acTL with num_plays "
  1.1106 +                    "> 2^31-1");
  1.1107 +        return (0);
  1.1108 +    }
  1.1109 +
  1.1110 +    info_ptr->num_frames = num_frames;
  1.1111 +    info_ptr->num_plays = num_plays;
  1.1112 +
  1.1113 +    info_ptr->valid |= PNG_INFO_acTL;
  1.1114 +
  1.1115 +    return (1);
  1.1116 +}
  1.1117 +
  1.1118 +/* delay_num and delay_den can hold any 16-bit values including zero */
  1.1119 +png_uint_32 PNGAPI
  1.1120 +png_set_next_frame_fcTL(png_structp png_ptr, png_infop info_ptr,
  1.1121 +    png_uint_32 width, png_uint_32 height,
  1.1122 +    png_uint_32 x_offset, png_uint_32 y_offset,
  1.1123 +    png_uint_16 delay_num, png_uint_16 delay_den,
  1.1124 +    png_byte dispose_op, png_byte blend_op)
  1.1125 +{
  1.1126 +    png_debug1(1, "in %s storage function", "fcTL");
  1.1127 +
  1.1128 +    if (png_ptr == NULL || info_ptr == NULL)
  1.1129 +    {
  1.1130 +        png_warning(png_ptr,
  1.1131 +                    "Call to png_set_fcTL() with NULL png_ptr or info_ptr "
  1.1132 +                    "ignored");
  1.1133 +        return (0);
  1.1134 +    }
  1.1135 +
  1.1136 +    png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
  1.1137 +                             delay_num, delay_den, dispose_op, blend_op);
  1.1138 +
  1.1139 +    if (blend_op == PNG_BLEND_OP_OVER)
  1.1140 +    {
  1.1141 +        if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
  1.1142 +            !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
  1.1143 +        {
  1.1144 +          png_warning(png_ptr, "PNG_BLEND_OP_OVER is meaningless "
  1.1145 +                               "and wasteful for opaque images, ignored");
  1.1146 +          blend_op = PNG_BLEND_OP_SOURCE;
  1.1147 +        }
  1.1148 +    }
  1.1149 +
  1.1150 +    info_ptr->next_frame_width = width;
  1.1151 +    info_ptr->next_frame_height = height;
  1.1152 +    info_ptr->next_frame_x_offset = x_offset;
  1.1153 +    info_ptr->next_frame_y_offset = y_offset;
  1.1154 +    info_ptr->next_frame_delay_num = delay_num;
  1.1155 +    info_ptr->next_frame_delay_den = delay_den;
  1.1156 +    info_ptr->next_frame_dispose_op = dispose_op;
  1.1157 +    info_ptr->next_frame_blend_op = blend_op;
  1.1158 +
  1.1159 +    info_ptr->valid |= PNG_INFO_fcTL;
  1.1160 +
  1.1161 +    return (1);
  1.1162 +}
  1.1163 +
  1.1164 +void /* PRIVATE */
  1.1165 +png_ensure_fcTL_is_valid(png_structp png_ptr,
  1.1166 +    png_uint_32 width, png_uint_32 height,
  1.1167 +    png_uint_32 x_offset, png_uint_32 y_offset,
  1.1168 +    png_uint_16 delay_num, png_uint_16 delay_den,
  1.1169 +    png_byte dispose_op, png_byte blend_op)
  1.1170 +{
  1.1171 +    if (width > PNG_UINT_31_MAX)
  1.1172 +        png_error(png_ptr, "invalid width in fcTL (> 2^31-1)");
  1.1173 +    if (height > PNG_UINT_31_MAX)
  1.1174 +        png_error(png_ptr, "invalid height in fcTL (> 2^31-1)");
  1.1175 +    if (x_offset > PNG_UINT_31_MAX)
  1.1176 +        png_error(png_ptr, "invalid x_offset in fcTL (> 2^31-1)");
  1.1177 +    if (y_offset > PNG_UINT_31_MAX)
  1.1178 +        png_error(png_ptr, "invalid y_offset in fcTL (> 2^31-1)");
  1.1179 +    if (width + x_offset > png_ptr->first_frame_width ||
  1.1180 +        height + y_offset > png_ptr->first_frame_height)
  1.1181 +        png_error(png_ptr, "dimensions of a frame are greater than"
  1.1182 +                           "the ones in IHDR");
  1.1183 +
  1.1184 +    if (dispose_op != PNG_DISPOSE_OP_NONE &&
  1.1185 +        dispose_op != PNG_DISPOSE_OP_BACKGROUND &&
  1.1186 +        dispose_op != PNG_DISPOSE_OP_PREVIOUS)
  1.1187 +        png_error(png_ptr, "invalid dispose_op in fcTL");
  1.1188 +
  1.1189 +    if (blend_op != PNG_BLEND_OP_SOURCE &&
  1.1190 +        blend_op != PNG_BLEND_OP_OVER)
  1.1191 +        png_error(png_ptr, "invalid blend_op in fcTL");
  1.1192 +
  1.1193 +    PNG_UNUSED(delay_num)
  1.1194 +    PNG_UNUSED(delay_den)
  1.1195 +}
  1.1196 +
  1.1197 +png_uint_32 PNGAPI
  1.1198 +png_set_first_frame_is_hidden(png_structp png_ptr, png_infop info_ptr,
  1.1199 +                              png_byte is_hidden)
  1.1200 +{
  1.1201 +    png_debug(1, "in png_first_frame_is_hidden()");
  1.1202 +
  1.1203 +    if (png_ptr == NULL)
  1.1204 +        return 0;
  1.1205 +
  1.1206 +    if (is_hidden)
  1.1207 +        png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
  1.1208 +    else
  1.1209 +        png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
  1.1210 +
  1.1211 +    PNG_UNUSED(info_ptr)
  1.1212 +
  1.1213 +    return 1;
  1.1214 +}
  1.1215 +#endif /* PNG_APNG_SUPPORTED */
  1.1216 +
  1.1217 +#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
  1.1218 +static png_byte
  1.1219 +check_location(png_const_structrp png_ptr, int location)
  1.1220 +{
  1.1221 +   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
  1.1222 +
  1.1223 +   /* New in 1.6.0; copy the location and check it.  This is an API
  1.1224 +    * change, previously the app had to use the
  1.1225 +    * png_set_unknown_chunk_location API below for each chunk.
  1.1226 +    */
  1.1227 +   if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT))
  1.1228 +   {
  1.1229 +      /* Write struct, so unknown chunks come from the app */
  1.1230 +      png_app_warning(png_ptr,
  1.1231 +         "png_set_unknown_chunks now expects a valid location");
  1.1232 +      /* Use the old behavior */
  1.1233 +      location = (png_byte)(png_ptr->mode &
  1.1234 +         (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
  1.1235 +   }
  1.1236 +
  1.1237 +   /* This need not be an internal error - if the app calls
  1.1238 +    * png_set_unknown_chunks on a read pointer it must get the location right.
  1.1239 +    */
  1.1240 +   if (location == 0)
  1.1241 +      png_error(png_ptr, "invalid location in png_set_unknown_chunks");
  1.1242 +
  1.1243 +   /* Now reduce the location to the top-most set bit by removing each least
  1.1244 +    * significant bit in turn.
  1.1245 +    */
  1.1246 +   while (location != (location & -location))
  1.1247 +      location &= ~(location & -location);
  1.1248 +
  1.1249 +   /* The cast is safe because 'location' is a bit mask and only the low four
  1.1250 +    * bits are significant.
  1.1251 +    */
  1.1252 +   return (png_byte)location;
  1.1253 +}
  1.1254 +
  1.1255 +void PNGAPI
  1.1256 +png_set_unknown_chunks(png_const_structrp png_ptr,
  1.1257 +   png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
  1.1258 +{
  1.1259 +   png_unknown_chunkp np;
  1.1260 +
  1.1261 +   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
  1.1262 +      unknowns == NULL)
  1.1263 +      return;
  1.1264 +
  1.1265 +   /* Check for the failure cases where support has been disabled at compile
  1.1266 +    * time.  This code is hardly ever compiled - it's here because
  1.1267 +    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
  1.1268 +    * code) but may be meaningless if the read or write handling of unknown
  1.1269 +    * chunks is not compiled in.
  1.1270 +    */
  1.1271 +#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
  1.1272 +      defined(PNG_READ_SUPPORTED)
  1.1273 +      if (png_ptr->mode & PNG_IS_READ_STRUCT)
  1.1274 +      {
  1.1275 +         png_app_error(png_ptr, "no unknown chunk support on read");
  1.1276 +         return;
  1.1277 +      }
  1.1278 +#  endif
  1.1279 +#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
  1.1280 +      defined(PNG_WRITE_SUPPORTED)
  1.1281 +      if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
  1.1282 +      {
  1.1283 +         png_app_error(png_ptr, "no unknown chunk support on write");
  1.1284 +         return;
  1.1285 +      }
  1.1286 +#  endif
  1.1287 +
  1.1288 +   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
  1.1289 +    * unknown critical chunks could be lost with just a warning resulting in
  1.1290 +    * undefined behavior.  Now png_chunk_report is used to provide behavior
  1.1291 +    * appropriate to read or write.
  1.1292 +    */
  1.1293 +   np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
  1.1294 +         info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
  1.1295 +         sizeof *np));
  1.1296 +
  1.1297 +   if (np == NULL)
  1.1298 +   {
  1.1299 +      png_chunk_report(png_ptr, "too many unknown chunks",
  1.1300 +         PNG_CHUNK_WRITE_ERROR);
  1.1301 +      return;
  1.1302 +   }
  1.1303 +
  1.1304 +   png_free(png_ptr, info_ptr->unknown_chunks);
  1.1305 +   info_ptr->unknown_chunks = np; /* safe because it is initialized */
  1.1306 +   info_ptr->free_me |= PNG_FREE_UNKN;
  1.1307 +
  1.1308 +   np += info_ptr->unknown_chunks_num;
  1.1309 +
  1.1310 +   /* Increment unknown_chunks_num each time round the loop to protect the
  1.1311 +    * just-allocated chunk data.
  1.1312 +    */
  1.1313 +   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
  1.1314 +   {
  1.1315 +      memcpy(np->name, unknowns->name, (sizeof np->name));
  1.1316 +      np->name[(sizeof np->name)-1] = '\0';
  1.1317 +      np->location = check_location(png_ptr, unknowns->location);
  1.1318 +
  1.1319 +      if (unknowns->size == 0)
  1.1320 +      {
  1.1321 +         np->data = NULL;
  1.1322 +         np->size = 0;
  1.1323 +      }
  1.1324 +
  1.1325 +      else
  1.1326 +      {
  1.1327 +         np->data = png_voidcast(png_bytep,
  1.1328 +            png_malloc_base(png_ptr, unknowns->size));
  1.1329 +
  1.1330 +         if (np->data == NULL)
  1.1331 +         {
  1.1332 +            png_chunk_report(png_ptr, "unknown chunk: out of memory",
  1.1333 +               PNG_CHUNK_WRITE_ERROR);
  1.1334 +            /* But just skip storing the unknown chunk */
  1.1335 +            continue;
  1.1336 +         }
  1.1337 +
  1.1338 +         memcpy(np->data, unknowns->data, unknowns->size);
  1.1339 +         np->size = unknowns->size;
  1.1340 +      }
  1.1341 +
  1.1342 +      /* These increments are skipped on out-of-memory for the data - the
  1.1343 +       * unknown chunk entry gets overwritten if the png_chunk_report returns.
  1.1344 +       * This is correct in the read case (the chunk is just dropped.)
  1.1345 +       */
  1.1346 +      ++np;
  1.1347 +      ++(info_ptr->unknown_chunks_num);
  1.1348 +   }
  1.1349 +}
  1.1350 +
  1.1351 +void PNGAPI
  1.1352 +png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
  1.1353 +    int chunk, int location)
  1.1354 +{
  1.1355 +   /* This API is pretty pointless in 1.6.0 because the location can be set
  1.1356 +    * before the call to png_set_unknown_chunks.
  1.1357 +    *
  1.1358 +    * TODO: add a png_app_warning in 1.7
  1.1359 +    */
  1.1360 +   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
  1.1361 +      chunk < info_ptr->unknown_chunks_num)
  1.1362 +   {
  1.1363 +      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
  1.1364 +      {
  1.1365 +         png_app_error(png_ptr, "invalid unknown chunk location");
  1.1366 +         /* Fake out the pre 1.6.0 behavior: */
  1.1367 +         if ((location & PNG_HAVE_IDAT)) /* undocumented! */
  1.1368 +            location = PNG_AFTER_IDAT;
  1.1369 +
  1.1370 +         else
  1.1371 +            location = PNG_HAVE_IHDR; /* also undocumented */
  1.1372 +      }
  1.1373 +
  1.1374 +      info_ptr->unknown_chunks[chunk].location =
  1.1375 +         check_location(png_ptr, location);
  1.1376 +   }
  1.1377 +}
  1.1378 +#endif
  1.1379 +
  1.1380 +
  1.1381 +#ifdef PNG_MNG_FEATURES_SUPPORTED
  1.1382 +png_uint_32 PNGAPI
  1.1383 +png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
  1.1384 +{
  1.1385 +   png_debug(1, "in png_permit_mng_features");
  1.1386 +
  1.1387 +   if (png_ptr == NULL)
  1.1388 +      return 0;
  1.1389 +
  1.1390 +   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
  1.1391 +
  1.1392 +   return png_ptr->mng_features_permitted;
  1.1393 +}
  1.1394 +#endif
  1.1395 +
  1.1396 +#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
  1.1397 +static unsigned int
  1.1398 +add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
  1.1399 +{
  1.1400 +   unsigned int i;
  1.1401 +
  1.1402 +   /* Utility function: update the 'keep' state of a chunk if it is already in
  1.1403 +    * the list, otherwise add it to the list.
  1.1404 +    */
  1.1405 +   for (i=0; i<count; ++i, list += 5) if (memcmp(list, add, 4) == 0)
  1.1406 +   {
  1.1407 +      list[4] = (png_byte)keep;
  1.1408 +      return count;
  1.1409 +   }
  1.1410 +
  1.1411 +   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
  1.1412 +   {
  1.1413 +      ++count;
  1.1414 +      memcpy(list, add, 4);
  1.1415 +      list[4] = (png_byte)keep;
  1.1416 +   }
  1.1417 +
  1.1418 +   return count;
  1.1419 +}
  1.1420 +
  1.1421 +void PNGAPI
  1.1422 +png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
  1.1423 +    png_const_bytep chunk_list, int num_chunks_in)
  1.1424 +{
  1.1425 +   png_bytep new_list;
  1.1426 +   unsigned int num_chunks, old_num_chunks;
  1.1427 +
  1.1428 +   if (png_ptr == NULL)
  1.1429 +      return;
  1.1430 +
  1.1431 +   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
  1.1432 +   {
  1.1433 +      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
  1.1434 +      return;
  1.1435 +   }
  1.1436 +
  1.1437 +   if (num_chunks_in <= 0)
  1.1438 +   {
  1.1439 +      png_ptr->unknown_default = keep;
  1.1440 +
  1.1441 +      /* '0' means just set the flags, so stop here */
  1.1442 +      if (num_chunks_in == 0)
  1.1443 +        return;
  1.1444 +   }
  1.1445 +
  1.1446 +   if (num_chunks_in < 0)
  1.1447 +   {
  1.1448 +      /* Ignore all unknown chunks and all chunks recognized by
  1.1449 +       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
  1.1450 +       */
  1.1451 +      static PNG_CONST png_byte chunks_to_ignore[] = {
  1.1452 +         98,  75,  71,  68, '\0',  /* bKGD */
  1.1453 +         99,  72,  82,  77, '\0',  /* cHRM */
  1.1454 +        103,  65,  77,  65, '\0',  /* gAMA */
  1.1455 +        104,  73,  83,  84, '\0',  /* hIST */
  1.1456 +        105,  67,  67,  80, '\0',  /* iCCP */
  1.1457 +        105,  84,  88, 116, '\0',  /* iTXt */
  1.1458 +        111,  70,  70, 115, '\0',  /* oFFs */
  1.1459 +        112,  67,  65,  76, '\0',  /* pCAL */
  1.1460 +        112,  72,  89, 115, '\0',  /* pHYs */
  1.1461 +        115,  66,  73,  84, '\0',  /* sBIT */
  1.1462 +        115,  67,  65,  76, '\0',  /* sCAL */
  1.1463 +        115,  80,  76,  84, '\0',  /* sPLT */
  1.1464 +        115,  84,  69,  82, '\0',  /* sTER */
  1.1465 +        115,  82,  71,  66, '\0',  /* sRGB */
  1.1466 +        116,  69,  88, 116, '\0',  /* tEXt */
  1.1467 +        116,  73,  77,  69, '\0',  /* tIME */
  1.1468 +        122,  84,  88, 116, '\0'   /* zTXt */
  1.1469 +      };
  1.1470 +
  1.1471 +      chunk_list = chunks_to_ignore;
  1.1472 +      num_chunks = (sizeof chunks_to_ignore)/5;
  1.1473 +   }
  1.1474 +
  1.1475 +   else /* num_chunks_in > 0 */
  1.1476 +   {
  1.1477 +      if (chunk_list == NULL)
  1.1478 +      {
  1.1479 +         /* Prior to 1.6.0 this was silently ignored, now it is an app_error
  1.1480 +          * which can be switched off.
  1.1481 +          */
  1.1482 +         png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
  1.1483 +         return;
  1.1484 +      }
  1.1485 +
  1.1486 +      num_chunks = num_chunks_in;
  1.1487 +   }
  1.1488 +
  1.1489 +   old_num_chunks = png_ptr->num_chunk_list;
  1.1490 +   if (png_ptr->chunk_list == NULL)
  1.1491 +      old_num_chunks = 0;
  1.1492 +
  1.1493 +   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
  1.1494 +    */
  1.1495 +   if (num_chunks + old_num_chunks > UINT_MAX/5)
  1.1496 +   {
  1.1497 +      png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
  1.1498 +      return;
  1.1499 +   }
  1.1500 +
  1.1501 +   /* If these chunks are being reset to the default then no more memory is
  1.1502 +    * required because add_one_chunk above doesn't extend the list if the 'keep'
  1.1503 +    * parameter is the default.
  1.1504 +    */
  1.1505 +   if (keep)
  1.1506 +   {
  1.1507 +      new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
  1.1508 +          5 * (num_chunks + old_num_chunks)));
  1.1509 +
  1.1510 +      if (old_num_chunks > 0)
  1.1511 +         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
  1.1512 +   }
  1.1513 +
  1.1514 +   else if (old_num_chunks > 0)
  1.1515 +      new_list = png_ptr->chunk_list;
  1.1516 +
  1.1517 +   else
  1.1518 +      new_list = NULL;
  1.1519 +
  1.1520 +   /* Add the new chunks together with each one's handling code.  If the chunk
  1.1521 +    * already exists the code is updated, otherwise the chunk is added to the
  1.1522 +    * end.  (In libpng 1.6.0 order no longer matters because this code enforces
  1.1523 +    * the earlier convention that the last setting is the one that is used.)
  1.1524 +    */
  1.1525 +   if (new_list != NULL)
  1.1526 +   {
  1.1527 +      png_const_bytep inlist;
  1.1528 +      png_bytep outlist;
  1.1529 +      unsigned int i;
  1.1530 +
  1.1531 +      for (i=0; i<num_chunks; ++i)
  1.1532 +         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
  1.1533 +            chunk_list+5*i, keep);
  1.1534 +
  1.1535 +      /* Now remove any spurious 'default' entries. */
  1.1536 +      num_chunks = 0;
  1.1537 +      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
  1.1538 +         if (inlist[4])
  1.1539 +         {
  1.1540 +            if (outlist != inlist)
  1.1541 +               memcpy(outlist, inlist, 5);
  1.1542 +            outlist += 5;
  1.1543 +            ++num_chunks;
  1.1544 +         }
  1.1545 +
  1.1546 +      /* This means the application has removed all the specialized handling. */
  1.1547 +      if (num_chunks == 0)
  1.1548 +      {
  1.1549 +         if (png_ptr->chunk_list != new_list)
  1.1550 +            png_free(png_ptr, new_list);
  1.1551 +
  1.1552 +         new_list = NULL;
  1.1553 +      }
  1.1554 +   }
  1.1555 +
  1.1556 +   else
  1.1557 +      num_chunks = 0;
  1.1558 +
  1.1559 +   png_ptr->num_chunk_list = num_chunks;
  1.1560 +
  1.1561 +   if (png_ptr->chunk_list != new_list)
  1.1562 +   {
  1.1563 +      if (png_ptr->chunk_list != NULL)
  1.1564 +         png_free(png_ptr, png_ptr->chunk_list);
  1.1565 +
  1.1566 +      png_ptr->chunk_list = new_list;
  1.1567 +   }
  1.1568 +}
  1.1569 +#endif
  1.1570 +
  1.1571 +#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
  1.1572 +void PNGAPI
  1.1573 +png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
  1.1574 +    png_user_chunk_ptr read_user_chunk_fn)
  1.1575 +{
  1.1576 +   png_debug(1, "in png_set_read_user_chunk_fn");
  1.1577 +
  1.1578 +   if (png_ptr == NULL)
  1.1579 +      return;
  1.1580 +
  1.1581 +   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
  1.1582 +   png_ptr->user_chunk_ptr = user_chunk_ptr;
  1.1583 +}
  1.1584 +#endif
  1.1585 +
  1.1586 +#ifdef PNG_INFO_IMAGE_SUPPORTED
  1.1587 +void PNGAPI
  1.1588 +png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
  1.1589 +    png_bytepp row_pointers)
  1.1590 +{
  1.1591 +   png_debug1(1, "in %s storage function", "rows");
  1.1592 +
  1.1593 +   if (png_ptr == NULL || info_ptr == NULL)
  1.1594 +      return;
  1.1595 +
  1.1596 +   if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
  1.1597 +      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
  1.1598 +
  1.1599 +   info_ptr->row_pointers = row_pointers;
  1.1600 +
  1.1601 +   if (row_pointers)
  1.1602 +      info_ptr->valid |= PNG_INFO_IDAT;
  1.1603 +}
  1.1604 +#endif
  1.1605 +
  1.1606 +void PNGAPI
  1.1607 +png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
  1.1608 +{
  1.1609 +    if (png_ptr == NULL)
  1.1610 +       return;
  1.1611 +
  1.1612 +    if (size == 0 || size > PNG_UINT_31_MAX)
  1.1613 +       png_error(png_ptr, "invalid compression buffer size");
  1.1614 +
  1.1615 +#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
  1.1616 +      if (png_ptr->mode & PNG_IS_READ_STRUCT)
  1.1617 +      {
  1.1618 +         png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
  1.1619 +         return;
  1.1620 +      }
  1.1621 +#  endif
  1.1622 +
  1.1623 +#  ifdef PNG_WRITE_SUPPORTED
  1.1624 +      if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
  1.1625 +      {
  1.1626 +         if (png_ptr->zowner != 0)
  1.1627 +         {
  1.1628 +            png_warning(png_ptr,
  1.1629 +              "Compression buffer size cannot be changed because it is in use");
  1.1630 +            return;
  1.1631 +         }
  1.1632 +
  1.1633 +         if (size > ZLIB_IO_MAX)
  1.1634 +         {
  1.1635 +            png_warning(png_ptr,
  1.1636 +               "Compression buffer size limited to system maximum");
  1.1637 +            size = ZLIB_IO_MAX; /* must fit */
  1.1638 +         }
  1.1639 +
  1.1640 +         else if (size < 6)
  1.1641 +         {
  1.1642 +            /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
  1.1643 +             * if this is permitted.
  1.1644 +             */
  1.1645 +            png_warning(png_ptr,
  1.1646 +               "Compression buffer size cannot be reduced below 6");
  1.1647 +            return;
  1.1648 +         }
  1.1649 +
  1.1650 +         if (png_ptr->zbuffer_size != size)
  1.1651 +         {
  1.1652 +            png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
  1.1653 +            png_ptr->zbuffer_size = (uInt)size;
  1.1654 +         }
  1.1655 +      }
  1.1656 +#  endif
  1.1657 +}
  1.1658 +
  1.1659 +void PNGAPI
  1.1660 +png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
  1.1661 +{
  1.1662 +   if (png_ptr && info_ptr)
  1.1663 +      info_ptr->valid &= ~mask;
  1.1664 +}
  1.1665 +
  1.1666 +
  1.1667 +#ifdef PNG_SET_USER_LIMITS_SUPPORTED
  1.1668 +/* This function was added to libpng 1.2.6 */
  1.1669 +void PNGAPI
  1.1670 +png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
  1.1671 +    png_uint_32 user_height_max)
  1.1672 +{
  1.1673 +   /* Images with dimensions larger than these limits will be
  1.1674 +    * rejected by png_set_IHDR().  To accept any PNG datastream
  1.1675 +    * regardless of dimensions, set both limits to 0x7ffffffL.
  1.1676 +    */
  1.1677 +   if (png_ptr == NULL)
  1.1678 +      return;
  1.1679 +
  1.1680 +   png_ptr->user_width_max = user_width_max;
  1.1681 +   png_ptr->user_height_max = user_height_max;
  1.1682 +}
  1.1683 +
  1.1684 +/* This function was added to libpng 1.4.0 */
  1.1685 +void PNGAPI
  1.1686 +png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
  1.1687 +{
  1.1688 +    if (png_ptr)
  1.1689 +       png_ptr->user_chunk_cache_max = user_chunk_cache_max;
  1.1690 +}
  1.1691 +
  1.1692 +/* This function was added to libpng 1.4.1 */
  1.1693 +void PNGAPI
  1.1694 +png_set_chunk_malloc_max (png_structrp png_ptr,
  1.1695 +    png_alloc_size_t user_chunk_malloc_max)
  1.1696 +{
  1.1697 +   if (png_ptr)
  1.1698 +      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
  1.1699 +}
  1.1700 +#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */
  1.1701 +
  1.1702 +
  1.1703 +#ifdef PNG_BENIGN_ERRORS_SUPPORTED
  1.1704 +void PNGAPI
  1.1705 +png_set_benign_errors(png_structrp png_ptr, int allowed)
  1.1706 +{
  1.1707 +   png_debug(1, "in png_set_benign_errors");
  1.1708 +
  1.1709 +   /* If allowed is 1, png_benign_error() is treated as a warning.
  1.1710 +    *
  1.1711 +    * If allowed is 0, png_benign_error() is treated as an error (which
  1.1712 +    * is the default behavior if png_set_benign_errors() is not called).
  1.1713 +    */
  1.1714 +
  1.1715 +   if (allowed)
  1.1716 +      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
  1.1717 +         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
  1.1718 +
  1.1719 +   else
  1.1720 +      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
  1.1721 +         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
  1.1722 +}
  1.1723 +#endif /* PNG_BENIGN_ERRORS_SUPPORTED */
  1.1724 +
  1.1725 +#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
  1.1726 +   /* Whether to report invalid palette index; added at libng-1.5.10.
  1.1727 +    * It is possible for an indexed (color-type==3) PNG file to contain
  1.1728 +    * pixels with invalid (out-of-range) indexes if the PLTE chunk has
  1.1729 +    * fewer entries than the image's bit-depth would allow. We recover
  1.1730 +    * from this gracefully by filling any incomplete palette with zeroes
  1.1731 +    * (opaque black).  By default, when this occurs libpng will issue
  1.1732 +    * a benign error.  This API can be used to override that behavior.
  1.1733 +    */
  1.1734 +void PNGAPI
  1.1735 +png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
  1.1736 +{
  1.1737 +   png_debug(1, "in png_set_check_for_invalid_index");
  1.1738 +
  1.1739 +   if (allowed > 0)
  1.1740 +      png_ptr->num_palette_max = 0;
  1.1741 +
  1.1742 +   else
  1.1743 +      png_ptr->num_palette_max = -1;
  1.1744 +}
  1.1745 +#endif
  1.1746 +#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */

mercurial