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