pngset.c 40.7 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 83 84 85 86 87 88 89 90 91 92
    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;

   XYZ.redX = int_red_X;
   XYZ.redY = int_red_Y;
   XYZ.redZ = int_red_Z;
   XYZ.greenX = int_green_X;
   XYZ.greenY = int_green_Y;
   XYZ.greenZ = int_green_Z;
   XYZ.blueX = int_blue_X;
   XYZ.blueY = int_blue_Y;
   XYZ.blueZ = int_blue_Z;

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 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662
   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
    * application knows better than libpng what the correct values are.)
    */
   {
      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
         proflen, profile, 0/* do *not* override the app cHRM or gAMA */);

      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;
   }

663
   length = strlen(name)+1;
664
   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
665

666 667
   if (new_iccp_name == NULL)
   {
668
      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
669 670
      return;
   }
671

672
   memcpy(new_iccp_name, name, length);
673 674
   new_iccp_profile = png_voidcast(png_bytep,
      png_malloc_warn(png_ptr, proflen));
675

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

684
   memcpy(new_iccp_profile, profile, proflen);
685

686
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
687

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

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

704
   if (ret)
705
      png_error(png_ptr, "Insufficient memory to store text");
706 707 708
}

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

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

717
   if (png_ptr == NULL || info_ptr == NULL || num_text == 0)
718
      return(0);
A
Andreas Dilger 已提交
719 720 721 722 723 724

   /* 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)
   {
725 726 727
      int old_max_text = info_ptr->max_text;
      int old_num_text = info_ptr->num_text;

A
Andreas Dilger 已提交
728 729 730 731 732 733
      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;
734

735
         info_ptr->text = (png_textp)png_malloc_warn(png_ptr,
736
            (png_size_t)(info_ptr->max_text * (sizeof (png_text))));
737

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

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

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

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

776
      if (text_ptr[i].key == NULL)
777 778
          continue;

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

786
      key_len = strlen(text_ptr[i].key);
787

788
      if (text_ptr[i].compression <= 0)
789
      {
790 791
         lang_len = 0;
         lang_key_len = 0;
792
      }
793

794
      else
795
#  ifdef PNG_iTXt_SUPPORTED
796
      {
797
         /* Set iTXt data */
798

799
         if (text_ptr[i].lang != NULL)
800
            lang_len = strlen(text_ptr[i].lang);
801

802 803
         else
            lang_len = 0;
804

805
         if (text_ptr[i].lang_key != NULL)
806
            lang_key_len = strlen(text_ptr[i].lang_key);
807

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

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

825
         else
826
#  endif
827
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
A
Andreas Dilger 已提交
828
      }
829

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

836
      textp->key = (png_charp)png_malloc_warn(png_ptr,
837 838
          (png_size_t)
          (key_len + text_length + lang_len + lang_key_len + 4));
839

840
      if (textp->key == NULL)
841
         return(1);
842

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

848
      memcpy(textp->key, text_ptr[i].key,(png_size_t)(key_len));
849
      *(textp->key + key_len) = '\0';
850

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

862 863
      else
      {
864 865
         textp->lang=NULL;
         textp->lang_key=NULL;
866
         textp->text = textp->key + key_len + 1;
867
      }
868

869
      if (text_length)
870
         memcpy(textp->text, text_ptr[i].text,
871
             (png_size_t)(text_length));
872

873
      *(textp->text + text_length) = '\0';
874

875
#  ifdef PNG_iTXt_SUPPORTED
876
      if (textp->compression > 0)
877 878 879 880
      {
         textp->text_length = 0;
         textp->itxt_length = text_length;
      }
881

882
      else
883
#  endif
884 885 886 887
      {
         textp->text_length = text_length;
         textp->itxt_length = 0;
      }
888

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

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

903
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
904
       (png_ptr->mode & PNG_WROTE_tIME))
A
Andreas Dilger 已提交
905 906
      return;

907 908 909 910 911 912 913 914 915
   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;
   }

916
   info_ptr->mod_time = *mod_time;
A
Andreas Dilger 已提交
917 918 919 920
   info_ptr->valid |= PNG_INFO_tIME;
}
#endif

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

928
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
929 930
      return;

931
   if (trans_alpha != NULL)
932
   {
933
       /* It may not actually be necessary to set png_ptr->trans_alpha here;
934 935
        * we do it for backward compatibility with the way the png_handle_tRNS
        * function used to do the allocation.
936 937 938 939
        *
        * 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).
940
        */
941

942
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
943

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

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

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

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

965
      info_ptr->trans_color = *trans_color;
966

967
      if (num_trans == 0)
968
         num_trans = 1;
A
Andreas Dilger 已提交
969
   }
970

A
Andreas Dilger 已提交
971
   info_ptr->num_trans = (png_uint_16)num_trans;
972

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

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

997 998
   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 ||
      entries == NULL)
999
      return;
1000

1001
   np = png_voidcast(png_sPLT_tp, png_malloc_warn(png_ptr,
1002
       (info_ptr->splt_palettes_num + nentries) * (sizeof (png_sPLT_t))));
1003

1004 1005
   if (np == NULL)
   {
1006
      png_warning(png_ptr, "No memory for sPLT palettes");
1007
      return;
1008
   }
1009

1010
   memcpy(np, info_ptr->splt_palettes,
1011
       info_ptr->splt_palettes_num * (sizeof (png_sPLT_t)));
1012

1013 1014
   png_free(png_ptr, info_ptr->splt_palettes);
   info_ptr->splt_palettes=NULL;
1015

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

1025 1026 1027 1028
      /* 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.
       */
1029
      memset(to, 0, (sizeof *to));
1030 1031 1032 1033

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

1034
      length = strlen(from->name) + 1;
1035
      to->name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
1036

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

1044
      memcpy(to->name, from->name, length);
1045
      to->entries = png_voidcast(png_sPLT_entryp, png_malloc_warn(png_ptr,
1046
          from->nentries * (sizeof (png_sPLT_entry))));
1047

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

1056
      memcpy(to->entries, from->entries,
1057
          from->nentries * (sizeof (png_sPLT_entry)));
1058

1059 1060 1061 1062 1063 1064 1065 1066
      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;
1067 1068 1069
}
#endif /* PNG_sPLT_SUPPORTED */

1070
#ifdef PNG_UNKNOWN_CHUNKS_SUPPORTED
1071
void PNGAPI
1072
png_set_unknown_chunks(png_const_structrp png_ptr,
1073
   png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
1074
{
1075 1076 1077 1078
   png_unknown_chunkp np;
   int i;

   if (png_ptr == NULL || info_ptr == NULL || num_unknowns == 0)
1079
      return;
1080

1081
   np = png_voidcast(png_unknown_chunkp, png_malloc_warn(png_ptr,
1082
       (png_size_t)(info_ptr->unknown_chunks_num + num_unknowns) *
1083
       (sizeof (png_unknown_chunk))));
1084

1085 1086 1087
   if (np == NULL)
   {
      png_warning(png_ptr,
1088
          "Out of memory while processing unknown chunk");
1089 1090 1091
      return;
   }

1092
   memcpy(np, info_ptr->unknown_chunks,
1093
       (png_size_t)info_ptr->unknown_chunks_num *
1094
       (sizeof (png_unknown_chunk)));
1095

1096
   png_free(png_ptr, info_ptr->unknown_chunks);
1097
   info_ptr->unknown_chunks = NULL;
1098 1099 1100 1101

   for (i = 0; i < num_unknowns; i++)
   {
      png_unknown_chunkp to = np + info_ptr->unknown_chunks_num + i;
1102
      png_const_unknown_chunkp from = unknowns + i;
1103

1104
      memcpy(to->name, from->name, (sizeof from->name));
1105
      to->name[(sizeof to->name)-1] = '\0';
1106
      to->size = from->size;
1107

1108
      /* Note our location in the read or write sequence */
1109
      to->location = (png_byte)png_ptr->mode;
1110 1111 1112

      if (from->size == 0)
         to->data=NULL;
1113

1114 1115 1116
      else
      {
         to->data = (png_bytep)png_malloc_warn(png_ptr,
1117
             (png_size_t)from->size);
1118

1119 1120 1121
         if (to->data == NULL)
         {
            png_warning(png_ptr,
1122
                "Out of memory while processing unknown chunk");
1123 1124
            to->size = 0;
         }
1125

1126
         else
1127
            memcpy(to->data, from->data, from->size);
1128 1129 1130 1131 1132 1133
      }
   }

   info_ptr->unknown_chunks = np;
   info_ptr->unknown_chunks_num += num_unknowns;
   info_ptr->free_me |= PNG_FREE_UNKN;
1134
}
1135

1136
void PNGAPI
1137
png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
1138
    int chunk, int location)
1139
{
1140
   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 && chunk <
1141
       info_ptr->unknown_chunks_num)
1142 1143
      info_ptr->unknown_chunks[chunk].location = (png_byte)location;
}
1144 1145
#endif

1146

1147
#ifdef PNG_MNG_FEATURES_SUPPORTED
1148
png_uint_32 PNGAPI
1149
png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
1150
{
1151
   png_debug(1, "in png_permit_mng_features");
1152

1153
   if (png_ptr == NULL)
1154
      return 0;
1155

1156
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1157

1158
   return png_ptr->mng_features_permitted;
1159 1160
}
#endif
1161

1162
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1163
void PNGAPI
1164
png_set_keep_unknown_chunks(png_structrp png_ptr, int keepIn,
1165
    png_const_bytep chunk_list, int num_chunksIn)
1166
{
1167
   png_bytep new_list, p;
1168
   png_byte keep;
1169
   unsigned int i, num_chunks, old_num_chunks;
1170 1171
   if (png_ptr == NULL)
      return;
1172

1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196
   switch (keepIn)
   {
      case PNG_HANDLE_CHUNK_AS_DEFAULT:
         keep = PNG_HANDLE_CHUNK_AS_DEFAULT;
         break;

      case PNG_HANDLE_CHUNK_NEVER:
         keep = PNG_HANDLE_CHUNK_NEVER;
         break;

      case PNG_HANDLE_CHUNK_IF_SAFE:
         keep = PNG_HANDLE_CHUNK_IF_SAFE;
         break;

      case PNG_HANDLE_CHUNK_ALWAYS:
         keep = PNG_HANDLE_CHUNK_ALWAYS;
         break;


      default:
         png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
         return;
   }

1197
   if (num_chunksIn <= 0)
1198
   {
1199
      if (keep == PNG_HANDLE_CHUNK_ALWAYS || keep == PNG_HANDLE_CHUNK_IF_SAFE)
1200
         png_ptr->flags |= PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
1201

1202
      else
1203
         png_ptr->flags &= ~PNG_FLAG_KEEP_UNKNOWN_CHUNKS;
1204

1205
      if (keep == PNG_HANDLE_CHUNK_ALWAYS)
1206
         png_ptr->flags |= PNG_FLAG_KEEP_UNSAFE_CHUNKS;
1207

1208
      else
1209
         png_ptr->flags &= ~PNG_FLAG_KEEP_UNSAFE_CHUNKS;
1210

1211 1212
      if (num_chunksIn == 0)
        return;
1213
   }
1214

1215
   if (num_chunksIn < 0)
1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242
   {
      /* 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;
   }
1243

1244 1245 1246 1247 1248 1249 1250
   else /* num_chunksIn > 0 */
   {
      if (chunk_list == NULL)
         return;

      num_chunks = num_chunksIn;
   }
1251

1252
   old_num_chunks = png_ptr->num_chunk_list;
1253 1254 1255 1256 1257 1258 1259 1260 1261

   /* 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;
   }

1262 1263
   new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
       5 * (num_chunks + old_num_chunks)));
1264

1265 1266
   if (png_ptr->chunk_list != NULL)
   {
1267
      memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1268 1269 1270
      png_free(png_ptr, png_ptr->chunk_list);
      png_ptr->chunk_list=NULL;
   }
1271

1272
   memcpy(new_list + 5*old_num_chunks, chunk_list, 5*num_chunks);
1273

1274
   for (p = new_list + 5*old_num_chunks + 4, i = 0; i<num_chunks; i++, p += 5)
1275
      *p=keep;
1276

1277 1278 1279
   png_ptr->num_chunk_list = old_num_chunks + num_chunks;
   png_ptr->chunk_list = new_list;
   png_ptr->free_me |= PNG_FREE_LIST;
1280 1281
}
#endif
1282

1283
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1284
void PNGAPI
1285
png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
1286
    png_user_chunk_ptr read_user_chunk_fn)
1287
{
1288
   png_debug(1, "in png_set_read_user_chunk_fn");
1289

1290 1291
   if (png_ptr == NULL)
      return;
1292

1293 1294 1295 1296
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
   png_ptr->user_chunk_ptr = user_chunk_ptr;
}
#endif
1297

1298
#ifdef PNG_INFO_IMAGE_SUPPORTED
1299
void PNGAPI
1300 1301
png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
    png_bytepp row_pointers)
1302
{
1303
   png_debug1(1, "in %s storage function", "rows");
1304

1305 1306 1307
   if (png_ptr == NULL || info_ptr == NULL)
      return;

1308
   if (info_ptr->row_pointers && (info_ptr->row_pointers != row_pointers))
1309
      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1310

1311
   info_ptr->row_pointers = row_pointers;
1312

1313
   if (row_pointers)
1314
      info_ptr->valid |= PNG_INFO_IDAT;
1315 1316 1317
}
#endif

1318
void PNGAPI
1319
png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
1320
{
1321 1322
    if (png_ptr == NULL)
       return;
1323

1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
    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

1335
#  ifdef PNG_WRITE_SUPPORTED
1336 1337 1338 1339 1340 1341 1342 1343
      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;
         }
1344

1345 1346 1347 1348 1349 1350
         if (size > ZLIB_IO_MAX)
         {
            png_warning(png_ptr,
               "Compression buffer size limited to system maximum");
            size = ZLIB_IO_MAX; /* must fit */
         }
1351

1352 1353 1354 1355 1356 1357 1358 1359 1360
         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;
         }
1361

1362 1363 1364 1365 1366 1367 1368
         if (png_ptr->zbuffer_size != size)
         {
            png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
            png_ptr->zbuffer_size = (uInt)size;
         }
      }
#  endif
1369
}
1370 1371

void PNGAPI
1372
png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
1373 1374
{
   if (png_ptr && info_ptr)
1375
      info_ptr->valid &= ~mask;
1376
}
1377

1378

1379
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1380
/* This function was added to libpng 1.2.6 */
1381
void PNGAPI
1382
png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
1383 1384
    png_uint_32 user_height_max)
{
1385 1386 1387 1388 1389 1390
   /* 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;
1391

1392 1393
   png_ptr->user_width_max = user_width_max;
   png_ptr->user_height_max = user_height_max;
1394
}
1395

1396
/* This function was added to libpng 1.4.0 */
1397
void PNGAPI
1398
png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
1399
{
1400 1401 1402 1403 1404 1405
    if (png_ptr)
       png_ptr->user_chunk_cache_max = user_chunk_cache_max;
}

/* This function was added to libpng 1.4.1 */
void PNGAPI
1406
png_set_chunk_malloc_max (png_structrp png_ptr,
1407
    png_alloc_size_t user_chunk_malloc_max)
1408
{
1409 1410
   if (png_ptr)
      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
1411
}
1412 1413
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */

1414

1415
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
1416
void PNGAPI
1417
png_set_benign_errors(png_structrp png_ptr, int allowed)
1418
{
1419
   png_debug(1, "in png_set_benign_errors");
1420

1421 1422 1423 1424 1425 1426
   /* 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).
    */

1427
   if (allowed)
1428 1429
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
1430

1431
   else
1432 1433
      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
1434 1435
}
#endif /* PNG_BENIGN_ERRORS_SUPPORTED */
1436

1437
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
1438 1439 1440 1441 1442 1443
   /* 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");

1444
   if (allowed > 0)
1445 1446 1447 1448 1449 1450 1451
      png_ptr->num_palette_max = 0;

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

1452
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */