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