pngset.c 45.0 KB
Newer Older
A
Andreas Dilger 已提交
1 2

/* pngset.c - storage of image information into info struct
3
 *
4
 * Last changed in libpng 1.6.0 [(PENDING RELEASE)]
5
 * Copyright (c) 1998-2012 Glenn Randers-Pehrson
6 7
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
8
 *
9
 * This code is released under the libpng license.
10
 * For conditions of distribution and use, see the disclaimer
11
 * and license in png.h
12
 *
13 14 15 16 17
 * The functions here are used during reads to store data from the file
 * into the info struct, and during writes to store application data
 * into the info struct for writing into the file.  This abstracts the
 * info struct and allows us to change the structure in the future.
 */
A
Andreas Dilger 已提交
18

19
#include "pngpriv.h"
20

21 22
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

23
#ifdef PNG_bKGD_SUPPORTED
24
void PNGAPI
25
png_set_bKGD(png_const_structrp png_ptr, png_inforp info_ptr,
26
    png_const_color_16p background)
A
Andreas Dilger 已提交
27
{
28
   png_debug1(1, "in %s storage function", "bKGD");
29

30
   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
A
Andreas Dilger 已提交
31 32
      return;

33
   info_ptr->background = *background;
A
Andreas Dilger 已提交
34 35 36 37
   info_ptr->valid |= PNG_INFO_bKGD;
}
#endif

38
#ifdef PNG_cHRM_SUPPORTED
G
[devel]  
Glenn Randers-Pehrson 已提交
39
void PNGFAPI
40
png_set_cHRM_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
41 42 43
    png_fixed_point white_x, png_fixed_point white_y, png_fixed_point red_x,
    png_fixed_point red_y, png_fixed_point green_x, png_fixed_point green_y,
    png_fixed_point blue_x, png_fixed_point blue_y)
44
{
45 46
   png_xy xy;

47
   png_debug1(1, "in %s storage function", "cHRM fixed");
48

49 50
   if (png_ptr == NULL || info_ptr == NULL)
      return;
A
Andreas Dilger 已提交
51

52 53 54 55 56 57 58 59 60 61 62 63 64 65
   xy.redx = red_x;
   xy.redy = red_y;
   xy.greenx = green_x;
   xy.greeny = green_y;
   xy.bluex = blue_x;
   xy.bluey = blue_y;
   xy.whitex = white_x;
   xy.whitey = white_y;

   if (png_colorspace_set_chromaticities(png_ptr, &info_ptr->colorspace, &xy,
      2/* override with app values*/))
      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;

   png_colorspace_sync_info(png_ptr, info_ptr);
66 67
}

68
void PNGFAPI
69
png_set_cHRM_XYZ_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
70 71 72 73 74 75 76 77 78 79 80 81 82
    png_fixed_point int_red_X, png_fixed_point int_red_Y,
    png_fixed_point int_red_Z, png_fixed_point int_green_X,
    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
    png_fixed_point int_blue_Z)
{
   png_XYZ XYZ;

   png_debug1(1, "in %s storage function", "cHRM XYZ fixed");

   if (png_ptr == NULL || info_ptr == NULL)
      return;

83 84 85 86 87 88 89 90 91
   XYZ.red_X = int_red_X;
   XYZ.red_Y = int_red_Y;
   XYZ.red_Z = int_red_Z;
   XYZ.green_X = int_green_X;
   XYZ.green_Y = int_green_Y;
   XYZ.green_Z = int_green_Z;
   XYZ.blue_X = int_blue_X;
   XYZ.blue_Y = int_blue_Y;
   XYZ.blue_Z = int_blue_Z;
92

93 94
   if (png_colorspace_set_endpoints(png_ptr, &info_ptr->colorspace, &XYZ, 2))
      info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_cHRM;
95

96
   png_colorspace_sync_info(png_ptr, info_ptr);
97 98
}

99
#  ifdef PNG_FLOATING_POINT_SUPPORTED
100
void PNGAPI
101
png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
G
[devel]  
Glenn Randers-Pehrson 已提交
102 103
    double white_x, double white_y, double red_x, double red_y,
    double green_x, double green_y, double blue_x, double blue_y)
A
Andreas Dilger 已提交
104
{
G
[devel]  
Glenn Randers-Pehrson 已提交
105 106 107 108 109 110 111 112 113 114
   png_set_cHRM_fixed(png_ptr, info_ptr,
      png_fixed(png_ptr, white_x, "cHRM White X"),
      png_fixed(png_ptr, white_y, "cHRM White Y"),
      png_fixed(png_ptr, red_x, "cHRM Red X"),
      png_fixed(png_ptr, red_y, "cHRM Red Y"),
      png_fixed(png_ptr, green_x, "cHRM Green X"),
      png_fixed(png_ptr, green_y, "cHRM Green Y"),
      png_fixed(png_ptr, blue_x, "cHRM Blue X"),
      png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
}
115 116

void PNGAPI
117
png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
118 119 120 121 122 123 124 125 126 127 128 129 130 131
    double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
    double blue_X, double blue_Y, double blue_Z)
{
   png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
      png_fixed(png_ptr, red_X, "cHRM Red X"),
      png_fixed(png_ptr, red_Y, "cHRM Red Y"),
      png_fixed(png_ptr, red_Z, "cHRM Red Z"),
      png_fixed(png_ptr, green_X, "cHRM Red X"),
      png_fixed(png_ptr, green_Y, "cHRM Red Y"),
      png_fixed(png_ptr, green_Z, "cHRM Red Z"),
      png_fixed(png_ptr, blue_X, "cHRM Red X"),
      png_fixed(png_ptr, blue_Y, "cHRM Red Y"),
      png_fixed(png_ptr, blue_Z, "cHRM Red Z"));
}
132
#  endif /* PNG_FLOATING_POINT_SUPPORTED */
133

G
[devel]  
Glenn Randers-Pehrson 已提交
134
#endif /* PNG_cHRM_SUPPORTED */
135

G
[devel]  
Glenn Randers-Pehrson 已提交
136 137
#ifdef PNG_gAMA_SUPPORTED
void PNGFAPI
138 139
png_set_gAMA_fixed(png_const_structrp png_ptr, png_inforp info_ptr,
    png_fixed_point file_gamma)
