VirtualBox

source: vbox/trunk/src/libs/libpng-1.6.45/pngset.c

Last change on this file was 107813, checked in by vboxsync, 3 weeks ago

libpng-1.6.45: Applied and adjusted our libpng changes to 1.6.45. bugref:8515

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette