pngset.c 45.9 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.15 [(PENDING RELEASE)]
5
 * Copyright (c) 1998-2014 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
   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,
62
       2/* override with app values*/) != 0)
63 64 65
      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 92
   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;

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

   png_colorspace_sync_info(png_ptr, info_ptr);
98 99
}

100
#  ifdef PNG_FLOATING_POINT_SUPPORTED
101
void PNGAPI
102
png_set_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
G
[devel]  
Glenn Randers-Pehrson 已提交
103 104
    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 已提交
105
{
G
[devel]  
Glenn Randers-Pehrson 已提交
106 107 108 109 110 111 112 113 114 115
   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"));
}
116 117

void PNGAPI
118
png_set_cHRM_XYZ(png_const_structrp png_ptr, png_inforp info_ptr, double red_X,
119 120 121 122 123 124 125 126 127 128 129 130 131 132
    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"));
}
133
#  endif /* PNG_FLOATING_POINT_SUPPORTED */
134

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

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

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

147 148
   png_colorspace_set_gamma(png_ptr, &info_ptr->colorspace, file_gamma);
   png_colorspace_sync_info(png_ptr, info_ptr);
G
[devel]  
Glenn Randers-Pehrson 已提交
149
}
150

151
#  ifdef PNG_FLOATING_POINT_SUPPORTED
G
[devel]  
Glenn Randers-Pehrson 已提交
152
void PNGAPI
153
png_set_gAMA(png_const_structrp png_ptr, png_inforp info_ptr, double file_gamma)
G
[devel]  
Glenn Randers-Pehrson 已提交
154 155
{
   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
156
       "png_set_gAMA"));
A
Andreas Dilger 已提交
157
}
158
#  endif
159
#endif
A
Andreas Dilger 已提交
160

