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