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