140
{
141
   png_debug1(1, "in %s storage function", "gAMA");
142

143 144 145
   if (png_ptr == NULL || info_ptr == NULL)
      return;

146 147 148 149 150
   /* Changed in libpng-1.5.4 to limit the values to ensure overflow can't
    * occur.  Since the fixed point representation is assymetrical it is
    * possible for 1/gamma to overflow the limit of 21474 and this means the
    * gamma value must be at least 5/100000 and hence at most 20000.0.  For
    * safety the limits here are a little narrower.  The values are 0.00016 to
151
    * 6250.0, which are truly ridiculous gamma values (and will produce
152
    * displays that are all black or all white.)
G
[devel]  
Glenn Randers-Pehrson 已提交
153
    */
154
   if (file_gamma < 16 || file_gamma > 625000000)
155
      png_app_error(png_ptr, "Out of range gamma value ignored");
156

157 158
   else
   {
159 160 161 162 163
      if (png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma,
         2/* overrided with app value */))
         info_ptr->colorspace.flags |= PNG_COLORSPACE_FROM_gAMA;

      png_colorspace_sync_info(png_ptr, info_ptr);
164
   }
G
[devel]  
Glenn Randers-Pehrson 已提交
165
}
166

167
#  ifdef PNG_FLOATING_POINT_SUPPORTED
G
[devel]  
Glenn Randers-Pehrson 已提交
168
void PNGAPI
169
png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)
G
[devel]  
Glenn Randers-Pehrson 已提交
170 171
{
   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
172
       "png_set_gAMA"));
A
Andreas Dilger 已提交
173
}
174
#  endif
175
#endif
A
Andreas Dilger 已提交
176

177
#ifdef PNG_hIST_SUPPORTED
178
void PNGAPI
179 180
png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_uint_16p hist)
A
Andreas Dilger 已提交
181
{
182
   int i;
183

184
   png_debug1(1, "in %s storage function", "hIST");
185

186
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
187
      return;
188

189
   if (info_ptr->num_palette == 0 || info_ptr->num_palette
190
       > PNG_MAX_PALETTE_LENGTH)
191
   {
192
      png_warning(png_ptr,
193
          "Invalid palette size, hIST allocation skipped");
194

195
      return;
196
   }
197 198

   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
199

200 201 202
   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
    * version 1.2.1
    */
203
   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
204
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
205

206
   if (info_ptr->hist == NULL)
207 208 209 210
   {
      png_warning(png_ptr, "Insufficient memory for hIST chunk data");
      return;
   }
A
Andreas Dilger 已提交
211

212 213
   info_ptr->free_me |= PNG_FREE_HIST;

214
   for (i = 0; i < info_ptr->num_palette; i++)
215
      info_ptr->hist[i] = hist[i];
216

A
Andreas Dilger 已提交
217 218 219 220
   info_ptr->valid |= PNG_INFO_hIST;
}
#endif

221
void PNGAPI
222
png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
223 224 225
    png_uint_32 width, png_uint_32 height, int bit_depth,
    int color_type, int interlace_type, int compression_type,
    int filter_type)
A
Andreas Dilger 已提交
226
{
227
   png_debug1(1, "in %s storage function", "IHDR");
228

229
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
230 231 232 233 234
      return;

   info_ptr->width = width;
   info_ptr->height = height;
   info_ptr->bit_depth = (png_byte)bit_depth;
235
   info_ptr->color_type = (png_byte)color_type;
A
Andreas Dilger 已提交
236 237 238
   info_ptr->compression_type = (png_byte)compression_type;
   info_ptr->filter_type = (png_byte)filter_type;
   info_ptr->interlace_type = (png_byte)interlace_type;
239 240 241 242 243

   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
       info_ptr->compression_type, info_ptr->filter_type);

244 245
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
      info_ptr->channels = 1;
246

247
   else if (info_ptr->color_type & PNG_COLOR_MASK_COLOR)
A
Andreas Dilger 已提交
248
      info_ptr->channels = 3;
249

A
Andreas Dilger 已提交
250 251
   else
      info_ptr->channels = 1;
252

A
Andreas Dilger 已提交
253 254
   if (info_ptr->color_type & PNG_COLOR_MASK_ALPHA)
      info_ptr->channels++;
255

A
Andreas Dilger 已提交
256
   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
257

258
   /* Check for potential overflow */
259 260 261 262 263 264
   if (width >
       (PNG_UINT_32_MAX >> 3)      /* 8-byte RRGGBBAA pixels */
       - 48       /* bigrowbuf hack */
       - 1        /* filter byte */
       - 7*8      /* rounding of width to multiple of 8 pixels */
       - 8)       /* extra max_pixel_depth pad */
265
      info_ptr->rowbytes = 0;
266
   else
267
      info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
A
Andreas Dilger 已提交
268 269
}

270
#ifdef PNG_oFFs_SUPPORTED
271
void PNGAPI
272
png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,
273
    png_int_32 offset_x, png_int_32 offset_y, int unit_type)
A
Andreas Dilger 已提交
274
{
275
   png_debug1(1, "in %s storage function", "oFFs");
276

277
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
278 279 280 281 282 283 284 285 286
      return;

   info_ptr->x_offset = offset_x;
   info_ptr->y_offset = offset_y;
   info_ptr->offset_unit_type = (png_byte)unit_type;
   info_ptr->valid |= PNG_INFO_oFFs;
}
#endif

287
#ifdef PNG_pCAL_SUPPORTED
288
void PNGAPI
289
png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
290 291
    png_const_charp purpose, png_int_32 X0, png_int_32 X1, int type,
    int nparams, png_const_charp units, png_charpp params)
A
Andreas Dilger 已提交
292
{
293
   png_size_t length;
294
   int i;
A
Andreas Dilger 已提交
295

296
   png_debug1(1, "in %s storage function", "pCAL");
297

298 299
   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
      || (nparams > 0 && params == NULL))
A
Andreas Dilger 已提交
300 301
      return;

302
   length = strlen(purpose) + 1;
303
   png_debug1(3, "allocating purpose for info (%lu bytes)",
304
       (unsigned long)length);
305

G
[devel]  
Glenn Randers-Pehrson 已提交
306 307 308 309 310 311
   /* TODO: validate format of calibration name and unit name */

   /* Check that the type matches the specification. */
   if (type < 0 || type > 3)
      png_error(png_ptr, "Invalid pCAL equation type");

312 313 314
   if (nparams < 0 || nparams > 255)
      png_error(png_ptr, "Invalid pCAL parameter count");

G
[devel]  
Glenn Randers-Pehrson 已提交
315 316
   /* Validate params[nparams] */
   for (i=0; i<nparams; ++i)
317
      if (params[i] == NULL ||
318
         !png_check_fp_string(params[i], strlen(params[i])))
G
[devel]  
Glenn Randers-Pehrson 已提交
319 320
         png_error(png_ptr, "Invalid format for pCAL parameter");

321 322
   info_ptr->pcal_purpose = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, length));
323

324
   if (info_ptr->pcal_purpose == NULL)
325
   {
326
      png_warning(png_ptr, "Insufficient memory for pCAL purpose");
327 328
      return;
   }
329

330
   memcpy(info_ptr->pcal_purpose, purpose, length);
A
Andreas Dilger 已提交
331

332
   png_debug(3, "storing X0, X1, type, and nparams in info");
A
Andreas Dilger 已提交
333 334 335 336 337
   info_ptr->pcal_X0 = X0;
   info_ptr->pcal_X1 = X1;
   info_ptr->pcal_type = (png_byte)type;
   info_ptr->pcal_nparams = (png_byte)nparams;

338
   length = strlen(units) + 1;
339
   png_debug1(3, "allocating units for info (%lu bytes)",
340
     (unsigned long)length);
341

342 343
   info_ptr->pcal_units = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, length));
344

345
   if (info_ptr->pcal_units == NULL)
346
   {
347
      png_warning(png_ptr, "Insufficient memory for pCAL units");
348 349
      return;
   }
350

351
   memcpy(info_ptr->pcal_units, units, length);
A
Andreas Dilger 已提交
352

353
   info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
354
       (png_size_t)((nparams + 1) * (sizeof (png_charp)))));
355

356
   if (info_ptr->pcal_params == NULL)
357
   {
358
      png_warning(png_ptr, "Insufficient memory for pCAL params");
359 360
      return;
   }
361

362
   memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp)));
A
Andreas Dilger 已提交
363 364 365

   for (i = 0; i < nparams; i++)
   {
366
      length = strlen(params[i]) + 1;
367
      png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
368
          (unsigned long)length);
369

370
      info_ptr->pcal_params[i] = (png_charp)png_malloc_warn(png_ptr, length);
371

372
      if (info_ptr->pcal_params[i] == NULL)
373
      {
374 375
         png_warning(png_ptr, "Insufficient memory for pCAL parameter");
         return;
376
      }
377

378
      memcpy(info_ptr->pcal_params[i], params[i], length);
A
Andreas Dilger 已提交
379 380 381
   }

   info_ptr->valid |= PNG_INFO_pCAL;
382
   info_ptr->free_me |= PNG_FREE_PCAL;
A
Andreas Dilger 已提交
383 384 385
}
#endif

386
#ifdef PNG_sCAL_SUPPORTED
387
void PNGAPI
388
png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
389
    int unit, png_const_charp swidth, png_const_charp sheight)
390
{
391
   png_size_t lengthw = 0, lengthh = 0;
392

393
   png_debug1(1, "in %s storage function", "sCAL");
394

395 396 397
   if (png_ptr == NULL || info_ptr == NULL)
      return;

G
[devel]  
Glenn Randers-Pehrson 已提交
398 399 400 401 402 403
   /* Double check the unit (should never get here with an invalid
    * unit unless this is an API call.)
    */
   if (unit != 1 && unit != 2)
      png_error(png_ptr, "Invalid sCAL unit");

404
   if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||
405
       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
G
[devel]  
Glenn Randers-Pehrson 已提交
406 407
      png_error(png_ptr, "Invalid sCAL width");

408
   if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||
409
       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
G
[devel]  
Glenn Randers-Pehrson 已提交
410 411
      png_error(png_ptr, "Invalid sCAL height");

412
   info_ptr->scal_unit = (png_byte)unit;
413

G
[devel]  
Glenn Randers-Pehrson 已提交
414
   ++lengthw;
415

416
   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);
417

418 419
   info_ptr->scal_s_width = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, lengthw));
420

421 422
   if (info_ptr->scal_s_width == NULL)
   {
G
[devel]  
Glenn Randers-Pehrson 已提交
423
      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
424
      return;
425
   }
426

427
   memcpy(info_ptr->scal_s_width, swidth, lengthw);
428

G
[devel]  
Glenn Randers-Pehrson 已提交
429
   ++lengthh;
430

431
   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);
432

433 434
   info_ptr->scal_s_height = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, lengthh));
435

436 437 438
   if (info_ptr->scal_s_height == NULL)
   {
      png_free (png_ptr, info_ptr->scal_s_width);
439
      info_ptr->scal_s_width = NULL;
440

G
[devel]  
Glenn Randers-Pehrson 已提交
441
      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
442
      return;
443
   }
444

445
   memcpy(info_ptr->scal_s_height, sheight, lengthh);
G
[devel]  
Glenn Randers-Pehrson 已提交
446

447
   info_ptr->valid |= PNG_INFO_sCAL;
448
   info_ptr->free_me |= PNG_FREE_SCAL;
449
}
G
[devel]  
Glenn Randers-Pehrson 已提交
450

451
#  ifdef PNG_FLOATING_POINT_SUPPORTED
G
[devel]  
Glenn Randers-Pehrson 已提交
452
void PNGAPI
453 454
png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
    double width, double height)
G
[devel]  
Glenn Randers-Pehrson 已提交
455 456 457 458 459 460
{
   png_debug1(1, "in %s storage function", "sCAL");

   /* Check the arguments. */
   if (width <= 0)
      png_warning(png_ptr, "Invalid sCAL width ignored");
461

G
[devel]  
Glenn Randers-Pehrson 已提交
462 463
   else if (height <= 0)
      png_warning(png_ptr, "Invalid sCAL height ignored");
464

G
[devel]  
Glenn Randers-Pehrson 已提交
465 466 467 468 469 470
   else
   {
      /* Convert 'width' and 'height' to ASCII. */
      char swidth[PNG_sCAL_MAX_DIGITS+1];
      char sheight[PNG_sCAL_MAX_DIGITS+1];

471
      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
G
[devel]  
Glenn Randers-Pehrson 已提交
472
         PNG_sCAL_PRECISION);
473
      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
G
[devel]  
Glenn Randers-Pehrson 已提交
474 475 476 477 478
         PNG_sCAL_PRECISION);

      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   }
}
479
#  endif
480

481
#  ifdef PNG_FIXED_POINT_SUPPORTED
482
void PNGAPI
483
png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
484
    png_fixed_point width, png_fixed_point height)
485 486 487 488 489 490
{
   png_debug1(1, "in %s storage function", "sCAL");

   /* Check the arguments. */
   if (width <= 0)
      png_warning(png_ptr, "Invalid sCAL width ignored");
491

492 493
   else if (height <= 0)
      png_warning(png_ptr, "Invalid sCAL height ignored");
494

495 496 497 498 499 500
   else
   {
      /* Convert 'width' and 'height' to ASCII. */
      char swidth[PNG_sCAL_MAX_DIGITS+1];
      char sheight[PNG_sCAL_MAX_DIGITS+1];

501 502
      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
503 504 505 506

      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   }
}
507
#  endif
508
#endif
509

510
#ifdef PNG_pHYs_SUPPORTED
511
void PNGAPI
512
png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,
513
    png_uint_32 res_x, png_uint_32 res_y, int unit_type)
A
Andreas Dilger 已提交
514
{
515
   png_debug1(1, "in %s storage function", "pHYs");
516

517
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
518 519 520 521 522 523 524 525 526
      return;

   info_ptr->x_pixels_per_unit = res_x;
   info_ptr->y_pixels_per_unit = res_y;
   info_ptr->phys_unit_type = (png_byte)unit_type;
   info_ptr->valid |= PNG_INFO_pHYs;
}
#endif

527
void PNGAPI
528
png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
529
    png_const_colorp palette, int num_palette)
A
Andreas Dilger 已提交
530
{
531

532
   png_debug1(1, "in %s storage function", "PLTE");
533

534
   if (png_ptr == NULL || info_ptr == NULL || palette == NULL)
A
Andreas Dilger 已提交
535 536
      return;

537
   if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
538 539
   {
      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
540
         png_error(png_ptr, "Invalid palette length");
541

542 543
      else
      {
544 545
         png_warning(png_ptr, "Invalid palette length");
         return;
546 547
      }
   }
548

549
   /* It may not actually be necessary to set png_ptr->palette here;
550 551
    * we do it for backward compatibility with the way the png_handle_tRNS
    * function used to do the allocation.
552 553 554
    *
    * 1.6.0: the above statement appears to be incorrect; something has to set
    * the palette inside png_struct on read.
555 556
    */
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
557

558
   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
559 560 561
    * of num_palette entries, in case of an invalid PNG file that has
    * too-large sample values.
    */
562
   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
563
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
564

565
   memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));
566 567 568 569
   info_ptr->palette = png_ptr->palette;
   info_ptr->num_palette = png_ptr->num_palette = (png_uint_16)num_palette;

   info_ptr->free_me |= PNG_FREE_PLTE;
570

571
   info_ptr->valid |= PNG_INFO_PLTE;
A
Andreas Dilger 已提交
572 573
}

574
#ifdef PNG_sBIT_SUPPORTED
575
void PNGAPI
576
png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
577
    png_const_color_8p sig_bit)
A
Andreas Dilger 已提交
578
{
579
   png_debug1(1, "in %s storage function", "sBIT");
580

581
   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
A
Andreas Dilger 已提交
582 583
      return;

584
   info_ptr->sig_bit = *sig_bit;
A
Andreas Dilger 已提交
585 586 587 588
   info_ptr->valid |= PNG_INFO_sBIT;
}
#endif

589
#ifdef PNG_sRGB_SUPPORTED
590
void PNGAPI
591
png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
592
{
593
   png_debug1(1, "in %s storage function", "sRGB");
594

595
   if (png_ptr == NULL || info_ptr == NULL)
596 597
      return;

598 599 600 601
   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent,
      2/* app value overrides*/);

   png_colorspace_sync_info(png_ptr, info_ptr);
602
}
603

604
void PNGAPI
605
png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
606
    int srgb_intent)
607
{
608
   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
609

610
   if (png_ptr == NULL || info_ptr == NULL)
611 612
      return;

613 614 615 616 617 618 619
   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent,
      2/* app value overrides*/))
   {
      /* And cause the gAMA and cHRM to be written too */
      info_ptr->colorspace.flags |=
         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   }
620

621
   png_colorspace_sync_info(png_ptr, info_ptr);
622
}
623
#endif /* sRGB */
624

625

626
#ifdef PNG_iCCP_SUPPORTED
627
void PNGAPI
628
png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
629 630
    png_const_charp name, int compression_type,
    png_const_bytep profile, png_uint_32 proflen)
631
{
632
   png_charp new_iccp_name;
G
[devel]  
Glenn Randers-Pehrson 已提交
633
   png_bytep new_iccp_profile;
634
   png_size_t length;
635

636
   png_debug1(1, "in %s storage function", "iCCP");
637

638 639 640
   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
      return;

641 642 643 644 645
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
      png_app_error(png_ptr, "Invalid iCCP compression method");

   /* Set the colorspace first because this validates the profile; do not
    * override previously set app cHRM or gAMA here (because likely as not the
646 647 648
    * application knows better than libpng what the correct values are.)  Pass
    * the info_ptr color_type field to png_colorspace_set_ICC because in the
    * write case it has not yet been stored in png_ptr.
649 650 651
    */
   {
      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
652 653
         proflen, profile, 0/* do *not* override the app cHRM or gAMA */,
         info_ptr->color_type);
654 655 656 657 658 659 660 661 662 663 664 665

      png_colorspace_sync_info(png_ptr, info_ptr);

      /* Don't do any of the copying if the profile was bad, or inconsistent. */
      if (!result)
         return;

      /* But do write the gAMA and cHRM chunks from the profile. */
      info_ptr->colorspace.flags |=
         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   }

666
   length = strlen(name)+1;
667
   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
668

669 670
   if (new_iccp_name == NULL)
   {
671
      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
672 673
      return;
   }
674

675
   memcpy(new_iccp_name, name, length);
676 677
   new_iccp_profile = png_voidcast(png_bytep,
      png_malloc_warn(png_ptr, proflen));
678

679 680
   if (new_iccp_profile == NULL)
   {
681 682
      png_free(png_ptr, new_iccp_name);
      png_benign_error(png_ptr,
683
          "Insufficient memory to process iCCP profile");
684 685
      return;
   }
686

687
   memcpy(new_iccp_profile, profile, proflen);
688

689
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
690

691
   info_ptr->iccp_proflen = proflen;
692 693
   info_ptr->iccp_name = new_iccp_name;
   info_ptr->iccp_profile = new_iccp_profile;
694
   info_ptr->free_me |= PNG_FREE_ICCP;
695 696 697 698
   info_ptr->valid |= PNG_INFO_iCCP;
}
#endif

699
#ifdef PNG_TEXT_SUPPORTED
700
void PNGAPI
701 702
png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_textp text_ptr, int num_text)
703 704
{
   int ret;
705
   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
706

707
   if (ret)
708
      png_error(png_ptr, "Insufficient memory to store text");
709 710 711
}

int /* PRIVATE */
712
png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
713
    png_const_textp text_ptr, int num_text)
A
Andreas Dilger 已提交
714 715 716
{
   int i;

717 718
   png_debug1(1, "in %lx storage function", png_ptr == NULL ? "unexpected" :
      (unsigned long)png_ptr->chunk_name);
A
Andreas Dilger 已提交
719

720
   if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
721
      return(0);
A
Andreas Dilger 已提交
722 723 724 725 726 727

   /* Make sure we have enough space in the "text" array in info_struct
    * to hold all of the incoming text_ptr objects.
    */
   if (info_ptr->num_text + num_text > info_ptr->max_text)
   {
728 729 730
      int old_max_text = info_ptr->max_text;
      int old_num_text = info_ptr->num_text;

A
Andreas Dilger 已提交
731 732 733 734 735 736
      if (info_ptr->text != NULL)
      {
         png_textp old_text;

         info_ptr->max_text = info_ptr->num_text + num_text + 8;
         old_text = info_ptr->text;
737

738
         info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
739
            (png_size_t)(info_ptr->max_text * (sizeof (png_text))));
740

741
         if (info_ptr->text == NULL)
742
         {
743 744 745
            /* Restore to previous condition */
            info_ptr->max_text = old_max_text;
            info_ptr->text = old_text;
746 747
            return(1);
         }
748

749
         memcpy(info_ptr->text, old_text, (png_size_t)(old_max_text *
750
             (sizeof (png_text))));
A
Andreas Dilger 已提交
751 752
         png_free(png_ptr, old_text);
      }
753

A
Andreas Dilger 已提交
754 755 756 757
      else
      {
         info_ptr->max_text = num_text + 8;
         info_ptr->num_text = 0;
758
         info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
759
             (png_size_t)(info_ptr->max_text * (sizeof (png_text))));
760
         if (info_ptr->text == NULL)
761 762 763 764
         {
            /* Restore to previous condition */
            info_ptr->num_text = old_num_text;
            info_ptr->max_text = old_max_text;
765
            return(1);
766
         }
767
         info_ptr->free_me |= PNG_FREE_TEXT;
A
Andreas Dilger 已提交
768
      }
769

770
      png_debug1(3, "allocated %d entries for info_ptr->text",
771
          info_ptr->max_text);
A
Andreas Dilger 已提交
772 773 774
   }
   for (i = 0; i < num_text; i++)
   {
775 776
      png_size_t text_length, key_len;
      png_size_t lang_len, lang_key_len;
A
Andreas Dilger 已提交
777 778
      png_textp textp = &(info_ptr->text[info_ptr->num_text]);

779
      if (text_ptr[i].key == NULL)
780 781
          continue;

782 783
      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
784 785 786 787 788
      {
         png_warning(png_ptr, "text compression mode is out of range");
         continue;
      }

789
      key_len = strlen(text_ptr[i].key);
790

791
      if (text_ptr[i].compression <= 0)
792
      {
793 794
         lang_len = 0;
         lang_key_len = 0;
795
      }
796

797
      else
798
#  ifdef PNG_iTXt_SUPPORTED
799
      {
800
         /* Set iTXt data */
801

802
         if (text_ptr[i].lang != NULL)
803
            lang_len = strlen(text_ptr[i].lang);
804

805 806
         else
            lang_len = 0;
807

808
         if (text_ptr[i].lang_key != NULL)
809
            lang_key_len = strlen(text_ptr[i].lang_key);
810

811 812
         else
            lang_key_len = 0;
813
      }
814
#  else /* PNG_iTXt_SUPPORTED */
815
      {
816 817
         png_warning(png_ptr, "iTXt chunk not supported");
         continue;
818
      }
819
#  endif
A
Andreas Dilger 已提交
820

821
      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
A
Andreas Dilger 已提交
822
      {
823
         text_length = 0;
824
#  ifdef PNG_iTXt_SUPPORTED
825
         if (text_ptr[i].compression > 0)
826
            textp->compression = PNG_ITXT_COMPRESSION_NONE;
827

828
         else
829
#  endif
830
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
A
Andreas Dilger 已提交
831
      }
832

A
Andreas Dilger 已提交
833 834
      else
      {
835
         text_length = strlen(text_ptr[i].text);
A
Andreas Dilger 已提交
836 837
         textp->compression = text_ptr[i].compression;
      }
838

839
      textp->key = (png_charp)png_malloc_warn(png_ptr,
840 841
          (png_size_t)
          (key_len + text_length + lang_len + lang_key_len + 4));
842

843
      if (textp->key == NULL)
844
         return(1);
845

846
      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
847 848
          (unsigned long)(png_uint_32)
          (key_len + lang_len + lang_key_len + text_length + 4),
849
          textp->key);
850

851
      memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len));
852
      *(textp->key + key_len) = '\0';
853

854 855
      if (text_ptr[i].compression > 0)
      {
856
         textp->lang = textp->key + key_len + 1;
857
         memcpy(textp->lang, text_ptr[i].lang, lang_len);
858
         *(textp->lang + lang_len) = '\0';
859
         textp->lang_key = textp->lang + lang_len + 1;
860
         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
861
         *(textp->lang_key + lang_key_len) = '\0';
862
         textp->text = textp->lang_key + lang_key_len + 1;
863
      }
864

865 866
      else
      {
867 868
         textp->lang=NULL;
         textp->lang_key=NULL;
869
         textp->text = textp->key + key_len + 1;
870
      }
871

872
      if (text_length)
873
         memcpy(textp->text, text_ptr[i].text,
874
             (png_size_t)(text_length));
875

876
      *(textp->text + text_length) = '\0';
877

878
#  ifdef PNG_iTXt_SUPPORTED
879
      if (textp->compression > 0)
880 881 882 883
      {
         textp->text_length = 0;
         textp->itxt_length = text_length;
      }
884

885
      else
886
#  endif
887 888 889 890
      {
         textp->text_length = text_length;
         textp->itxt_length = 0;
      }
891

A
Andreas Dilger 已提交
892
      info_ptr->num_text++;
893
      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
A
Andreas Dilger 已提交
894
   }
895
   return(0);
A
Andreas Dilger 已提交
896 897 898
}
#endif

899
#ifdef PNG_tIME_SUPPORTED
900
void PNGAPI
901 902
png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_timep mod_time)
A
Andreas Dilger 已提交
903
{
904
   png_debug1(1, "in %s storage function", "tIME");
905

906
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
907
       (png_ptr->mode & PNG_WROTE_tIME))
A
Andreas Dilger 已提交
908 909
      return;

910 911 912 913 914 915 916 917 918
   if (mod_time->month == 0   || mod_time->month > 12  ||
       mod_time->day   == 0   || mod_time->day   > 31  ||
       mod_time->hour  > 23   || mod_time->minute > 59 ||
       mod_time->second > 60)
   {
      png_warning(png_ptr, "Ignoring invalid time value");
      return;
   }

919
   info_ptr->mod_time = *mod_time;
A
Andreas Dilger 已提交
920 921 922 923
   info_ptr->valid |= PNG_INFO_tIME;
}
#endif

924
#ifdef PNG_tRNS_SUPPORTED
925
void PNGAPI
926
png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
927
    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
A
Andreas Dilger 已提交
928
{
929
   png_debug1(1, "in %s storage function", "tRNS");
930

931
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
932 933
      return;

934
   if (trans_alpha != NULL)
935
   {
936
       /* It may not actually be necessary to set png_ptr->trans_alpha here;
937 938
        * we do it for backward compatibility with the way the png_handle_tRNS
        * function used to do the allocation.
939 940 941 942
        *
        * 1.6.0: The above statement is incorrect; png_handle_tRNS effectively
        * relies on png_set_tRNS storing the information in png_struct
        * (otherwise it won't be there for the code in pngrtran.c).
943
        */
944

945
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
946

947
       /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
948 949
       png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,
         png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
950

951
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
952
          memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
953
   }
A
Andreas Dilger 已提交
954

955
   if (trans_color != NULL)
A
Andreas Dilger 已提交
956
   {
957
      int sample_max = (1 << info_ptr->bit_depth);
958

959
      if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
960
          trans_color->gray > sample_max) ||
961
          (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
962 963 964
          (trans_color->red > sample_max ||
          trans_color->green > sample_max ||
          trans_color->blue > sample_max)))
965 966
         png_warning(png_ptr,
            "tRNS chunk has out-of-range samples for bit_depth");
967

968
      info_ptr->trans_color = *trans_color;
969

970
      if (num_trans == 0)
971
         num_trans = 1;
A
Andreas Dilger 已提交
972
   }
973

A
Andreas Dilger 已提交
974
   info_ptr->num_trans = (png_uint_16)num_trans;
975

976 977 978 979 980
   if (num_trans != 0)
   {
      info_ptr->valid |= PNG_INFO_tRNS;
      info_ptr->free_me |= PNG_FREE_TRNS;
   }
A
Andreas Dilger 已提交
981 982 983
}
#endif

984
#ifdef PNG_sPLT_SUPPORTED
985
void PNGAPI
986
png_set_sPLT(png_const_structrp png_ptr,
987
    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
988 989 990 991
/*
 *  entries        - array of png_sPLT_t structures
 *                   to be added to the list of palettes
 *                   in the info structure.
992
 *
993 994 995
 *  nentries       - number of palette structures to be
 *                   added.
 */
996
{
997 998
   png_sPLT_tp np;
   int i;
999

1000 1001
   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 ||
      entries == NULL)
1002
      return;
1003

1004
   np = png_voidcast(png_sPLT_tp, png_malloc_warn(png_ptr,
1005
       (info_ptr->splt_palettes_num + nentries) * (sizeof (png_sPLT_t))));
1006

1007 1008
   if (np == NULL)
   {
1009
      png_warning(png_ptr, "No memory for sPLT palettes");
1010
      return;
1011
   }
1012

1013
   memcpy(np, info_ptr->splt_palettes,
1014
       info_ptr->splt_palettes_num * (sizeof (png_sPLT_t)));
1015

1016 1017
   png_free(png_ptr, info_ptr->splt_palettes);
   info_ptr->splt_palettes=NULL;
1018

1019 1020 1021
   /* TODO: fix this, it apparently leaves NULL entries in the event of OOM
    * below.
    */
1022 1023 1024
   for (i = 0; i < nentries; i++)
   {
      png_sPLT_tp to = np + info_ptr->splt_palettes_num + i;
1025
      png_const_sPLT_tp from = entries + i;
1026
      png_size_t length;
1027

1028 1029 1030 1031
      /* In event of error below the name and entries fields must be set to
       * NULL, otherwise libpng will crash later on while trying to free the
       * uninitialized pointers.
       */
1032
      memset(to, 0, (sizeof *to));
1033 1034 1035 1036

      if (from->name == NULL || from->entries == NULL)
         continue;

1037
      length = strlen(from->name) + 1;
1038
      to->name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
1039

1040 1041 1042
      if (to->name == NULL)
      {
         png_warning(png_ptr,
1043
             "Out of memory while processing sPLT chunk");
1044 1045
         continue;
      }
1046

1047
      memcpy(to->name, from->name, length);
1048
      to->entries = png_voidcast(png_sPLT_entryp, png_malloc_warn(png_ptr,
1049
          from->nentries * (sizeof (png_sPLT_entry))));
1050

1051 1052
      if (to->entries == NULL)
      {
1053
         png_warning(png_ptr, "Out of memory while processing sPLT chunk");
1054 1055 1056 1057
         png_free(png_ptr, to->name);
         to->name = NULL;
         continue;
      }
1058

1059
      memcpy(to->entries, from->entries,
1060
          from->nentries * (sizeof (png_sPLT_entry)));
1061

1062 1063 1064 1065 1066 1067 1068 1069
      to->nentries = from->nentries;
      to->depth = from->depth;
   }

   info_ptr->splt_palettes = np;
   info_ptr->splt_palettes_num += nentries;
   info_ptr->valid |= PNG_INFO_sPLT;
   info_ptr->free_me |= PNG_FREE_SPLT;
1070 1071 1072
}
#endif /* PNG_sPLT_SUPPORTED */

1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
static png_byte
check_location(png_const_structrp png_ptr, unsigned int location)
{
   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);

   /* New in 1.6.0; copy the location and check it.  This is an API
    * change, previously the app had to use the
    * png_set_unknown_chunk_location API below for each chunk.
    */
   if (location == 0 && !(png_ptr->mode & PNG_IS_READ_STRUCT))
   {
      /* Write struct, so unknown chunks come from the app */
      png_app_warning(png_ptr,
         "png_set_unknown_chunks now expects a valid location");
      /* Use the old behavior */
      location = png_ptr->mode &
         (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
   }

   if (location == 0)
      png_error(png_ptr, "invalid location in png_set_unknown_chunks");

   /* Now reduce the location to the top-most set bit by removing each least
    * significant bit in turn.
    */
   while (location != (location & -location))
      location &= (png_byte)~(location & -location);

   /* The cast is safe because 'location' is a bit mask and only the low four
    * bits are significant.
    */
   return (png_byte)location;
}

