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