161
#ifdef PNG_hIST_SUPPORTED
162
void PNGAPI
163 164
png_set_hIST(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_uint_16p hist)
A
Andreas Dilger 已提交
165
{
166
   int i;
167

168
   png_debug1(1, "in %s storage function", "hIST");
169

170
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
171
      return;
172

173
   if (info_ptr->num_palette == 0 || info_ptr->num_palette
174
       > PNG_MAX_PALETTE_LENGTH)
175
   {
176
      png_warning(png_ptr,
177
          "Invalid palette size, hIST allocation skipped");
178

179
      return;
180
   }
181 182

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

184 185 186
   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
    * version 1.2.1
    */
187
   info_ptr->hist = png_voidcast(png_uint_16p, png_malloc_warn(png_ptr,
188
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
189

190
   if (info_ptr->hist == NULL)
191 192 193 194
   {
      png_warning(png_ptr, "Insufficient memory for hIST chunk data");
      return;
   }
A
Andreas Dilger 已提交
195

196 197
   info_ptr->free_me |= PNG_FREE_HIST;

198
   for (i = 0; i < info_ptr->num_palette; i++)
199
      info_ptr->hist[i] = hist[i];
200

A
Andreas Dilger 已提交
201 202 203 204
   info_ptr->valid |= PNG_INFO_hIST;
}
#endif

205
void PNGAPI
206
png_set_IHDR(png_const_structrp png_ptr, png_inforp info_ptr,
207 208 209
    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 已提交
210
{
211
   png_debug1(1, "in %s storage function", "IHDR");
212

213
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
214 215 216 217 218
      return;

   info_ptr->width = width;
   info_ptr->height = height;
   info_ptr->bit_depth = (png_byte)bit_depth;
219
   info_ptr->color_type = (png_byte)color_type;
A
Andreas Dilger 已提交
220 221 222
   info_ptr->compression_type = (png_byte)compression_type;
   info_ptr->filter_type = (png_byte)filter_type;
   info_ptr->interlace_type = (png_byte)interlace_type;
223 224 225 226 227

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

228 229
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
      info_ptr->channels = 1;
230

231
   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
A
Andreas Dilger 已提交
232
      info_ptr->channels = 3;
233

A
Andreas Dilger 已提交
234 235
   else
      info_ptr->channels = 1;
236

237
   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
A
Andreas Dilger 已提交
238
      info_ptr->channels++;
239

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

242
   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
A
Andreas Dilger 已提交
243 244
}

245
#ifdef PNG_oFFs_SUPPORTED
246
void PNGAPI
247
png_set_oFFs(png_const_structrp png_ptr, png_inforp info_ptr,
248
    png_int_32 offset_x, png_int_32 offset_y, int unit_type)
A
Andreas Dilger 已提交
249
{
250
   png_debug1(1, "in %s storage function", "oFFs");
251

252
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
253 254 255 256 257 258 259 260 261
      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

262
#ifdef PNG_pCAL_SUPPORTED
263
void PNGAPI
264
png_set_pCAL(png_const_structrp png_ptr, png_inforp info_ptr,
265 266
    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 已提交
267
{
268
   png_size_t length;
269
   int i;
A
Andreas Dilger 已提交
270

271
   png_debug1(1, "in %s storage function", "pCAL");
272

273 274
   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
      || (nparams > 0 && params == NULL))
A
Andreas Dilger 已提交
275 276
      return;

277
   length = strlen(purpose) + 1;
278
   png_debug1(3, "allocating purpose for info (%lu bytes)",
279
       (unsigned long)length);
280

G
[devel]  
Glenn Randers-Pehrson 已提交
281 282 283 284 285 286
   /* 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");

287 288 289
   if (nparams < 0 || nparams > 255)
      png_error(png_ptr, "Invalid pCAL parameter count");

G
[devel]  
Glenn Randers-Pehrson 已提交
290 291
   /* Validate params[nparams] */
   for (i=0; i<nparams; ++i)
292
   {
293
      if (params[i] == NULL ||
294
          !png_check_fp_string(params[i], strlen(params[i])))
G
[devel]  
Glenn Randers-Pehrson 已提交
295
         png_error(png_ptr, "Invalid format for pCAL parameter");
296
   }
G
[devel]  
Glenn Randers-Pehrson 已提交
297

298
   info_ptr->pcal_purpose = png_voidcast(png_charp,
299
       png_malloc_warn(png_ptr, length));
300

301
   if (info_ptr->pcal_purpose == NULL)
302
   {
303
      png_warning(png_ptr, "Insufficient memory for pCAL purpose");
304 305
      return;
   }
306

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

309
   png_debug(3, "storing X0, X1, type, and nparams in info");
A
Andreas Dilger 已提交
310 311 312 313 314
   info_ptr->pcal_X0 = X0;
   info_ptr->pcal_X1 = X1;
   info_ptr->pcal_type = (png_byte)type;
   info_ptr->pcal_nparams = (png_byte)nparams;

315
   length = strlen(units) + 1;
316
   png_debug1(3, "allocating units for info (%lu bytes)",
317
     (unsigned long)length);
318

319 320
   info_ptr->pcal_units = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, length));
321

322
   if (info_ptr->pcal_units == NULL)
323
   {
324
      png_warning(png_ptr, "Insufficient memory for pCAL units");
325 326
      return;
   }
327

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

330
   info_ptr->pcal_params = png_voidcast(png_charpp, png_malloc_warn(png_ptr,
331
       (png_size_t)((nparams + 1) * (sizeof (png_charp)))));
332

333
   if (info_ptr->pcal_params == NULL)
334
   {
335
      png_warning(png_ptr, "Insufficient memory for pCAL params");
336 337
      return;
   }
338

339
   memset(info_ptr->pcal_params, 0, (nparams + 1) * (sizeof (png_charp)));
A
Andreas Dilger 已提交
340 341 342

   for (i = 0; i < nparams; i++)
   {
343
      length = strlen(params[i]) + 1;
344
      png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
345
          (unsigned long)length);
346

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

349
      if (info_ptr->pcal_params[i] == NULL)
350
      {
351 352
         png_warning(png_ptr, "Insufficient memory for pCAL parameter");
         return;
353
      }
354

355
      memcpy(info_ptr->pcal_params[i], params[i], length);
A
Andreas Dilger 已提交
356 357 358
   }

   info_ptr->valid |= PNG_INFO_pCAL;
359
   info_ptr->free_me |= PNG_FREE_PCAL;
A
Andreas Dilger 已提交
360 361 362
}
#endif

363
#ifdef PNG_sCAL_SUPPORTED
364
void PNGAPI
365
png_set_sCAL_s(png_const_structrp png_ptr, png_inforp info_ptr,
366
    int unit, png_const_charp swidth, png_const_charp sheight)
367
{
368
   png_size_t lengthw = 0, lengthh = 0;
369

370
   png_debug1(1, "in %s storage function", "sCAL");
371

372 373 374
   if (png_ptr == NULL || info_ptr == NULL)
      return;

G
[devel]  
Glenn Randers-Pehrson 已提交
375 376 377 378 379 380
   /* 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");

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

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

389
   info_ptr->scal_unit = (png_byte)unit;
390

G
[devel]  
Glenn Randers-Pehrson 已提交
391
   ++lengthw;
392

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

395 396
   info_ptr->scal_s_width = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, lengthw));
397

398 399
   if (info_ptr->scal_s_width == NULL)
   {
G
[devel]  
Glenn Randers-Pehrson 已提交
400
      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
401
      return;
402
   }
403

404
   memcpy(info_ptr->scal_s_width, swidth, lengthw);
405

G
[devel]  
Glenn Randers-Pehrson 已提交
406
   ++lengthh;
407

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

410 411
   info_ptr->scal_s_height = png_voidcast(png_charp,
      png_malloc_warn(png_ptr, lengthh));
412

413 414 415
   if (info_ptr->scal_s_height == NULL)
   {
      png_free (png_ptr, info_ptr->scal_s_width);
416
      info_ptr->scal_s_width = NULL;
417

G
[devel]  
Glenn Randers-Pehrson 已提交
418
      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
419
      return;
420
   }
421

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

424
   info_ptr->valid |= PNG_INFO_sCAL;
425
   info_ptr->free_me |= PNG_FREE_SCAL;
426
}
G
[devel]  
Glenn Randers-Pehrson 已提交
427

428
#  ifdef PNG_FLOATING_POINT_SUPPORTED
G
[devel]  
Glenn Randers-Pehrson 已提交
429
void PNGAPI
430 431
png_set_sCAL(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
    double width, double height)
G
[devel]  
Glenn Randers-Pehrson 已提交
432 433 434 435 436 437
{
   png_debug1(1, "in %s storage function", "sCAL");

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

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

G
[devel]  
Glenn Randers-Pehrson 已提交
442 443 444 445 446 447
   else
   {
      /* Convert 'width' and 'height' to ASCII. */
      char swidth[PNG_sCAL_MAX_DIGITS+1];
      char sheight[PNG_sCAL_MAX_DIGITS+1];

448
      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
G
[devel]  
Glenn Randers-Pehrson 已提交
449
         PNG_sCAL_PRECISION);
450
      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
G
[devel]  
Glenn Randers-Pehrson 已提交
451 452 453 454 455
         PNG_sCAL_PRECISION);

      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   }
}
456
#  endif
457