1108
void PNGAPI
1109
png_set_unknown_chunks(png_const_structrp png_ptr,
1110
   png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
1111
{
1112 1113
   png_unknown_chunkp np;

1114
   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0)
1115
      return;
1116

1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139
   /* Check for the failure cases where support has been disabled at compile
    * time.  This code is hardly ever compiled - it's here because
    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
    * code) but may be meaningless if the read or write handling of unknown
    * chunks is not compiled in.
    */
#  if !(defined PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
      (defined PNG_READ_SUPPORTED)
      if (png_ptr->mode & PNG_IS_READ_STRUCT)
      {
         png_app_error(png_ptr, "no unknown chunk support on read");
         return;
      }
#  endif
#  if !(defined PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
      (defined PNG_WRITE_SUPPORTED)
      if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
      {
         png_app_error(png_ptr, "no unknown chunk support on write");
         return;
      }
#  endif

1140 1141 1142 1143 1144 1145 1146 1147 1148 1149
   /* Prior to 1.6.0 this code used png_malloc_warn, however this meant that
    * unknown critical chunks could be lost with just a warning resulting in
    * undefined behavior.  Changing to png_malloc fixes this by producing a
    * png_error.  The (png_size_t) cast was also removed as it hides a potential
    * overflow.
    *
    * TODO: fix the potential overflow in the multiply
    */
   np = png_voidcast(png_unknown_chunkp, png_malloc(png_ptr,
       (info_ptr->unknown_chunks_num + (unsigned int)num_unknowns) *
1150
       (sizeof (png_unknown_chunk))));
1151

1152
   memcpy(np, info_ptr->unknown_chunks,
1153
       info_ptr->unknown_chunks_num * (sizeof (png_unknown_chunk)));
1154

1155
   png_free(png_ptr, info_ptr->unknown_chunks);
1156 1157
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
   info_ptr->free_me |= PNG_FREE_UNKN;
1158

1159
   np += info_ptr->unknown_chunks_num;
1160

1161 1162 1163 1164 1165 1166 1167 1168 1169 1170
   /* Increment unknown_chunks_num each time round the loop to protect the
    * just-allocated chunk data.
    */
   for (; --num_unknowns >= 0;
      ++np, ++unknowns, ++(info_ptr->unknown_chunks_num))
   {
      memcpy(np->name, unknowns->name, (sizeof unknowns->name));
      np->name[(sizeof np->name)-1] = '\0';
      np->size = unknowns->size;
      np->location = check_location(png_ptr, unknowns->location);
1171

1172 1173
      if (unknowns->size == 0)
         np->data = NULL;
1174

1175 1176
      else
      {
1177 1178 1179 1180
         /* png_error is safe here because the list is stored in png_ptr */
         np->data = png_voidcast(png_bytep,
            png_malloc(png_ptr, unknowns->size));
         memcpy(np->data, unknowns->data, unknowns->size);
1181 1182
      }
   }
1183
}
1184

1185
void PNGAPI
1186
png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
1187
    int chunk, int location)
1188
{
1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210
   /* This API is pretty pointless in 1.6.0 because the location can be set
    * before the call to png_set_unknown_chunks.
    *
    * TODO: add a png_app_warning in 1.7
    */
   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
      (unsigned int)chunk < info_ptr->unknown_chunks_num)
   {
      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
      {
         png_app_error(png_ptr, "invalid unknown chunk location");
         /* Fake out the pre 1.6.0 behavior: */
         if ((location & PNG_HAVE_IDAT)) /* undocumented! */
            location = PNG_AFTER_IDAT;

         else
            location = PNG_HAVE_IHDR; /* also undocumented */
      }

      info_ptr->unknown_chunks[chunk].location =
         check_location(png_ptr, (png_byte)location);
   }
1211
}
1212 1213
#endif

1214

1215
#ifdef PNG_MNG_FEATURES_SUPPORTED
1216
png_uint_32 PNGAPI
1217
png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
1218
{
1219
   png_debug(1, "in png_permit_mng_features");
1220

1221
   if (png_ptr == NULL)
1222
      return 0;
1223

1224
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1225

1226
   return png_ptr->mng_features_permitted;
1227 1228
}
#endif
1229

1230
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1231 1232
static unsigned int
add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
1233
{
1234
   unsigned int i;
1235

1236 1237 1238 1239
   /* Utility function: update the 'keep' state of a chunk if it is already in
    * the list, otherwise add it to the list.
    */
   for (i=0; i<count; ++i, list += 5) if (memcmp(list, add, 4) == 0)
1240
   {
1241 1242 1243
      list[4] = (png_byte)keep;
      return count;
   }
1244

1245 1246 1247 1248 1249 1250
   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
   {
      ++count;
      memcpy(list, add, 4);
      list[4] = (png_byte)keep;
   }
1251

1252 1253
   return count;
}
1254

1255 1256
void PNGAPI
png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
1257
    png_const_bytep chunk_list, int num_chunks_in)
1258 1259 1260
{
   png_bytep new_list;
   unsigned int num_chunks, old_num_chunks;
1261

1262 1263
   if (png_ptr == NULL)
      return;
1264

1265 1266 1267 1268
   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
   {
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
      return;
1269 1270
   }

1271
   if (num_chunks_in <= 0)
1272
   {
1273
      png_ptr->unknown_default = keep;
1274

1275
      /* '0' means just set the flags, so stop here */
1276
      if (num_chunks_in == 0)
1277
        return;
1278
   }
1279

1280
   if (num_chunks_in < 0)
1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307
   {
      /* Ignore all unknown chunks and all chunks recognized by
       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
       */
      static PNG_CONST png_byte chunks_to_ignore[] = {
         98,  75,  71,  68, '\0',  /* bKGD */
         99,  72,  82,  77, '\0',  /* cHRM */
        103,  65,  77,  65, '\0',  /* gAMA */
        104,  73,  83,  84, '\0',  /* hIST */
        105,  67,  67,  80, '\0',  /* iCCP */
        105,  84,  88, 116, '\0',  /* iTXt */
        111,  70,  70, 115, '\0',  /* oFFs */
        112,  67,  65,  76, '\0',  /* pCAL */
        112,  72,  89, 115, '\0',  /* pHYs */
        115,  66,  73,  84, '\0',  /* sBIT */
        115,  67,  65,  76, '\0',  /* sCAL */
        115,  80,  76,  84, '\0',  /* sPLT */
        115,  84,  69,  82, '\0',  /* sTER */
        115,  82,  71,  66, '\0',  /* sRGB */
        116,  69,  88, 116, '\0',  /* tEXt */
        116,  73,  77,  69, '\0',  /* tIME */
        122,  84,  88, 116, '\0'   /* zTXt */
      };

      chunk_list = chunks_to_ignore;
      num_chunks = (sizeof chunks_to_ignore)/5;
   }
1308

1309
   else /* num_chunks_in > 0 */
1310 1311
   {
      if (chunk_list == NULL)
1312 1313 1314 1315 1316
      {
         /* Prior to 1.6.0 this was silently ignored, now it is an app_error
          * which can be switched off.
          */
         png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
1317
         return;
1318
      }
1319

1320
      num_chunks = num_chunks_in;
1321
   }
1322

1323
   old_num_chunks = png_ptr->num_chunk_list;
1324 1325
   if (png_ptr->chunk_list == NULL)
      old_num_chunks = 0;
1326 1327 1328 1329 1330 1331 1332 1333 1334

   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
    */
   if (num_chunks + old_num_chunks > UINT_MAX/5)
   {
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
      return;
   }

1335 1336 1337 1338 1339 1340 1341 1342
   /* If these chunks are being reset to the default then no more memory is
    * required because add_one_chunk above doesn't extend the list if the 'keep'
    * parameter is the default.
    */
   if (keep)
   {
      new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
          5 * (num_chunks + old_num_chunks)));
1343

1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359
      if (old_num_chunks > 0)
         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
   }

   else if (old_num_chunks > 0)
      new_list = png_ptr->chunk_list;

   else
      new_list = NULL;

   /* Add the new chunks together with each one's handling code.  If the chunk
    * already exists the code is updated, otherwise the chunk is added to the
    * end.  (In libpng 1.6.0 order no longer matters because this code enforces
    * the earlier convention that the last setting is the one that is used.)
    */
   if (new_list != NULL)
1360
   {
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387
      png_const_bytep inlist;
      png_bytep outlist;
      unsigned int i;

      for (i=0; i<num_chunks; ++i)
         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
            chunk_list+5*i, keep);

      /* Now remove any spurious 'default' entries. */
      num_chunks = 0;
      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
         if (inlist[4])
         {
            if (outlist != inlist)
               memcpy(outlist, inlist, 5);
            outlist += 5;
            ++num_chunks;
         }

      /* This means the application has removed all the specialized handling. */
      if (num_chunks == 0)
      {
         if (png_ptr->chunk_list != new_list)
            png_free(png_ptr, new_list);

         new_list = NULL;
      }
1388
   }
1389

1390 1391
   else
      num_chunks = 0;
1392

1393
   png_ptr->num_chunk_list = num_chunks;
1394

1395 1396 1397 1398 1399 1400 1401
   if (png_ptr->chunk_list != new_list)
   {
      if (png_ptr->chunk_list != NULL)
         png_free(png_ptr, png_ptr->chunk_list);

      png_ptr->chunk_list = new_list;
   }
1402 1403
}
#endif
1404

1405
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1406
void PNGAPI
1407
png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
1408
    png_user_chunk_ptr read_user_chunk_fn)
1409
{
1410
   png_debug(1, "in png_set_read_user_chunk_fn");
1411

1412 1413
   if (png_ptr == NULL)
      return;
1414

1415 1416 1417 1418
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
   png_ptr->user_chunk_ptr = user_chunk_ptr;
}
#endif
1419

1420
#ifdef PNG_INFO_IMAGE_SUPPORTED
1421
void PNGAPI
1422 1423
png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
    png_bytepp row_pointers)
1424
{
1425
   png_debug1(1, "in %s storage function", "rows");
1426

1427 1428 1429
   if (png_ptr == NULL || info_ptr == NULL)
      return;

1430
   if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
1431
      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1432

1433
   info_ptr->row_pointers = row_pointers;
1434

1435
   if (row_pointers)
1436
      info_ptr->valid |= PNG_INFO_IDAT;
1437 1438 1439
}
#endif

1440
void PNGAPI
1441
png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
1442
{
1443 1444
    if (png_ptr == NULL)
       return;
1445

1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456
    if (size == 0 || size > PNG_UINT_31_MAX)
       png_error(png_ptr, "invalid compression buffer size");

#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
      if (png_ptr->mode & PNG_IS_READ_STRUCT)
      {
         png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
         return;
      }
#  endif

1457
#  ifdef PNG_WRITE_SUPPORTED
1458 1459 1460 1461 1462 1463 1464 1465
      if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
      {
         if (png_ptr->zowner != 0)
         {
            png_warning(png_ptr,
              "Compression buffer size cannot be changed because it is in use");
            return;
         }
1466

1467 1468 1469 1470 1471 1472
         if (size > ZLIB_IO_MAX)
         {
            png_warning(png_ptr,
               "Compression buffer size limited to system maximum");
            size = ZLIB_IO_MAX; /* must fit */
         }
1473

1474 1475 1476 1477 1478 1479 1480 1481 1482
         else if (size < 6)
         {
            /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
             * if this is permitted.
             */
            png_warning(png_ptr,
               "Compression buffer size cannot be reduced below 6");
            return;
         }
1483

1484 1485 1486 1487 1488 1489 1490
         if (png_ptr->zbuffer_size != size)
         {
            png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
            png_ptr->zbuffer_size = (uInt)size;
         }
      }
#  endif
1491
}
1492 1493

void PNGAPI
1494
png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
1495 1496
{
   if (png_ptr && info_ptr)
1497
      info_ptr->valid &= ~mask;
1498
}
1499

1500

1501
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1502
/* This function was added to libpng 1.2.6 */
1503
void PNGAPI
1504
png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
1505 1506
    png_uint_32 user_height_max)
{
1507 1508 1509 1510 1511 1512
   /* Images with dimensions larger than these limits will be
    * rejected by png_set_IHDR().  To accept any PNG datastream
    * regardless of dimensions, set both limits to 0x7ffffffL.
    */
   if (png_ptr == NULL)
      return;
1513

1514 1515
   png_ptr->user_width_max = user_width_max;
   png_ptr->user_height_max = user_height_max;
1516
}
1517

1518
/* This function was added to libpng 1.4.0 */
1519
void PNGAPI
1520
png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
1521
{
1522 1523 1524 1525 1526 1527
    if (png_ptr)
       png_ptr->user_chunk_cache_max = user_chunk_cache_max;
}

/* This function was added to libpng 1.4.1 */
void PNGAPI
1528
png_set_chunk_malloc_max (png_structrp png_ptr,
1529
    png_alloc_size_t user_chunk_malloc_max)
1530
{
1531 1532
   if (png_ptr)
      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
1533
}
1534 1535
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */

1536

1537
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
1538
void PNGAPI
1539
png_set_benign_errors(png_structrp png_ptr, int allowed)
1540
{
1541
   png_debug(1, "in png_set_benign_errors");
1542

1543 1544 1545 1546 1547 1548
   /* If allowed is 1, png_benign_error() is treated as a warning.
    *
    * If allowed is 0, png_benign_error() is treated as an error (which
    * is the default behavior if png_set_benign_errors() is not called).
    */

1549
   if (allowed)
1550 1551
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
1552

1553
   else
1554 1555
      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
1556 1557
}
#endif /* PNG_BENIGN_ERRORS_SUPPORTED */
1558

1559
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
1560 1561 1562 1563 1564 1565
   /* Do not report invalid palette index; added at libng-1.5.10 */
void PNGAPI
png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
{
   png_debug(1, "in png_set_check_for_invalid_index");

1566
   if (allowed > 0)
1567 1568 1569 1570 1571 1572 1573
      png_ptr->num_palette_max = 0;

   else
      png_ptr->num_palette_max = -1;
}
#endif

1574
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */