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