CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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