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.

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

mercurial