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