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