458
#  ifdef PNG_FIXED_POINT_SUPPORTED
459
void PNGAPI
460
png_set_sCAL_fixed(png_const_structrp png_ptr, png_inforp info_ptr, int unit,
461
    png_fixed_point width, png_fixed_point height)
462 463 464 465 466 467
{
   png_debug1(1, "in %s storage function", "sCAL");

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

469 470
   else if (height <= 0)
      png_warning(png_ptr, "Invalid sCAL height ignored");
471

472 473 474 475 476 477
   else
   {
      /* Convert 'width' and 'height' to ASCII. */
      char swidth[PNG_sCAL_MAX_DIGITS+1];
      char sheight[PNG_sCAL_MAX_DIGITS+1];

478 479
      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
480 481 482 483

      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
   }
}
484
#  endif
485
#endif
486

487
#ifdef PNG_pHYs_SUPPORTED
488
void PNGAPI
489
png_set_pHYs(png_const_structrp png_ptr, png_inforp info_ptr,
490
    png_uint_32 res_x, png_uint_32 res_y, int unit_type)
A
Andreas Dilger 已提交
491
{
492
   png_debug1(1, "in %s storage function", "pHYs");
493

494
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
495 496 497 498 499 500 501 502 503
      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

504
void PNGAPI
505
png_set_PLTE(png_structrp png_ptr, png_inforp info_ptr,
506
    png_const_colorp palette, int num_palette)
A
Andreas Dilger 已提交
507
{
508

509
   png_debug1(1, "in %s storage function", "PLTE");
510

511
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
512 513
      return;

514
   if (num_palette < 0 || num_palette > PNG_MAX_PALETTE_LENGTH)
515 516
   {
      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
517
         png_error(png_ptr, "Invalid palette length");
518

519 520
      else
      {
521 522
         png_warning(png_ptr, "Invalid palette length");
         return;
523 524
      }
   }
525

526 527 528 529 530 531 532
   if ((num_palette > 0 && palette == NULL) ||
      (num_palette == 0
#        ifdef PNG_MNG_FEATURES_SUPPORTED
            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
#        endif
      ))
   {
533
      png_error(png_ptr, "Invalid palette");
534 535 536
      return;
   }

537
   /* It may not actually be necessary to set png_ptr->palette here;
538 539
    * we do it for backward compatibility with the way the png_handle_tRNS
    * function used to do the allocation.
540 541 542
    *
    * 1.6.0: the above statement appears to be incorrect; something has to set
    * the palette inside png_struct on read.
543 544
    */
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
545

546
   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
547 548 549
    * of num_palette entries, in case of an invalid PNG file that has
    * too-large sample values.
    */
550
   png_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
551
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
552

553 554
   if (num_palette > 0)
      memcpy(png_ptr->palette, palette, num_palette * (sizeof (png_color)));
555 556 557 558
   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;
559

560
   info_ptr->valid |= PNG_INFO_PLTE;
A
Andreas Dilger 已提交
561 562
}

563
#ifdef PNG_sBIT_SUPPORTED
564
void PNGAPI
565
png_set_sBIT(png_const_structrp png_ptr, png_inforp info_ptr,
566
    png_const_color_8p sig_bit)
A
Andreas Dilger 已提交
567
{
568
   png_debug1(1, "in %s storage function", "sBIT");
569

570
   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
A
Andreas Dilger 已提交
571 572
      return;

573
   info_ptr->sig_bit = *sig_bit;
A
Andreas Dilger 已提交
574 575 576 577
   info_ptr->valid |= PNG_INFO_sBIT;
}
#endif

578
#ifdef PNG_sRGB_SUPPORTED
579
void PNGAPI
580
png_set_sRGB(png_const_structrp png_ptr, png_inforp info_ptr, int srgb_intent)
581
{
582
   png_debug1(1, "in %s storage function", "sRGB");
583

584
   if (png_ptr == NULL || info_ptr == NULL)
585 586
      return;

587 588
   (void)png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace, srgb_intent);
   png_colorspace_sync_info(png_ptr, info_ptr);
589
}
590

591
void PNGAPI
592
png_set_sRGB_gAMA_and_cHRM(png_const_structrp png_ptr, png_inforp info_ptr,
593
    int srgb_intent)
594
{
595
   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
596

597
   if (png_ptr == NULL || info_ptr == NULL)
598 599
      return;

600 601
   if (png_colorspace_set_sRGB(png_ptr, &info_ptr->colorspace,
       srgb_intent) != 0)
602 603 604 605 606
   {
      /* This causes the gAMA and cHRM to be written too */
      info_ptr->colorspace.flags |=
         PNG_COLORSPACE_FROM_gAMA|PNG_COLORSPACE_FROM_cHRM;
   }
607

608
   png_colorspace_sync_info(png_ptr, info_ptr);
609
}
610
#endif /* sRGB */
611

612

613
#ifdef PNG_iCCP_SUPPORTED
614
void PNGAPI
615
png_set_iCCP(png_const_structrp png_ptr, png_inforp info_ptr,
616 617
    png_const_charp name, int compression_type,
    png_const_bytep profile, png_uint_32 proflen)
618
{
619
   png_charp new_iccp_name;
G
[devel]  
Glenn Randers-Pehrson 已提交
620
   png_bytep new_iccp_profile;
621
   png_size_t length;
622

623
   png_debug1(1, "in %s storage function", "iCCP");
624

625 626 627
   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
      return;

628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
   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.)  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.
    */
   {
      int result = png_colorspace_set_ICC(png_ptr, &info_ptr->colorspace, name,
         proflen, profile, info_ptr->color_type);

      png_colorspace_sync_info(png_ptr, info_ptr);

      /* Don't do any of the copying if the profile was bad, or inconsistent. */
644
      if (result == 0)
645 646 647 648 649 650 651 652
         return;

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

   length = strlen(name)+1;
653
   new_iccp_name = png_voidcast(png_charp, png_malloc_warn(png_ptr, length));
654

655 656
   if (new_iccp_name == NULL)
   {
657
      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
658 659
      return;
   }
660

661
   memcpy(new_iccp_name, name, length);
662 663
   new_iccp_profile = png_voidcast(png_bytep,
      png_malloc_warn(png_ptr, proflen));
664

665 666
   if (new_iccp_profile == NULL)
   {
667
      png_free(png_ptr, new_iccp_name);
668
      new_iccp_name = NULL;
669
      png_benign_error(png_ptr,
670
          "Insufficient memory to process iCCP profile");
671 672
      return;
   }
673

674
   memcpy(new_iccp_profile, profile, proflen);
675

676
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
677

678
   info_ptr->iccp_proflen = proflen;
679 680
   info_ptr->iccp_name = new_iccp_name;
   info_ptr->iccp_profile = new_iccp_profile;
681
   info_ptr->free_me |= PNG_FREE_ICCP;
682 683 684 685
   info_ptr->valid |= PNG_INFO_iCCP;
}
#endif

686
#ifdef PNG_TEXT_SUPPORTED
687
void PNGAPI
688 689
png_set_text(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_textp text_ptr, int num_text)
690 691
{
   int ret;
692
   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
693

694
   if (ret != 0)
695
      png_error(png_ptr, "Insufficient memory to store text");
696 697 698
}

int /* PRIVATE */
699
png_set_text_2(png_const_structrp png_ptr, png_inforp info_ptr,
700
    png_const_textp text_ptr, int num_text)
A
Andreas Dilger 已提交
701 702 703
{
   int i;

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

707
   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
708
      return(0);
A
Andreas Dilger 已提交
709 710

   /* Make sure we have enough space in the "text" array in info_struct
711 712 713
    * to hold all of the incoming text_ptr objects.  This compare can't overflow
    * because max_text >= num_text (anyway, subtract of two positive integers
    * can't overflow in any case.)
A
Andreas Dilger 已提交
714
    */
715
   if (num_text > info_ptr->max_text - info_ptr->num_text)
A
Andreas Dilger 已提交
716
   {
717 718 719 720 721 722 723
      int old_num_text = info_ptr->num_text;
      int max_text;
      png_textp new_text = NULL;

      /* Calculate an appropriate max_text, checking for overflow. */
      max_text = old_num_text;
      if (num_text <= INT_MAX - max_text)
A
Andreas Dilger 已提交
724
      {
725
         max_text += num_text;
726

727 728 729
         /* Round up to a multiple of 8 */
         if (max_text < INT_MAX-8)
            max_text = (max_text + 8) & ~0x7;
730

731 732 733
         else
            max_text = INT_MAX;

734
         /* Now allocate a new array and copy the old members in; this does all
735 736 737 738 739
          * the overflow checks.
          */
         new_text = png_voidcast(png_textp,png_realloc_array(png_ptr,
            info_ptr->text, old_num_text, max_text-old_num_text,
            sizeof *new_text));
A
Andreas Dilger 已提交
740
      }
741

742
      if (new_text == NULL)
A
Andreas Dilger 已提交
743
      {
744 745 746
         png_chunk_report(png_ptr, "too many text chunks",
            PNG_CHUNK_WRITE_ERROR);
         return 1;
A
Andreas Dilger 已提交
747
      }
748

749 750 751 752 753 754 755 756
      png_free(png_ptr, info_ptr->text);

      info_ptr->text = new_text;
      info_ptr->free_me |= PNG_FREE_TEXT;
      info_ptr->max_text = max_text;
      /* num_text is adjusted below as the entries are copied in */

      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
A
Andreas Dilger 已提交
757
   }
758

A
Andreas Dilger 已提交
759 760
   for (i = 0; i < num_text; i++)
   {
761 762
      size_t text_length, key_len;
      size_t lang_len, lang_key_len;
A
Andreas Dilger 已提交
763 764
      png_textp textp = &(info_ptr->text[info_ptr->num_text]);

765
      if (text_ptr[i].key == NULL)
766 767
          continue;

768 769
      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
770
      {
771 772
         png_chunk_report(png_ptr, "text compression mode is out of range",
            PNG_CHUNK_WRITE_ERROR);
773 774 775
         continue;
      }

776
      key_len = strlen(text_ptr[i].key);
777

778
      if (text_ptr[i].compression <= 0)
779
      {
780 781
         lang_len = 0;
         lang_key_len = 0;
782
      }
783

784
      else
785
#  ifdef PNG_iTXt_SUPPORTED
786
      {
787
         /* Set iTXt data */
788

789
         if (text_ptr[i].lang != NULL)
790
            lang_len = strlen(text_ptr[i].lang);
791

792 793
         else
            lang_len = 0;
794

795
         if (text_ptr[i].lang_key != NULL)
796
            lang_key_len = strlen(text_ptr[i].lang_key);
797

798 799
         else
            lang_key_len = 0;
800
      }
801
#  else /* PNG_iTXt_SUPPORTED */
802
      {
803 804
         png_chunk_report(png_ptr, "iTXt chunk not supported",
            PNG_CHUNK_WRITE_ERROR);
805
         continue;
806
      }
807
#  endif
A
Andreas Dilger 已提交
808

809
      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
A
Andreas Dilger 已提交
810
      {
811
         text_length = 0;
812
#  ifdef PNG_iTXt_SUPPORTED
813
         if (text_ptr[i].compression > 0)
814
            textp->compression = PNG_ITXT_COMPRESSION_NONE;
815

816
         else
817
#  endif
818
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
A
Andreas Dilger 已提交
819
      }
820

A
Andreas Dilger 已提交
821 822
      else
      {
823
         text_length = strlen(text_ptr[i].text);
A
Andreas Dilger 已提交
824 825
         textp->compression = text_ptr[i].compression;
      }
826

827 828
      textp->key = png_voidcast(png_charp,png_malloc_base(png_ptr,
          key_len + text_length + lang_len + lang_key_len + 4));
829

830
      if (textp->key == NULL)
831 832 833 834 835
      {
         png_chunk_report(png_ptr, "text chunk: out of memory",
               PNG_CHUNK_WRITE_ERROR);
         return 1;
      }
836

837
      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
838 839
          (unsigned long)(png_uint_32)
          (key_len + lang_len + lang_key_len + text_length + 4),
840
          textp->key);
841

842
      memcpy(textp->key, text_ptr[i].key, key_len);
843
      *(textp->key + key_len) = '\0';
844

845 846
      if (text_ptr[i].compression > 0)
      {
847
         textp->lang = textp->key + key_len + 1;
848
         memcpy(textp->lang, text_ptr[i].lang, lang_len);
849
         *(textp->lang + lang_len) = '\0';
850
         textp->lang_key = textp->lang + lang_len + 1;
851
         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
852
         *(textp->lang_key + lang_key_len) = '\0';
853
         textp->text = textp->lang_key + lang_key_len + 1;
854
      }
855

856 857
      else
      {
858 859
         textp->lang=NULL;
         textp->lang_key=NULL;
860
         textp->text = textp->key + key_len + 1;
861
      }
862

863
      if (text_length != 0)
864
         memcpy(textp->text, text_ptr[i].text, text_length);
865

866
      *(textp->text + text_length) = '\0';
867

868
#  ifdef PNG_iTXt_SUPPORTED
869
      if (textp->compression > 0)
870 871 872 873
      {
         textp->text_length = 0;
         textp->itxt_length = text_length;
      }
874

875
      else
876
#  endif
877 878 879 880
      {
         textp->text_length = text_length;
         textp->itxt_length = 0;
      }
881

A
Andreas Dilger 已提交
882
      info_ptr->num_text++;
883
      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
A
Andreas Dilger 已提交
884
   }
885

886
   return(0);
A
Andreas Dilger 已提交
887 888 889
}
#endif

890
#ifdef PNG_tIME_SUPPORTED
891
void PNGAPI
892 893
png_set_tIME(png_const_structrp png_ptr, png_inforp info_ptr,
    png_const_timep mod_time)
A
Andreas Dilger 已提交
894
{
895
   png_debug1(1, "in %s storage function", "tIME");
896

897
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
898
       (png_ptr->mode & PNG_WROTE_tIME) != 0)
A
Andreas Dilger 已提交
899 900
      return;

901 902 903 904 905 906 907 908 909
   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;
   }

910
   info_ptr->mod_time = *mod_time;
A
Andreas Dilger 已提交
911 912 913 914
   info_ptr->valid |= PNG_INFO_tIME;
}
#endif

915
#ifdef PNG_tRNS_SUPPORTED
916
void PNGAPI
917
png_set_tRNS(png_structrp png_ptr, png_inforp info_ptr,
918
    png_const_bytep trans_alpha, int num_trans, png_const_color_16p trans_color)
A
Andreas Dilger 已提交
919
{
920
   png_debug1(1, "in %s storage function", "tRNS");
921

922
   if (png_ptr == NULL || info_ptr == NULL)
A
Andreas Dilger 已提交
923 924
      return;

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

936
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
937

938
       /* Changed from num_trans to PNG_MAX_PALETTE_LENGTH in version 1.2.1 */
939 940
       png_ptr->trans_alpha = info_ptr->trans_alpha = png_voidcast(png_bytep,
         png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
941

942
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
943
          memcpy(info_ptr->trans_alpha, trans_alpha, (png_size_t)num_trans);
944
   }
A
Andreas Dilger 已提交
945

946
   if (trans_color != NULL)
A
Andreas Dilger 已提交
947
   {
948
      int sample_max = (1 << info_ptr->bit_depth);
949

950
      if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
951
          trans_color->gray > sample_max) ||
952
          (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
953 954 955
          (trans_color->red > sample_max ||
          trans_color->green > sample_max ||
          trans_color->blue > sample_max)))
956 957
         png_warning(png_ptr,
            "tRNS chunk has out-of-range samples for bit_depth");
958

959
      info_ptr->trans_color = *trans_color;
960

961
      if (num_trans == 0)
962
         num_trans = 1;
A
Andreas Dilger 已提交
963
   }
964

A
Andreas Dilger 已提交
965
   info_ptr->num_trans = (png_uint_16)num_trans;
966

967 968 969 970 971
   if (num_trans != 0)
   {
      info_ptr->valid |= PNG_INFO_tRNS;
      info_ptr->free_me |= PNG_FREE_TRNS;
   }
A
Andreas Dilger 已提交
972 973 974
}
#endif

975
#ifdef PNG_sPLT_SUPPORTED
976
void PNGAPI
977
png_set_sPLT(png_const_structrp png_ptr,
978
    png_inforp info_ptr, png_const_sPLT_tp entries, int nentries)
979 980 981 982
/*
 *  entries        - array of png_sPLT_t structures
 *                   to be added to the list of palettes
 *                   in the info structure.
983
 *
984 985 986
 *  nentries       - number of palette structures to be
 *                   added.
 */
987
{
988
   png_sPLT_tp np;
989

990
   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
991
      return;
992

993 994 995 996 997 998
   /* Use the internal realloc function, which checks for all the possible
    * overflows.  Notice that the parameters are (int) and (size_t)
    */
   np = png_voidcast(png_sPLT_tp,png_realloc_array(png_ptr,
      info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
      sizeof *np));
999

1000 1001
   if (np == NULL)
   {
1002 1003
      /* Out of memory or too many chunks */
      png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
1004
      return;
1005
   }
1006

1007
   png_free(png_ptr, info_ptr->splt_palettes);
1008 1009
   info_ptr->splt_palettes = np;
   info_ptr->free_me |= PNG_FREE_SPLT;
1010

1011 1012 1013
   np += info_ptr->splt_palettes_num;

   do
1014
   {
1015
      png_size_t length;
1016

1017 1018
      /* Skip invalid input entries */
      if (entries->name == NULL || entries->entries == NULL)
1019
      {
1020 1021 1022
         /* png_handle_sPLT doesn't do this, so this is an app error */
         png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
         /* Just skip the invalid entry */
1023
         continue;
1024
      }
1025

1026 1027
      np->depth = entries->depth;

1028 1029
      /* In the event of out-of-memory just return - there's no point keeping
       * on trying to add sPLT chunks.
1030 1031 1032 1033 1034 1035
       */
      length = strlen(entries->name) + 1;
      np->name = png_voidcast(png_charp, png_malloc_base(png_ptr, length));

      if (np->name == NULL)
         break;
1036

1037 1038 1039
      memcpy(np->name, entries->name, length);

      /* IMPORTANT: we have memory now that won't get freed if something else
1040 1041
       * goes wrong; this code must free it.  png_malloc_array produces no
       * warnings; use a png_chunk_report (below) if there is an error.
1042 1043 1044 1045 1046
       */
      np->entries = png_voidcast(png_sPLT_entryp, png_malloc_array(png_ptr,
          entries->nentries, sizeof (png_sPLT_entry)));

      if (np->entries == NULL)
1047
      {
1048
         png_free(png_ptr, np->name);
1049
         np->name = NULL;
1050
         break;
1051
      }
1052

1053 1054 1055 1056 1057 1058
      np->nentries = entries->nentries;
      /* This multiply can't overflow because png_malloc_array has already
       * checked it when doing the allocation.
       */
      memcpy(np->entries, entries->entries,
         entries->nentries * sizeof (png_sPLT_entry));
1059

1060 1061 1062 1063 1064 1065
      /* Note that 'continue' skips the advance of the out pointer and out
       * count, so an invalid entry is not added.
       */
      info_ptr->valid |= PNG_INFO_sPLT;
      ++(info_ptr->splt_palettes_num);
      ++np;
1066
   }
1067
   while (++entries, --nentries);
1068

1069 1070
   if (nentries > 0)
      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
1071
}
1072
#endif /* PNG_sPLT_SUPPORTED */
1073

1074 1075 1076 1077 1078 1079 1080
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
static png_byte
check_location(png_const_structrp png_ptr, 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
1081
    * change; previously the app had to use the
1082 1083
    * png_set_unknown_chunk_location API below for each chunk.
    */
1084
   if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111
   {
      /* 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_byte)(png_ptr->mode &
         (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
   }

   /* This need not be an internal error - if the app calls
    * png_set_unknown_chunks on a read pointer it must get the location right.
    */
   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 &= ~(location & -location);

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

1112
void PNGAPI
1113
png_set_unknown_chunks(png_const_structrp png_ptr,
1114
   png_inforp info_ptr, png_const_unknown_chunkp unknowns, int num_unknowns)
1115
{
1116 1117
   png_unknown_chunkp np;

1118 1119
   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
      unknowns == NULL)
1120
      return;
1121

1122 1123 1124 1125 1126 1127 1128 1129
   /* 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)
1130
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1131 1132 1133 1134 1135 1136 1137
      {
         png_app_error(png_ptr, "no unknown chunk support on read");
         return;
      }
#  endif
#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
      defined(PNG_WRITE_SUPPORTED)
1138
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152
      {
         png_app_error(png_ptr, "no unknown chunk support on write");
         return;
      }
#  endif

   /* 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.  Now png_chunk_report is used to provide behavior
    * appropriate to read or write.
    */
   np = png_voidcast(png_unknown_chunkp, png_realloc_array(png_ptr,
         info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
         sizeof *np));
1153 1154 1155

   if (np == NULL)
   {
1156 1157
      png_chunk_report(png_ptr, "too many unknown chunks",
         PNG_CHUNK_WRITE_ERROR);
1158 1159 1160
      return;
   }

1161
   png_free(png_ptr, info_ptr->unknown_chunks);
1162 1163
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
   info_ptr->free_me |= PNG_FREE_UNKN;
1164

1165
   np += info_ptr->unknown_chunks_num;
1166

1167 1168 1169 1170 1171 1172 1173 1174
   /* Increment unknown_chunks_num each time round the loop to protect the
    * just-allocated chunk data.
    */
   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
   {
      memcpy(np->name, unknowns->name, (sizeof np->name));
      np->name[(sizeof np->name)-1] = '\0';
      np->location = check_location(png_ptr, unknowns->location);
1175

1176 1177 1178 1179 1180
      if (unknowns->size == 0)
      {
         np->data = NULL;
         np->size = 0;
      }
1181

1182 1183
      else
      {
1184 1185
         np->data = png_voidcast(png_bytep,
            png_malloc_base(png_ptr, unknowns->size));
1186

1187
         if (np->data == NULL)
1188
         {
1189 1190 1191 1192
            png_chunk_report(png_ptr, "unknown chunk: out of memory",
               PNG_CHUNK_WRITE_ERROR);
            /* But just skip storing the unknown chunk */
            continue;
1193 1194
         }

1195 1196
         memcpy(np->data, unknowns->data, unknowns->size);
         np->size = unknowns->size;
1197
      }
1198

1199 1200 1201 1202 1203 1204 1205
      /* These increments are skipped on out-of-memory for the data - the
       * unknown chunk entry gets overwritten if the png_chunk_report returns.
       * This is correct in the read case (the chunk is just dropped.)
       */
      ++np;
      ++(info_ptr->unknown_chunks_num);
   }
1206
}
1207

1208
void PNGAPI
1209
png_set_unknown_chunk_location(png_const_structrp png_ptr, png_inforp info_ptr,
1210
    int chunk, int location)
1211
{
1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223
   /* 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 &&
      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: */
1224
         if ((location & PNG_HAVE_IDAT) != 0) /* undocumented! */
1225 1226 1227 1228 1229 1230 1231 1232 1233
            location = PNG_AFTER_IDAT;

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

      info_ptr->unknown_chunks[chunk].location =
         check_location(png_ptr, location);
   }
1234
}
1235 1236
#endif

1237

1238
#ifdef PNG_MNG_FEATURES_SUPPORTED
1239
png_uint_32 PNGAPI
1240
png_permit_mng_features (png_structrp png_ptr, png_uint_32 mng_features)
1241
{
1242
   png_debug(1, "in png_permit_mng_features");
1243

1244
   if (png_ptr == NULL)
1245
      return 0;
1246

1247
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1248

1249
   return png_ptr->mng_features_permitted;
1250 1251
}
#endif
1252

1253
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1254 1255 1256 1257 1258 1259 1260 1261
static unsigned int
add_one_chunk(png_bytep list, unsigned int count, png_const_bytep add, int keep)
{
   unsigned int i;

   /* Utility function: update the 'keep' state of a chunk if it is already in
    * the list, otherwise add it to the list.
    */
1262
   for (i=0; i<count; ++i, list += 5)
1263
   {
1264 1265 1266 1267 1268
      if (memcmp(list, add, 4) == 0)
      {
         list[4] = (png_byte)keep;
         return count;
      }
1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280
   }

   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
   {
      ++count;
      memcpy(list, add, 4);
      list[4] = (png_byte)keep;
   }

   return count;
}

1281 1282
void PNGAPI
png_set_keep_unknown_chunks(png_structrp png_ptr, int keep,
1283
    png_const_bytep chunk_list, int num_chunks_in)
