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