1284
{
1285 1286 1287
   png_bytep new_list;
   unsigned int num_chunks, old_num_chunks;

1288 1289
   if (png_ptr == NULL)
      return;
1290

1291
   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
1292
   {
1293 1294 1295
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
      return;
   }
1296

1297 1298 1299
   if (num_chunks_in <= 0)
   {
      png_ptr->unknown_default = keep;
1300

1301 1302 1303 1304
      /* '0' means just set the flags, so stop here */
      if (num_chunks_in == 0)
        return;
   }
1305

1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333
   if (num_chunks_in < 0)
   {
      /* 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;
   }
1334

1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346
   else /* num_chunks_in > 0 */
   {
      if (chunk_list == NULL)
      {
         /* 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");
         return;
      }

      num_chunks = num_chunks_in;
1347 1348
   }

1349 1350 1351 1352 1353 1354 1355 1356 1357
   old_num_chunks = png_ptr->num_chunk_list;
   if (png_ptr->chunk_list == NULL)
      old_num_chunks = 0;

   /* 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");
1358
      return;
1359
   }
1360

1361 1362 1363 1364
   /* 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.
    */
1365
   if (keep != 0)
1366 1367 1368
   {
      new_list = png_voidcast(png_bytep, png_malloc(png_ptr,
          5 * (num_chunks + old_num_chunks)));
1369

1370 1371 1372 1373 1374 1375
      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;
1376

1377 1378 1379 1380 1381 1382 1383 1384 1385
   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)
1386
   {
1387 1388 1389 1390 1391
      png_const_bytep inlist;
      png_bytep outlist;
      unsigned int i;

      for (i=0; i<num_chunks; ++i)
1392
      {
1393 1394
         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
            chunk_list+5*i, keep);
1395
      }
1396 1397 1398 1399

      /* Now remove any spurious 'default' entries. */
      num_chunks = 0;
      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1400
      {
1401 1402 1403 1404 1405 1406 1407
         if (inlist[4])
         {
            if (outlist != inlist)
               memcpy(outlist, inlist, 5);
            outlist += 5;
            ++num_chunks;
         }
1408
      }
1409 1410 1411 1412 1413 1414 1415 1416 1417

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

1420 1421 1422 1423
   else
      num_chunks = 0;

   png_ptr->num_chunk_list = num_chunks;
1424

1425 1426 1427 1428
   if (png_ptr->chunk_list != new_list)
   {
      if (png_ptr->chunk_list != NULL)
         png_free(png_ptr, png_ptr->chunk_list);
1429

1430 1431
      png_ptr->chunk_list = new_list;
   }
1432 1433
}
#endif
1434

1435
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1436
void PNGAPI
1437
png_set_read_user_chunk_fn(png_structrp png_ptr, png_voidp user_chunk_ptr,
1438
    png_user_chunk_ptr read_user_chunk_fn)
1439
{
1440
   png_debug(1, "in png_set_read_user_chunk_fn");
1441

1442 1443
   if (png_ptr == NULL)
      return;
1444

1445 1446 1447 1448
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
   png_ptr->user_chunk_ptr = user_chunk_ptr;
}
#endif
1449

1450
#ifdef PNG_INFO_IMAGE_SUPPORTED
1451
void PNGAPI
1452 1453
png_set_rows(png_const_structrp png_ptr, png_inforp info_ptr,
    png_bytepp row_pointers)
1454
{
1455
   png_debug1(1, "in %s storage function", "rows");
1456

1457 1458 1459
   if (png_ptr == NULL || info_ptr == NULL)
      return;

1460 1461
   if (info_ptr->row_pointers != NULL &&
       (info_ptr->row_pointers != row_pointers))
1462
      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1463

1464
   info_ptr->row_pointers = row_pointers;
1465

1466
   if (row_pointers != NULL)
1467
      info_ptr->valid |= PNG_INFO_IDAT;
1468 1469 1470
}
#endif

1471
void PNGAPI
1472
png_set_compression_buffer_size(png_structrp png_ptr, png_size_t size)
1473
{
1474 1475
    if (png_ptr == NULL)
       return;
1476

1477 1478
    if (size == 0 || size > PNG_UINT_31_MAX)
       png_error(png_ptr, "invalid compression buffer size");
1479

1480
#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1481
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1482 1483 1484 1485 1486 1487 1488
      {
         png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
         return;
      }
#  endif

#  ifdef PNG_WRITE_SUPPORTED
1489
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1490 1491 1492 1493 1494 1495 1496
      {
         if (png_ptr->zowner != 0)
         {
            png_warning(png_ptr,
              "Compression buffer size cannot be changed because it is in use");
            return;
         }
1497

1498 1499 1500 1501 1502 1503
         if (size > ZLIB_IO_MAX)
         {
            png_warning(png_ptr,
               "Compression buffer size limited to system maximum");
            size = ZLIB_IO_MAX; /* must fit */
         }
1504

1505 1506 1507 1508 1509 1510 1511 1512 1513
         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;
         }
1514

1515 1516 1517 1518 1519 1520 1521
         if (png_ptr->zbuffer_size != size)
         {
            png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
            png_ptr->zbuffer_size = (uInt)size;
         }
      }
#  endif
1522
}
1523 1524

void PNGAPI
1525
png_set_invalid(png_const_structrp png_ptr, png_inforp info_ptr, int mask)
1526
{
1527
   if (png_ptr != NULL && info_ptr != NULL)
1528
      info_ptr->valid &= ~mask;
1529
}
1530

1531

1532
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
1533
/* This function was added to libpng 1.2.6 */
1534
void PNGAPI
1535
png_set_user_limits (png_structrp png_ptr, png_uint_32 user_width_max,
1536 1537
    png_uint_32 user_height_max)
{
1538 1539 1540 1541 1542 1543
   /* 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;
1544

1545 1546
   png_ptr->user_width_max = user_width_max;
   png_ptr->user_height_max = user_height_max;
1547
}
1548

1549
/* This function was added to libpng 1.4.0 */
1550
void PNGAPI
1551
png_set_chunk_cache_max (png_structrp png_ptr, png_uint_32 user_chunk_cache_max)
1552
{
1553
    if (png_ptr != NULL)
1554
       png_ptr->user_chunk_cache_max = user_chunk_cache_max;
1555 1556 1557 1558
}

/* This function was added to libpng 1.4.1 */
void PNGAPI
1559
png_set_chunk_malloc_max (png_structrp png_ptr,
1560
    png_alloc_size_t user_chunk_malloc_max)
1561
{
1562
   if (png_ptr != NULL)
1563
      png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
1564
}
1565 1566
#endif /* ?PNG_SET_USER_LIMITS_SUPPORTED */

1567

1568
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
1569
void PNGAPI
1570
png_set_benign_errors(png_structrp png_ptr, int allowed)
1571
{
1572
   png_debug(1, "in png_set_benign_errors");
1573

1574 1575 1576 1577 1578 1579
   /* 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).
    */

1580
   if (allowed != 0)
1581 1582
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
1583

1584
   else
1585 1586
      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
1587 1588
}
#endif /* PNG_BENIGN_ERRORS_SUPPORTED */
1589 1590 1591 1592 1593 1594

#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
   /* Whether to report invalid palette index; added at libng-1.5.10.
    * It is possible for an indexed (color-type==3) PNG file to contain
    * pixels with invalid (out-of-range) indexes if the PLTE chunk has
    * fewer entries than the image's bit-depth would allow. We recover
1595
    * from this gracefully by filling any incomplete palette with zeros
1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610
    * (opaque black).  By default, when this occurs libpng will issue
    * a benign error.  This API can be used to override that behavior.
    */
void PNGAPI
png_set_check_for_invalid_index(png_structrp png_ptr, int allowed)
{
   png_debug(1, "in png_set_check_for_invalid_index");

   if (allowed > 0)
      png_ptr->num_palette_max = 0;

   else
      png_ptr->num_palette_max = -1;
}
#endif
1611
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */