Coverage Report

Created: 2026-05-16 07:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libpng/pngset.c
Line
Count
Source
1
/* pngset.c - storage of image information into info struct
2
 *
3
 * Copyright (c) 2018-2026 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
23
void
24
png_set_bKGD(const png_struct *png_ptr, png_info *info_ptr,
25
    const png_color_16 *background)
26
1.99k
{
27
1.99k
   png_debug1(1, "in %s storage function", "bKGD");
28
29
1.99k
   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
30
0
      return;
31
32
1.99k
   info_ptr->background = *background;
33
1.99k
   info_ptr->valid |= PNG_INFO_bKGD;
34
1.99k
}
35
#endif
36
37
#ifdef PNG_cHRM_SUPPORTED
38
void
39
png_set_cHRM_fixed(const png_struct *png_ptr, png_info *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
1.24k
{
44
1.24k
   png_debug1(1, "in %s storage function", "cHRM fixed");
45
46
1.24k
   if (png_ptr == NULL || info_ptr == NULL)
47
0
      return;
48
49
1.24k
   info_ptr->cHRM.redx = red_x;
50
1.24k
   info_ptr->cHRM.redy = red_y;
51
1.24k
   info_ptr->cHRM.greenx = green_x;
52
1.24k
   info_ptr->cHRM.greeny = green_y;
53
1.24k
   info_ptr->cHRM.bluex = blue_x;
54
1.24k
   info_ptr->cHRM.bluey = blue_y;
55
1.24k
   info_ptr->cHRM.whitex = white_x;
56
1.24k
   info_ptr->cHRM.whitey = white_y;
57
58
1.24k
   info_ptr->valid |= PNG_INFO_cHRM;
59
1.24k
}
60
61
void
62
png_set_cHRM_XYZ_fixed(const png_struct *png_ptr, png_info *info_ptr,
63
    png_fixed_point int_red_X, png_fixed_point int_red_Y,
64
    png_fixed_point int_red_Z, png_fixed_point int_green_X,
65
    png_fixed_point int_green_Y, png_fixed_point int_green_Z,
66
    png_fixed_point int_blue_X, png_fixed_point int_blue_Y,
67
    png_fixed_point int_blue_Z)
68
0
{
69
0
   png_XYZ XYZ;
70
0
   png_xy xy;
71
72
0
   png_debug1(1, "in %s storage function", "cHRM XYZ fixed");
73
74
0
   if (png_ptr == NULL || info_ptr == NULL)
75
0
      return;
76
77
0
   XYZ.red_X = int_red_X;
78
0
   XYZ.red_Y = int_red_Y;
79
0
   XYZ.red_Z = int_red_Z;
80
0
   XYZ.green_X = int_green_X;
81
0
   XYZ.green_Y = int_green_Y;
82
0
   XYZ.green_Z = int_green_Z;
83
0
   XYZ.blue_X = int_blue_X;
84
0
   XYZ.blue_Y = int_blue_Y;
85
0
   XYZ.blue_Z = int_blue_Z;
86
87
0
   if (png_xy_from_XYZ(&xy, &XYZ) == 0)
88
0
   {
89
0
      info_ptr->cHRM = xy;
90
0
      info_ptr->valid |= PNG_INFO_cHRM;
91
0
   }
92
93
0
   else
94
0
      png_app_error(png_ptr, "invalid cHRM XYZ");
95
0
}
96
97
#  ifdef PNG_FLOATING_POINT_SUPPORTED
98
void
99
png_set_cHRM(const png_struct *png_ptr, png_info *info_ptr,
100
    double white_x, double white_y, double red_x, double red_y,
101
    double green_x, double green_y, double blue_x, double blue_y)
102
791
{
103
791
   png_set_cHRM_fixed(png_ptr, info_ptr,
104
791
       png_fixed(png_ptr, white_x, "cHRM White X"),
105
791
       png_fixed(png_ptr, white_y, "cHRM White Y"),
106
791
       png_fixed(png_ptr, red_x, "cHRM Red X"),
107
791
       png_fixed(png_ptr, red_y, "cHRM Red Y"),
108
791
       png_fixed(png_ptr, green_x, "cHRM Green X"),
109
791
       png_fixed(png_ptr, green_y, "cHRM Green Y"),
110
791
       png_fixed(png_ptr, blue_x, "cHRM Blue X"),
111
791
       png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
112
791
}
113
114
void
115
png_set_cHRM_XYZ(const png_struct *png_ptr, png_info *info_ptr, double red_X,
116
    double red_Y, double red_Z, double green_X, double green_Y, double green_Z,
117
    double blue_X, double blue_Y, double blue_Z)
118
0
{
119
0
   png_set_cHRM_XYZ_fixed(png_ptr, info_ptr,
120
0
       png_fixed(png_ptr, red_X, "cHRM Red X"),
121
0
       png_fixed(png_ptr, red_Y, "cHRM Red Y"),
122
0
       png_fixed(png_ptr, red_Z, "cHRM Red Z"),
123
0
       png_fixed(png_ptr, green_X, "cHRM Green X"),
124
0
       png_fixed(png_ptr, green_Y, "cHRM Green Y"),
125
0
       png_fixed(png_ptr, green_Z, "cHRM Green Z"),
126
0
       png_fixed(png_ptr, blue_X, "cHRM Blue X"),
127
0
       png_fixed(png_ptr, blue_Y, "cHRM Blue Y"),
128
0
       png_fixed(png_ptr, blue_Z, "cHRM Blue Z"));
129
0
}
130
#  endif /* FLOATING_POINT */
131
132
#endif /* cHRM */
133
134
#ifdef PNG_cICP_SUPPORTED
135
void
136
png_set_cICP(const png_struct *png_ptr, png_info *info_ptr,
137
             png_byte colour_primaries, png_byte transfer_function,
138
             png_byte matrix_coefficients, png_byte video_full_range_flag)
139
25
{
140
25
   png_debug1(1, "in %s storage function", "cICP");
141
142
25
   if (png_ptr == NULL || info_ptr == NULL)
143
0
      return;
144
145
25
   info_ptr->cicp_colour_primaries = colour_primaries;
146
25
   info_ptr->cicp_transfer_function = transfer_function;
147
25
   info_ptr->cicp_matrix_coefficients = matrix_coefficients;
148
25
   info_ptr->cicp_video_full_range_flag = video_full_range_flag;
149
150
25
   if (info_ptr->cicp_matrix_coefficients != 0)
151
13
   {
152
13
      png_warning(png_ptr, "Invalid cICP matrix coefficients");
153
13
      return;
154
13
   }
155
156
12
   info_ptr->valid |= PNG_INFO_cICP;
157
12
}
158
#endif /* cICP */
159
160
#ifdef PNG_cLLI_SUPPORTED
161
void
162
png_set_cLLI_fixed(const png_struct *png_ptr, png_info *info_ptr,
163
    /* The values below are in cd/m2 (nits) and are scaled by 10,000; not
164
     * 100,000 as in the case of png_fixed_point.
165
     */
166
    png_uint_32 maxCLL, png_uint_32 maxFALL)
167
62
{
168
62
   png_debug1(1, "in %s storage function", "cLLI");
169
170
62
   if (png_ptr == NULL || info_ptr == NULL)
171
0
      return;
172
173
   /* Check the light level range: */
174
62
   if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU)
175
46
   {
176
      /* The limit is 200kcd/m2; somewhat bright but not inconceivable because
177
       * human vision is said to run up to 100Mcd/m2.  The sun is about 2Gcd/m2.
178
       *
179
       * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is
180
       * 2kcd/m2.
181
       */
182
46
      png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit",
183
46
            PNG_CHUNK_WRITE_ERROR);
184
46
      return;
185
46
   }
186
187
16
   info_ptr->maxCLL = maxCLL;
188
16
   info_ptr->maxFALL = maxFALL;
189
16
   info_ptr->valid |= PNG_INFO_cLLI;
190
16
}
191
192
#  ifdef PNG_FLOATING_POINT_SUPPORTED
193
void
194
png_set_cLLI(const png_struct *png_ptr, png_info *info_ptr,
195
   double maxCLL, double maxFALL)
196
0
{
197
0
   png_set_cLLI_fixed(png_ptr, info_ptr,
198
0
       png_fixed_ITU(png_ptr, maxCLL, "png_set_cLLI(maxCLL)"),
199
0
       png_fixed_ITU(png_ptr, maxFALL, "png_set_cLLI(maxFALL)"));
200
0
}
201
#  endif /* FLOATING_POINT */
202
#endif /* cLLI */
203
204
#ifdef PNG_mDCV_SUPPORTED
205
static png_uint_16
206
png_ITU_fixed_16(int *error, png_fixed_point v)
207
1.48k
{
208
   /* Return a safe uint16_t value scaled according to the ITU H273 rules for
209
    * 16-bit display chromaticities.  Functions like the corresponding
210
    * png_fixed() internal function with regard to errors: it's an error on
211
    * write, a chunk_benign_error on read: See the definition of
212
    * png_chunk_report in pngpriv.h.
213
    */
214
1.48k
   v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */
215
1.48k
   if (v > 65535 || v < 0)
216
0
   {
217
0
      *error = 1;
218
0
      return 0;
219
0
   }
220
221
1.48k
   return (png_uint_16)/*SAFE*/v;
222
1.48k
}
223
224
void
225
png_set_mDCV_fixed(const png_struct *png_ptr, png_info *info_ptr,
226
    png_fixed_point white_x, png_fixed_point white_y,
227
    png_fixed_point red_x, png_fixed_point red_y,
228
    png_fixed_point green_x, png_fixed_point green_y,
229
    png_fixed_point blue_x, png_fixed_point blue_y,
230
    png_uint_32 maxDL,
231
    png_uint_32 minDL)
232
186
{
233
186
   png_uint_16 rx, ry, gx, gy, bx, by, wx, wy;
234
186
   int error;
235
236
186
   png_debug1(1, "in %s storage function", "mDCV");
237
238
186
   if (png_ptr == NULL || info_ptr == NULL)
239
0
      return;
240
241
   /* Check the input values to ensure they are in the expected range: */
242
186
   error = 0;
243
186
   rx = png_ITU_fixed_16(&error, red_x);
244
186
   ry = png_ITU_fixed_16(&error, red_y);
245
186
   gx = png_ITU_fixed_16(&error, green_x);
246
186
   gy = png_ITU_fixed_16(&error, green_y);
247
186
   bx = png_ITU_fixed_16(&error, blue_x);
248
186
   by = png_ITU_fixed_16(&error, blue_y);
249
186
   wx = png_ITU_fixed_16(&error, white_x);
250
186
   wy = png_ITU_fixed_16(&error, white_y);
251
252
186
   if (error)
253
0
   {
254
0
      png_chunk_report(png_ptr,
255
0
         "mDCV chromaticities outside representable range",
256
0
         PNG_CHUNK_WRITE_ERROR);
257
0
      return;
258
0
   }
259
260
   /* Check the light level range: */
261
186
   if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU)
262
103
   {
263
      /* The limit is 200kcd/m2; somewhat bright but not inconceivable because
264
       * human vision is said to run up to 100Mcd/m2.  The sun is about 2Gcd/m2.
265
       *
266
       * The reference sRGB monitor is 80cd/m2 and the limit of PQ encoding is
267
       * 2kcd/m2.
268
       */
269
103
      png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit",
270
103
            PNG_CHUNK_WRITE_ERROR);
271
103
      return;
272
103
   }
273
274
   /* All values are safe, the settings are accepted.
275
    *
276
    * IMPLEMENTATION NOTE: in practice the values can be checked and assigned
277
    * but the result is confusing if a writing app calls png_set_mDCV more than
278
    * once, the second time with an invalid value.  This approach is more
279
    * obviously correct at the cost of typing and a very slight machine
280
    * overhead.
281
    */
282
83
   info_ptr->mastering_red_x = rx;
283
83
   info_ptr->mastering_red_y = ry;
284
83
   info_ptr->mastering_green_x = gx;
285
83
   info_ptr->mastering_green_y = gy;
286
83
   info_ptr->mastering_blue_x = bx;
287
83
   info_ptr->mastering_blue_y = by;
288
83
   info_ptr->mastering_white_x = wx;
289
83
   info_ptr->mastering_white_y = wy;
290
83
   info_ptr->mastering_maxDL = maxDL;
291
83
   info_ptr->mastering_minDL = minDL;
292
83
   info_ptr->valid |= PNG_INFO_mDCV;
293
83
}
294
295
#  ifdef PNG_FLOATING_POINT_SUPPORTED
296
void
297
png_set_mDCV(const png_struct *png_ptr, png_info *info_ptr,
298
    double white_x, double white_y, double red_x, double red_y, double green_x,
299
    double green_y, double blue_x, double blue_y,
300
    double maxDL, double minDL)
301
0
{
302
0
   png_set_mDCV_fixed(png_ptr, info_ptr,
303
0
      png_fixed(png_ptr, white_x, "png_set_mDCV(white(x))"),
304
0
      png_fixed(png_ptr, white_y, "png_set_mDCV(white(y))"),
305
0
      png_fixed(png_ptr, red_x, "png_set_mDCV(red(x))"),
306
0
      png_fixed(png_ptr, red_y, "png_set_mDCV(red(y))"),
307
0
      png_fixed(png_ptr, green_x, "png_set_mDCV(green(x))"),
308
0
      png_fixed(png_ptr, green_y, "png_set_mDCV(green(y))"),
309
0
      png_fixed(png_ptr, blue_x, "png_set_mDCV(blue(x))"),
310
0
      png_fixed(png_ptr, blue_y, "png_set_mDCV(blue(y))"),
311
0
      png_fixed_ITU(png_ptr, maxDL, "png_set_mDCV(maxDL)"),
312
0
      png_fixed_ITU(png_ptr, minDL, "png_set_mDCV(minDL)"));
313
0
}
314
#  endif /* FLOATING_POINT */
315
#endif /* mDCV */
316
317
#ifdef PNG_eXIf_SUPPORTED
318
void
319
png_set_eXIf_1(const png_struct *png_ptr, png_info *info_ptr,
320
    png_uint_32 num_exif, png_byte *exif)
321
33
{
322
33
   png_byte *new_exif;
323
324
33
   png_debug1(1, "in %s storage function", "eXIf");
325
326
33
   if (png_ptr == NULL || info_ptr == NULL ||
327
33
       (png_ptr->mode & PNG_WROTE_eXIf) != 0 ||
328
33
       exif == NULL)
329
0
      return;
330
331
33
   new_exif = png_voidcast(png_byte *, png_malloc_warn(png_ptr, num_exif));
332
333
33
   if (new_exif == NULL)
334
0
   {
335
0
      png_warning(png_ptr, "Insufficient memory for eXIf chunk data");
336
0
      return;
337
0
   }
338
339
33
   memcpy(new_exif, exif, (size_t)num_exif);
340
341
33
   png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
342
343
33
   info_ptr->num_exif = num_exif;
344
33
   info_ptr->exif = new_exif;
345
33
   info_ptr->free_me |= PNG_FREE_EXIF;
346
33
   info_ptr->valid |= PNG_INFO_eXIf;
347
33
}
348
#endif /* eXIf */
349
350
#ifdef PNG_gAMA_SUPPORTED
351
void
352
png_set_gAMA_fixed(const png_struct *png_ptr, png_info *info_ptr,
353
    png_fixed_point file_gamma)
354
697
{
355
697
   png_debug1(1, "in %s storage function", "gAMA");
356
357
697
   if (png_ptr == NULL || info_ptr == NULL)
358
0
      return;
359
360
697
   info_ptr->gamma = file_gamma;
361
697
   info_ptr->valid |= PNG_INFO_gAMA;
362
697
}
363
364
#  ifdef PNG_FLOATING_POINT_SUPPORTED
365
void
366
png_set_gAMA(const png_struct *png_ptr, png_info *info_ptr, double file_gamma)
367
53
{
368
53
   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
369
53
       "png_set_gAMA"));
370
53
}
371
#  endif
372
#endif
373
374
#ifdef PNG_hIST_SUPPORTED
375
void
376
png_set_hIST(const png_struct *png_ptr, png_info *info_ptr,
377
    const png_uint_16 *hist)
378
0
{
379
0
   png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
380
0
   int i;
381
382
0
   png_debug1(1, "in %s storage function", "hIST");
383
384
0
   if (png_ptr == NULL || info_ptr == NULL || hist == NULL)
385
0
      return;
386
387
0
   if (info_ptr->num_palette == 0 || info_ptr->num_palette
388
0
       > PNG_MAX_PALETTE_LENGTH)
389
0
   {
390
0
      png_warning(png_ptr,
391
0
          "Invalid palette size, hIST allocation skipped");
392
393
0
      return;
394
0
   }
395
396
   /* Snapshot the caller's hist before freeing, in case it points to
397
    * info_ptr->hist (getter-to-setter aliasing).
398
    */
399
0
   memcpy(safe_hist, hist, (unsigned int)info_ptr->num_palette *
400
0
       (sizeof (png_uint_16)));
401
0
   hist = safe_hist;
402
403
0
   png_free_data(png_ptr, info_ptr, PNG_FREE_HIST, 0);
404
405
   /* Changed from info->num_palette to PNG_MAX_PALETTE_LENGTH in
406
    * version 1.2.1
407
    */
408
0
   info_ptr->hist = png_voidcast(png_uint_16 *, png_malloc_warn(png_ptr,
409
0
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_uint_16))));
410
411
0
   if (info_ptr->hist == NULL)
412
0
   {
413
0
      png_warning(png_ptr, "Insufficient memory for hIST chunk data");
414
0
      return;
415
0
   }
416
417
0
   for (i = 0; i < info_ptr->num_palette; i++)
418
0
      info_ptr->hist[i] = hist[i];
419
420
0
   info_ptr->free_me |= PNG_FREE_HIST;
421
0
   info_ptr->valid |= PNG_INFO_hIST;
422
0
}
423
#endif
424
425
void
426
png_set_IHDR(const png_struct *png_ptr, png_info *info_ptr,
427
    png_uint_32 width, png_uint_32 height, int bit_depth,
428
    int color_type, int interlace_type, int compression_type,
429
    int filter_type)
430
66.2k
{
431
66.2k
   png_debug1(1, "in %s storage function", "IHDR");
432
433
66.2k
   if (png_ptr == NULL || info_ptr == NULL)
434
0
      return;
435
436
66.2k
   info_ptr->width = width;
437
66.2k
   info_ptr->height = height;
438
66.2k
   info_ptr->bit_depth = (png_byte)bit_depth;
439
66.2k
   info_ptr->color_type = (png_byte)color_type;
440
66.2k
   info_ptr->compression_type = (png_byte)compression_type;
441
66.2k
   info_ptr->filter_type = (png_byte)filter_type;
442
66.2k
   info_ptr->interlace_type = (png_byte)interlace_type;
443
444
66.2k
   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
445
66.2k
       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
446
66.2k
       info_ptr->compression_type, info_ptr->filter_type);
447
448
66.2k
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
449
7.00k
      info_ptr->channels = 1;
450
451
59.2k
   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
452
18.2k
      info_ptr->channels = 3;
453
454
40.9k
   else
455
40.9k
      info_ptr->channels = 1;
456
457
66.2k
   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
458
7.65k
      info_ptr->channels++;
459
460
66.2k
   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
461
462
66.2k
   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
463
464
66.2k
#ifdef PNG_APNG_SUPPORTED
465
   /* Assume a non-animated PNG in the beginning. This may be overridden after
466
    * seeing an acTL chunk later.
467
    */
468
66.2k
   info_ptr->num_frames = 1;
469
66.2k
#endif
470
66.2k
}
471
472
#ifdef PNG_oFFs_SUPPORTED
473
void
474
png_set_oFFs(const png_struct *png_ptr, png_info *info_ptr,
475
    png_int_32 offset_x, png_int_32 offset_y, int unit_type)
476
68
{
477
68
   png_debug1(1, "in %s storage function", "oFFs");
478
479
68
   if (png_ptr == NULL || info_ptr == NULL)
480
0
      return;
481
482
68
   info_ptr->x_offset = offset_x;
483
68
   info_ptr->y_offset = offset_y;
484
68
   info_ptr->offset_unit_type = (png_byte)unit_type;
485
68
   info_ptr->valid |= PNG_INFO_oFFs;
486
68
}
487
#endif
488
489
#ifdef PNG_pCAL_SUPPORTED
490
void
491
png_set_pCAL(const png_struct *png_ptr, png_info *info_ptr,
492
    const char *purpose, png_int_32 X0, png_int_32 X1, int type,
493
    int nparams, const char *units, char **params)
494
0
{
495
0
   size_t length;
496
0
   int i;
497
498
0
   png_debug1(1, "in %s storage function", "pCAL");
499
500
0
   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
501
0
       || (nparams > 0 && params == NULL))
502
0
      return;
503
504
0
   length = strlen(purpose) + 1;
505
0
   png_debug1(3, "allocating purpose for info (%lu bytes)",
506
0
       (unsigned long)length);
507
508
   /* TODO: validate format of calibration name and unit name */
509
510
   /* Check that the type matches the specification. */
511
0
   if (type < 0 || type > 3)
512
0
   {
513
0
      png_chunk_report(png_ptr, "Invalid pCAL equation type",
514
0
            PNG_CHUNK_WRITE_ERROR);
515
0
      return;
516
0
   }
517
518
0
   if (nparams < 0 || nparams > 255)
519
0
   {
520
0
      png_chunk_report(png_ptr, "Invalid pCAL parameter count",
521
0
            PNG_CHUNK_WRITE_ERROR);
522
0
      return;
523
0
   }
524
525
   /* Validate params[nparams] */
526
0
   for (i=0; i<nparams; ++i)
527
0
   {
528
0
      if (params[i] == NULL ||
529
0
          !png_check_fp_string(params[i], strlen(params[i])))
530
0
      {
531
0
         png_chunk_report(png_ptr, "Invalid format for pCAL parameter",
532
0
               PNG_CHUNK_WRITE_ERROR);
533
0
         return;
534
0
      }
535
0
   }
536
537
0
   info_ptr->pcal_purpose = png_voidcast(char *,
538
0
       png_malloc_warn(png_ptr, length));
539
540
0
   if (info_ptr->pcal_purpose == NULL)
541
0
   {
542
0
      png_chunk_report(png_ptr, "Insufficient memory for pCAL purpose",
543
0
            PNG_CHUNK_WRITE_ERROR);
544
0
      return;
545
0
   }
546
547
0
   memcpy(info_ptr->pcal_purpose, purpose, length);
548
549
0
   info_ptr->free_me |= PNG_FREE_PCAL;
550
551
0
   png_debug(3, "storing X0, X1, type, and nparams in info");
552
0
   info_ptr->pcal_X0 = X0;
553
0
   info_ptr->pcal_X1 = X1;
554
0
   info_ptr->pcal_type = (png_byte)type;
555
0
   info_ptr->pcal_nparams = (png_byte)nparams;
556
557
0
   length = strlen(units) + 1;
558
0
   png_debug1(3, "allocating units for info (%lu bytes)",
559
0
       (unsigned long)length);
560
561
0
   info_ptr->pcal_units = png_voidcast(char *,
562
0
       png_malloc_warn(png_ptr, length));
563
564
0
   if (info_ptr->pcal_units == NULL)
565
0
   {
566
0
      png_warning(png_ptr, "Insufficient memory for pCAL units");
567
0
      return;
568
0
   }
569
570
0
   memcpy(info_ptr->pcal_units, units, length);
571
572
0
   info_ptr->pcal_params = png_voidcast(char **, png_malloc_warn(png_ptr,
573
0
       (size_t)(((unsigned int)nparams + 1) * (sizeof (char *)))));
574
575
0
   if (info_ptr->pcal_params == NULL)
576
0
   {
577
0
      png_warning(png_ptr, "Insufficient memory for pCAL params");
578
0
      return;
579
0
   }
580
581
0
   memset(info_ptr->pcal_params, 0, ((unsigned int)nparams + 1) *
582
0
       (sizeof (char *)));
583
584
0
   for (i = 0; i < nparams; i++)
585
0
   {
586
0
      length = strlen(params[i]) + 1;
587
0
      png_debug2(3, "allocating parameter %d for info (%lu bytes)", i,
588
0
          (unsigned long)length);
589
590
0
      info_ptr->pcal_params[i] = (char *)png_malloc_warn(png_ptr, length);
591
592
0
      if (info_ptr->pcal_params[i] == NULL)
593
0
      {
594
0
         png_warning(png_ptr, "Insufficient memory for pCAL parameter");
595
0
         return;
596
0
      }
597
598
0
      memcpy(info_ptr->pcal_params[i], params[i], length);
599
0
   }
600
601
0
   info_ptr->valid |= PNG_INFO_pCAL;
602
0
}
603
#endif
604
605
#ifdef PNG_sCAL_SUPPORTED
606
void
607
png_set_sCAL_s(const png_struct *png_ptr, png_info *info_ptr,
608
    int unit, const char *swidth, const char *sheight)
609
0
{
610
0
   size_t lengthw = 0, lengthh = 0;
611
612
0
   png_debug1(1, "in %s storage function", "sCAL");
613
614
0
   if (png_ptr == NULL || info_ptr == NULL)
615
0
      return;
616
617
   /* Double check the unit (should never get here with an invalid
618
    * unit unless this is an API call.)
619
    */
620
0
   if (unit != 1 && unit != 2)
621
0
      png_error(png_ptr, "Invalid sCAL unit");
622
623
0
   if (swidth == NULL || (lengthw = strlen(swidth)) == 0 ||
624
0
       swidth[0] == 45 /* '-' */ || !png_check_fp_string(swidth, lengthw))
625
0
      png_error(png_ptr, "Invalid sCAL width");
626
627
0
   if (sheight == NULL || (lengthh = strlen(sheight)) == 0 ||
628
0
       sheight[0] == 45 /* '-' */ || !png_check_fp_string(sheight, lengthh))
629
0
      png_error(png_ptr, "Invalid sCAL height");
630
631
0
   info_ptr->scal_unit = (png_byte)unit;
632
633
0
   ++lengthw;
634
635
0
   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthw);
636
637
0
   info_ptr->scal_s_width = png_voidcast(char *,
638
0
       png_malloc_warn(png_ptr, lengthw));
639
640
0
   if (info_ptr->scal_s_width == NULL)
641
0
   {
642
0
      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
643
644
0
      return;
645
0
   }
646
647
0
   memcpy(info_ptr->scal_s_width, swidth, lengthw);
648
649
0
   ++lengthh;
650
651
0
   png_debug1(3, "allocating unit for info (%u bytes)", (unsigned int)lengthh);
652
653
0
   info_ptr->scal_s_height = png_voidcast(char *,
654
0
       png_malloc_warn(png_ptr, lengthh));
655
656
0
   if (info_ptr->scal_s_height == NULL)
657
0
   {
658
0
      png_free(png_ptr, info_ptr->scal_s_width);
659
0
      info_ptr->scal_s_width = NULL;
660
661
0
      png_warning(png_ptr, "Memory allocation failed while processing sCAL");
662
0
      return;
663
0
   }
664
665
0
   memcpy(info_ptr->scal_s_height, sheight, lengthh);
666
667
0
   info_ptr->free_me |= PNG_FREE_SCAL;
668
0
   info_ptr->valid |= PNG_INFO_sCAL;
669
0
}
670
671
#  ifdef PNG_FLOATING_POINT_SUPPORTED
672
void
673
png_set_sCAL(const png_struct *png_ptr, png_info *info_ptr, int unit,
674
    double width, double height)
675
0
{
676
0
   png_debug1(1, "in %s storage function", "sCAL");
677
678
   /* Check the arguments. */
679
0
   if (width <= 0)
680
0
      png_warning(png_ptr, "Invalid sCAL width ignored");
681
682
0
   else if (height <= 0)
683
0
      png_warning(png_ptr, "Invalid sCAL height ignored");
684
685
0
   else
686
0
   {
687
      /* Convert 'width' and 'height' to ASCII. */
688
0
      char swidth[PNG_sCAL_MAX_DIGITS+1];
689
0
      char sheight[PNG_sCAL_MAX_DIGITS+1];
690
691
0
      png_ascii_from_fp(png_ptr, swidth, (sizeof swidth), width,
692
0
          PNG_sCAL_PRECISION);
693
0
      png_ascii_from_fp(png_ptr, sheight, (sizeof sheight), height,
694
0
          PNG_sCAL_PRECISION);
695
696
0
      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
697
0
   }
698
0
}
699
#  endif
700
701
#  ifdef PNG_FIXED_POINT_SUPPORTED
702
void
703
png_set_sCAL_fixed(const png_struct *png_ptr, png_info *info_ptr, int unit,
704
    png_fixed_point width, png_fixed_point height)
705
0
{
706
0
   png_debug1(1, "in %s storage function", "sCAL");
707
708
   /* Check the arguments. */
709
0
   if (width <= 0)
710
0
      png_warning(png_ptr, "Invalid sCAL width ignored");
711
712
0
   else if (height <= 0)
713
0
      png_warning(png_ptr, "Invalid sCAL height ignored");
714
715
0
   else
716
0
   {
717
      /* Convert 'width' and 'height' to ASCII. */
718
0
      char swidth[PNG_sCAL_MAX_DIGITS+1];
719
0
      char sheight[PNG_sCAL_MAX_DIGITS+1];
720
721
0
      png_ascii_from_fixed(png_ptr, swidth, (sizeof swidth), width);
722
0
      png_ascii_from_fixed(png_ptr, sheight, (sizeof sheight), height);
723
724
0
      png_set_sCAL_s(png_ptr, info_ptr, unit, swidth, sheight);
725
0
   }
726
0
}
727
#  endif
728
#endif
729
730
#ifdef PNG_pHYs_SUPPORTED
731
void
732
png_set_pHYs(const png_struct *png_ptr, png_info *info_ptr,
733
    png_uint_32 res_x, png_uint_32 res_y, int unit_type)
734
308
{
735
308
   png_debug1(1, "in %s storage function", "pHYs");
736
737
308
   if (png_ptr == NULL || info_ptr == NULL)
738
0
      return;
739
740
308
   info_ptr->x_pixels_per_unit = res_x;
741
308
   info_ptr->y_pixels_per_unit = res_y;
742
308
   info_ptr->phys_unit_type = (png_byte)unit_type;
743
308
   info_ptr->valid |= PNG_INFO_pHYs;
744
308
}
745
#endif
746
747
void
748
png_set_PLTE(png_struct *png_ptr, png_info *info_ptr,
749
    const png_color *palette, int num_palette)
750
2.68k
{
751
2.68k
   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
752
2.68k
   png_uint_32 max_palette_length;
753
754
2.68k
   png_debug1(1, "in %s storage function", "PLTE");
755
756
2.68k
   if (png_ptr == NULL || info_ptr == NULL)
757
0
      return;
758
759
2.68k
   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
760
2.44k
      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
761
762
2.68k
   if (num_palette < 0 || num_palette > (int) max_palette_length)
763
0
   {
764
0
      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
765
0
         png_error(png_ptr, "Invalid palette length");
766
767
0
      else
768
0
      {
769
0
         png_warning(png_ptr, "Invalid palette length");
770
771
0
         return;
772
0
      }
773
0
   }
774
775
2.68k
   if ((num_palette > 0 && palette == NULL) ||
776
2.68k
      (num_palette == 0
777
51
#        ifdef PNG_MNG_FEATURES_SUPPORTED
778
51
            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
779
2.68k
#        endif
780
2.68k
      ))
781
13
   {
782
13
      png_error(png_ptr, "Invalid palette");
783
13
   }
784
785
   /* Snapshot the caller's palette before freeing, in case it points to
786
    * info_ptr->palette (getter-to-setter aliasing).
787
    */
788
2.67k
   if (num_palette > 0)
789
2.63k
      memcpy(safe_palette, palette, (unsigned int)num_palette *
790
2.63k
          (sizeof (png_color)));
791
792
2.67k
   palette = safe_palette;
793
794
2.67k
   png_free_data(png_ptr, info_ptr, PNG_FREE_PLTE, 0);
795
796
   /* Changed in libpng-1.2.1 to allocate PNG_MAX_PALETTE_LENGTH instead
797
    * of num_palette entries, in case of an invalid PNG file or incorrect
798
    * call to png_set_PLTE() with too-large sample values.
799
    *
800
    * Allocate independent buffers for info_ptr and png_ptr so that the
801
    * lifetime of png_ptr->palette is decoupled from the lifetime of
802
    * info_ptr->palette.  Previously, these two pointers were aliased,
803
    * which caused a use-after-free vulnerability if png_free_data freed
804
    * info_ptr->palette while png_ptr->palette was still in use by the
805
    * row transform functions (e.g. png_do_expand_palette).
806
    *
807
    * Both buffers are allocated with png_calloc to zero-fill, because
808
    * the ARM NEON palette riffle reads all 256 entries unconditionally,
809
    * regardless of num_palette.
810
    */
811
2.67k
   png_free(png_ptr, png_ptr->palette);
812
2.67k
   png_ptr->palette = png_voidcast(png_color *, png_calloc(png_ptr,
813
2.67k
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
814
2.67k
   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
815
2.67k
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
816
2.67k
   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
817
818
2.67k
   if (num_palette > 0)
819
2.63k
   {
820
2.63k
      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
821
2.63k
          (sizeof (png_color)));
822
2.63k
      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
823
2.63k
          (sizeof (png_color)));
824
2.63k
   }
825
826
2.67k
   info_ptr->free_me |= PNG_FREE_PLTE;
827
2.67k
   info_ptr->valid |= PNG_INFO_PLTE;
828
2.67k
}
829
830
#ifdef PNG_sBIT_SUPPORTED
831
void
832
png_set_sBIT(const png_struct *png_ptr, png_info *info_ptr,
833
    const png_color_8 *sig_bit)
834
85
{
835
85
   png_debug1(1, "in %s storage function", "sBIT");
836
837
85
   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
838
0
      return;
839
840
85
   info_ptr->sig_bit = *sig_bit;
841
85
   info_ptr->valid |= PNG_INFO_sBIT;
842
85
}
843
#endif
844
845
#ifdef PNG_sRGB_SUPPORTED
846
void
847
png_set_sRGB(const png_struct *png_ptr, png_info *info_ptr, int srgb_intent)
848
111
{
849
111
   png_debug1(1, "in %s storage function", "sRGB");
850
851
111
   if (png_ptr == NULL || info_ptr == NULL)
852
0
      return;
853
854
111
   info_ptr->rendering_intent = srgb_intent;
855
111
   info_ptr->valid |= PNG_INFO_sRGB;
856
111
}
857
858
void
859
png_set_sRGB_gAMA_and_cHRM(const png_struct *png_ptr, png_info *info_ptr,
860
    int srgb_intent)
861
0
{
862
0
   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
863
864
0
   if (png_ptr == NULL || info_ptr == NULL)
865
0
      return;
866
867
0
   png_set_sRGB(png_ptr, info_ptr, srgb_intent);
868
869
0
#  ifdef PNG_gAMA_SUPPORTED
870
0
      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
871
0
#  endif /* gAMA */
872
873
0
#  ifdef PNG_cHRM_SUPPORTED
874
0
      png_set_cHRM_fixed(png_ptr, info_ptr,
875
         /* color      x       y */
876
0
         /* white */ 31270, 32900,
877
0
         /* red   */ 64000, 33000,
878
0
         /* green */ 30000, 60000,
879
0
         /* blue  */ 15000,  6000);
880
0
#  endif /* cHRM */
881
0
}
882
#endif /* sRGB */
883
884
885
#ifdef PNG_iCCP_SUPPORTED
886
void
887
png_set_iCCP(const png_struct *png_ptr, png_info *info_ptr,
888
    const char *name, int compression_type,
889
    const png_byte *profile, png_uint_32 proflen)
890
16
{
891
16
   char *new_iccp_name;
892
16
   png_byte *new_iccp_profile;
893
16
   size_t length;
894
895
16
   png_debug1(1, "in %s storage function", "iCCP");
896
897
16
   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
898
0
      return;
899
900
16
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
901
0
      png_app_error(png_ptr, "Invalid iCCP compression method");
902
903
16
   length = strlen(name)+1;
904
16
   new_iccp_name = png_voidcast(char *, png_malloc_warn(png_ptr, length));
905
906
16
   if (new_iccp_name == NULL)
907
0
   {
908
0
      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
909
910
0
      return;
911
0
   }
912
913
16
   memcpy(new_iccp_name, name, length);
914
16
   new_iccp_profile = png_voidcast(png_byte *,
915
16
       png_malloc_warn(png_ptr, proflen));
916
917
16
   if (new_iccp_profile == NULL)
918
0
   {
919
0
      png_free(png_ptr, new_iccp_name);
920
0
      png_benign_error(png_ptr,
921
0
          "Insufficient memory to process iCCP profile");
922
923
0
      return;
924
0
   }
925
926
16
   memcpy(new_iccp_profile, profile, proflen);
927
928
16
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
929
930
16
   info_ptr->iccp_proflen = proflen;
931
16
   info_ptr->iccp_name = new_iccp_name;
932
16
   info_ptr->iccp_profile = new_iccp_profile;
933
16
   info_ptr->free_me |= PNG_FREE_ICCP;
934
16
   info_ptr->valid |= PNG_INFO_iCCP;
935
16
}
936
#endif
937
938
#ifdef PNG_TEXT_SUPPORTED
939
void
940
png_set_text(const png_struct *png_ptr, png_info *info_ptr,
941
    const png_text *text_ptr, int num_text)
942
6.41k
{
943
6.41k
   int ret;
944
6.41k
   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
945
946
6.41k
   if (ret != 0)
947
0
      png_error(png_ptr, "Insufficient memory to store text");
948
6.41k
}
949
950
int /* PRIVATE */
951
png_set_text_2(const png_struct *png_ptr, png_info *info_ptr,
952
    const png_text *text_ptr, int num_text)
953
53.5k
{
954
53.5k
   int i;
955
53.5k
   png_textp old_text = NULL;
956
957
53.5k
   png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
958
53.5k
      png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
959
960
53.5k
   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
961
0
      return 0;
962
963
   /* Make sure we have enough space in the "text" array in info_struct
964
    * to hold all of the incoming text_ptr objects.  This compare can't overflow
965
    * because max_text >= num_text (anyway, subtract of two positive integers
966
    * can't overflow in any case.)
967
    */
968
53.5k
   if (num_text > info_ptr->max_text - info_ptr->num_text)
969
8.99k
   {
970
8.99k
      int old_num_text = info_ptr->num_text;
971
8.99k
      int max_text;
972
8.99k
      png_text *new_text = NULL;
973
974
      /* Calculate an appropriate max_text, checking for overflow. */
975
8.99k
      max_text = old_num_text;
976
8.99k
      if (num_text <= INT_MAX - max_text)
977
8.99k
      {
978
8.99k
         max_text += num_text;
979
980
         /* Round up to a multiple of 8 */
981
8.99k
         if (max_text < INT_MAX-8)
982
8.99k
            max_text = (max_text + 8) & ~0x7;
983
984
0
         else
985
0
            max_text = INT_MAX;
986
987
         /* Now allocate a new array and copy the old members in; this does all
988
          * the overflow checks.
989
          */
990
8.99k
         new_text = png_voidcast(png_text *,png_realloc_array(png_ptr,
991
8.99k
             info_ptr->text, old_num_text, max_text-old_num_text,
992
8.99k
             sizeof *new_text));
993
8.99k
      }
994
995
8.99k
      if (new_text == NULL)
996
0
      {
997
0
         png_chunk_report(png_ptr, "too many text chunks",
998
0
             PNG_CHUNK_WRITE_ERROR);
999
1000
0
         return 1;
1001
0
      }
1002
1003
      /* Defer freeing the old array until after the copy loop below,
1004
       * in case text_ptr aliases info_ptr->text (getter-to-setter).
1005
       */
1006
8.99k
      old_text = info_ptr->text;
1007
1008
8.99k
      info_ptr->text = new_text;
1009
8.99k
      info_ptr->free_me |= PNG_FREE_TEXT;
1010
8.99k
      info_ptr->max_text = max_text;
1011
      /* num_text is adjusted below as the entries are copied in */
1012
1013
8.99k
      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
1014
8.99k
   }
1015
1016
107k
   for (i = 0; i < num_text; i++)
1017
53.5k
   {
1018
53.5k
      size_t text_length, key_len;
1019
53.5k
      size_t lang_len, lang_key_len;
1020
53.5k
      png_text *textp = &(info_ptr->text[info_ptr->num_text]);
1021
1022
53.5k
      if (text_ptr[i].key == NULL)
1023
0
          continue;
1024
1025
53.5k
      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
1026
53.5k
          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
1027
0
      {
1028
0
         png_chunk_report(png_ptr, "text compression mode is out of range",
1029
0
             PNG_CHUNK_WRITE_ERROR);
1030
0
         continue;
1031
0
      }
1032
1033
53.5k
      key_len = strlen(text_ptr[i].key);
1034
1035
53.5k
      if (text_ptr[i].compression <= 0)
1036
53.4k
      {
1037
53.4k
         lang_len = 0;
1038
53.4k
         lang_key_len = 0;
1039
53.4k
      }
1040
1041
64
      else
1042
64
#  ifdef PNG_iTXt_SUPPORTED
1043
64
      {
1044
         /* Set iTXt data */
1045
1046
64
         if (text_ptr[i].lang != NULL)
1047
0
            lang_len = strlen(text_ptr[i].lang);
1048
1049
64
         else
1050
64
            lang_len = 0;
1051
1052
64
         if (text_ptr[i].lang_key != NULL)
1053
0
            lang_key_len = strlen(text_ptr[i].lang_key);
1054
1055
64
         else
1056
64
            lang_key_len = 0;
1057
64
      }
1058
#  else /* iTXt */
1059
      {
1060
         png_chunk_report(png_ptr, "iTXt chunk not supported",
1061
             PNG_CHUNK_WRITE_ERROR);
1062
         continue;
1063
      }
1064
#  endif
1065
1066
53.5k
      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
1067
32.7k
      {
1068
32.7k
         text_length = 0;
1069
32.7k
#  ifdef PNG_iTXt_SUPPORTED
1070
32.7k
         if (text_ptr[i].compression > 0)
1071
0
            textp->compression = PNG_ITXT_COMPRESSION_NONE;
1072
1073
32.7k
         else
1074
32.7k
#  endif
1075
32.7k
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
1076
32.7k
      }
1077
1078
20.7k
      else
1079
20.7k
      {
1080
20.7k
         text_length = strlen(text_ptr[i].text);
1081
20.7k
         textp->compression = text_ptr[i].compression;
1082
20.7k
      }
1083
1084
53.5k
      textp->key = png_voidcast(char *,png_malloc_base(png_ptr,
1085
53.5k
          key_len + text_length + lang_len + lang_key_len + 4));
1086
1087
53.5k
      if (textp->key == NULL)
1088
0
      {
1089
0
         png_chunk_report(png_ptr, "text chunk: out of memory",
1090
0
             PNG_CHUNK_WRITE_ERROR);
1091
0
         png_free(png_ptr, old_text);
1092
1093
0
         return 1;
1094
0
      }
1095
1096
53.5k
      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
1097
53.5k
          (unsigned long)(png_uint_32)
1098
53.5k
          (key_len + lang_len + lang_key_len + text_length + 4),
1099
53.5k
          textp->key);
1100
1101
53.5k
      memcpy(textp->key, text_ptr[i].key, key_len);
1102
53.5k
      *(textp->key + key_len) = '\0';
1103
1104
53.5k
      if (text_ptr[i].compression > 0)
1105
64
      {
1106
64
         textp->lang = textp->key + key_len + 1;
1107
64
         memcpy(textp->lang, text_ptr[i].lang, lang_len);
1108
64
         *(textp->lang + lang_len) = '\0';
1109
64
         textp->lang_key = textp->lang + lang_len + 1;
1110
64
         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
1111
64
         *(textp->lang_key + lang_key_len) = '\0';
1112
64
         textp->text = textp->lang_key + lang_key_len + 1;
1113
64
      }
1114
1115
53.4k
      else
1116
53.4k
      {
1117
53.4k
         textp->lang=NULL;
1118
53.4k
         textp->lang_key=NULL;
1119
53.4k
         textp->text = textp->key + key_len + 1;
1120
53.4k
      }
1121
1122
53.5k
      if (text_length != 0)
1123
20.7k
         memcpy(textp->text, text_ptr[i].text, text_length);
1124
1125
53.5k
      *(textp->text + text_length) = '\0';
1126
1127
53.5k
#  ifdef PNG_iTXt_SUPPORTED
1128
53.5k
      if (textp->compression > 0)
1129
64
      {
1130
64
         textp->text_length = 0;
1131
64
         textp->itxt_length = text_length;
1132
64
      }
1133
1134
53.4k
      else
1135
53.4k
#  endif
1136
53.4k
      {
1137
53.4k
         textp->text_length = text_length;
1138
53.4k
         textp->itxt_length = 0;
1139
53.4k
      }
1140
1141
53.5k
      info_ptr->num_text++;
1142
53.5k
      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
1143
53.5k
   }
1144
1145
53.5k
   png_free(png_ptr, old_text);
1146
1147
53.5k
   return 0;
1148
53.5k
}
1149
#endif
1150
1151
#ifdef PNG_tIME_SUPPORTED
1152
void
1153
png_set_tIME(const png_struct *png_ptr, png_info *info_ptr,
1154
    const png_time *mod_time)
1155
1.53k
{
1156
1.53k
   png_debug1(1, "in %s storage function", "tIME");
1157
1158
1.53k
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
1159
1.53k
       (png_ptr->mode & PNG_WROTE_tIME) != 0)
1160
0
      return;
1161
1162
1.53k
   if (mod_time->month == 0   || mod_time->month > 12  ||
1163
1.51k
       mod_time->day   == 0   || mod_time->day   > 31  ||
1164
1.48k
       mod_time->hour  > 23   || mod_time->minute > 59 ||
1165
1.45k
       mod_time->second > 60)
1166
82
   {
1167
82
      png_warning(png_ptr, "Ignoring invalid time value");
1168
1169
82
      return;
1170
82
   }
1171
1172
1.44k
   info_ptr->mod_time = *mod_time;
1173
1.44k
   info_ptr->valid |= PNG_INFO_tIME;
1174
1.44k
}
1175
#endif
1176
1177
#ifdef PNG_tRNS_SUPPORTED
1178
void
1179
png_set_tRNS(png_struct *png_ptr, png_info *info_ptr,
1180
    const png_byte *trans_alpha, int num_trans, const png_color_16 *trans_color)
1181
1.60k
{
1182
1.60k
   png_debug1(1, "in %s storage function", "tRNS");
1183
1184
1.60k
   if (png_ptr == NULL || info_ptr == NULL)
1185
1186
0
      return;
1187
1188
1.60k
   if (trans_alpha != NULL)
1189
1.50k
   {
1190
       /* Snapshot the caller's trans_alpha before freeing, in case it
1191
        * points to info_ptr->trans_alpha (getter-to-setter aliasing).
1192
        */
1193
1.50k
       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
1194
1195
1.50k
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1196
1.49k
          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
1197
1198
1.50k
       trans_alpha = safe_trans;
1199
1200
1.50k
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
1201
1202
1.50k
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1203
1.49k
       {
1204
          /* Allocate info_ptr's copy of the transparency data.
1205
           * Initialize all entries to fully opaque (0xff), then overwrite
1206
           * the first num_trans entries with the actual values.
1207
           */
1208
1.49k
          info_ptr->trans_alpha = png_voidcast(png_byte *,
1209
1.49k
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1210
1.49k
          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1211
1.49k
          memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1212
1.49k
          info_ptr->free_me |= PNG_FREE_TRNS;
1213
1.49k
          info_ptr->valid |= PNG_INFO_tRNS;
1214
1215
          /* Allocate an independent copy for png_struct, so that the
1216
           * lifetime of png_ptr->trans_alpha is decoupled from the
1217
           * lifetime of info_ptr->trans_alpha.  Previously these two
1218
           * pointers were aliased, which caused a use-after-free if
1219
           * png_free_data freed info_ptr->trans_alpha while
1220
           * png_ptr->trans_alpha was still in use by the row transform
1221
           * functions (e.g. png_do_expand_palette).
1222
           */
1223
1.49k
          png_free(png_ptr, png_ptr->trans_alpha);
1224
1.49k
          png_ptr->trans_alpha = png_voidcast(png_bytep,
1225
1.49k
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1226
1.49k
          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1227
1.49k
          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1228
1.49k
       }
1229
11
       else
1230
11
       {
1231
11
          png_free(png_ptr, png_ptr->trans_alpha);
1232
11
          png_ptr->trans_alpha = NULL;
1233
11
       }
1234
1.50k
   }
1235
1236
1.60k
   if (trans_color != NULL)
1237
1.52k
   {
1238
1.52k
#ifdef PNG_WARNINGS_SUPPORTED
1239
1.52k
      if (info_ptr->bit_depth < 16)
1240
1.10k
      {
1241
1.10k
         int sample_max = (1 << info_ptr->bit_depth) - 1;
1242
1243
1.10k
         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1244
326
             trans_color->gray > sample_max) ||
1245
1.02k
             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1246
500
             (trans_color->red > sample_max ||
1247
450
             trans_color->green > sample_max ||
1248
414
             trans_color->blue > sample_max)))
1249
225
            png_warning(png_ptr,
1250
225
                "tRNS chunk has out-of-range samples for bit_depth");
1251
1.10k
      }
1252
1.52k
#endif
1253
1254
1.52k
      info_ptr->trans_color = *trans_color;
1255
1256
1.52k
      if (num_trans == 0)
1257
95
         num_trans = 1;
1258
1.52k
   }
1259
1260
1.60k
   info_ptr->num_trans = (png_uint_16)num_trans;
1261
1262
1.60k
   if (num_trans != 0)
1263
1.59k
   {
1264
1.59k
      info_ptr->free_me |= PNG_FREE_TRNS;
1265
1.59k
      info_ptr->valid |= PNG_INFO_tRNS;
1266
1.59k
   }
1267
1.60k
}
1268
#endif
1269
1270
#ifdef PNG_sPLT_SUPPORTED
1271
void
1272
png_set_sPLT(const png_struct *png_ptr,
1273
    png_info *info_ptr, const png_sPLT_t *entries, int nentries)
1274
/*
1275
 *  entries        - array of png_sPLT_t structures
1276
 *                   to be added to the list of palettes
1277
 *                   in the info structure.
1278
 *
1279
 *  nentries       - number of palette structures to be
1280
 *                   added.
1281
 */
1282
0
{
1283
0
   png_sPLT_t *np;
1284
0
   png_sPLT_t *old_spalettes;
1285
1286
0
   png_debug1(1, "in %s storage function", "sPLT");
1287
1288
0
   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
1289
0
      return;
1290
1291
   /* Use the internal realloc function, which checks for all the possible
1292
    * overflows.  Notice that the parameters are (int) and (size_t)
1293
    */
1294
0
   np = png_voidcast(png_sPLT_t *,png_realloc_array(png_ptr,
1295
0
       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
1296
0
       sizeof *np));
1297
1298
0
   if (np == NULL)
1299
0
   {
1300
      /* Out of memory or too many chunks */
1301
0
      png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
1302
0
      return;
1303
0
   }
1304
1305
   /* Defer freeing the old array until after the copy loop below,
1306
    * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
1307
    */
1308
0
   old_spalettes = info_ptr->splt_palettes;
1309
1310
0
   info_ptr->splt_palettes = np;
1311
0
   info_ptr->free_me |= PNG_FREE_SPLT;
1312
1313
0
   np += info_ptr->splt_palettes_num;
1314
1315
0
   do
1316
0
   {
1317
0
      size_t length;
1318
1319
      /* Skip invalid input entries */
1320
0
      if (entries->name == NULL || entries->entries == NULL)
1321
0
      {
1322
         /* png_handle_sPLT doesn't do this, so this is an app error */
1323
0
         png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
1324
         /* Just skip the invalid entry */
1325
0
         continue;
1326
0
      }
1327
1328
0
      np->depth = entries->depth;
1329
1330
      /* In the event of out-of-memory just return - there's no point keeping
1331
       * on trying to add sPLT chunks.
1332
       */
1333
0
      length = strlen(entries->name) + 1;
1334
0
      np->name = png_voidcast(char *, png_malloc_base(png_ptr, length));
1335
1336
0
      if (np->name == NULL)
1337
0
         break;
1338
1339
0
      memcpy(np->name, entries->name, length);
1340
1341
      /* IMPORTANT: we have memory now that won't get freed if something else
1342
       * goes wrong; this code must free it.  png_malloc_array produces no
1343
       * warnings; use a png_chunk_report (below) if there is an error.
1344
       */
1345
0
      np->entries = png_voidcast(png_sPLT_entry *, png_malloc_array(png_ptr,
1346
0
          entries->nentries, sizeof (png_sPLT_entry)));
1347
1348
0
      if (np->entries == NULL)
1349
0
      {
1350
0
         png_free(png_ptr, np->name);
1351
0
         np->name = NULL;
1352
0
         break;
1353
0
      }
1354
1355
0
      np->nentries = entries->nentries;
1356
      /* This multiply can't overflow because png_malloc_array has already
1357
       * checked it when doing the allocation.
1358
       */
1359
0
      memcpy(np->entries, entries->entries,
1360
0
          (unsigned int)entries->nentries * sizeof (png_sPLT_entry));
1361
1362
      /* Note that 'continue' skips the advance of the out pointer and out
1363
       * count, so an invalid entry is not added.
1364
       */
1365
0
      info_ptr->valid |= PNG_INFO_sPLT;
1366
0
      ++(info_ptr->splt_palettes_num);
1367
0
      ++np;
1368
0
      ++entries;
1369
0
   }
1370
0
   while (--nentries);
1371
1372
0
   png_free(png_ptr, old_spalettes);
1373
1374
0
   if (nentries > 0)
1375
0
      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
1376
0
}
1377
#endif /* sPLT */
1378
1379
#ifdef PNG_APNG_SUPPORTED
1380
png_uint_32 PNGAPI
1381
png_set_acTL(png_struct *png_ptr, png_info *info_ptr,
1382
             png_uint_32 num_frames, png_uint_32 num_plays)
1383
0
{
1384
0
   png_debug1(1, "in %s storage function", "acTL");
1385
1386
0
   if (png_ptr == NULL || info_ptr == NULL)
1387
0
   {
1388
0
      png_warning(png_ptr,
1389
0
                  "Ignoring call to png_set_acTL with NULL libpng object args");
1390
0
      return 0;
1391
0
   }
1392
0
   if (num_frames == 0)
1393
0
   {
1394
0
      png_warning(png_ptr,
1395
0
                  "Ignoring attempt to set acTL with num_frames zero");
1396
0
      return 0;
1397
0
   }
1398
0
   if (num_frames > PNG_UINT_31_MAX)
1399
0
   {
1400
0
      png_warning(png_ptr,
1401
0
                  "Ignoring attempt to set acTL with num_frames > 2^31-1");
1402
0
      return 0;
1403
0
   }
1404
0
   if (num_plays > PNG_UINT_31_MAX)
1405
0
   {
1406
0
      png_warning(png_ptr,
1407
0
                  "Ignoring attempt to set acTL with num_plays > 2^31-1");
1408
0
      return 0;
1409
0
   }
1410
1411
0
   info_ptr->num_frames = num_frames;
1412
0
   info_ptr->num_plays = num_plays;
1413
1414
0
   info_ptr->valid |= PNG_INFO_acTL;
1415
1416
0
   return 1;
1417
0
}
1418
1419
png_uint_32 PNGAPI
1420
png_set_next_frame_fcTL(png_struct *png_ptr, png_info *info_ptr,
1421
                        png_uint_32 width, png_uint_32 height,
1422
                        png_uint_32 x_offset, png_uint_32 y_offset,
1423
                        png_uint_16 delay_num, png_uint_16 delay_den,
1424
                        png_byte dispose_op, png_byte blend_op)
1425
0
{
1426
0
   png_debug1(1, "in %s storage function", "fcTL");
1427
1428
0
   if (png_ptr == NULL || info_ptr == NULL)
1429
0
   {
1430
0
      png_warning(png_ptr,
1431
0
                  "Ignoring call to png_set_fcTL with NULL libpng object args");
1432
0
      return 0;
1433
0
   }
1434
1435
0
   png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1436
0
                            delay_num, delay_den, dispose_op, blend_op);
1437
1438
   /* No checking is required for delay_num and delay_den.
1439
    * They can hold any 16-bit value, including zero.
1440
    */
1441
1442
0
   if (blend_op == PNG_fcTL_BLEND_OP_OVER)
1443
0
   {
1444
0
      if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
1445
0
          !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
1446
0
      {
1447
0
         png_warning(png_ptr,
1448
0
                     "Ignoring wasteful fcTL BLEND_OP_OVER in opaque images");
1449
0
         blend_op = PNG_fcTL_BLEND_OP_SOURCE;
1450
0
      }
1451
0
   }
1452
1453
0
   info_ptr->next_frame_width = width;
1454
0
   info_ptr->next_frame_height = height;
1455
0
   info_ptr->next_frame_x_offset = x_offset;
1456
0
   info_ptr->next_frame_y_offset = y_offset;
1457
0
   info_ptr->next_frame_delay_num = delay_num;
1458
0
   info_ptr->next_frame_delay_den = delay_den;
1459
0
   info_ptr->next_frame_dispose_op = dispose_op;
1460
0
   info_ptr->next_frame_blend_op = blend_op;
1461
1462
0
   info_ptr->valid |= PNG_INFO_fcTL;
1463
1464
0
   return 1;
1465
0
}
1466
1467
void /* PRIVATE */
1468
png_ensure_fcTL_is_valid(png_struct *png_ptr,
1469
                         png_uint_32 width, png_uint_32 height,
1470
                         png_uint_32 x_offset, png_uint_32 y_offset,
1471
                         png_uint_16 delay_num, png_uint_16 delay_den,
1472
                         png_byte dispose_op, png_byte blend_op)
1473
0
{
1474
0
   if (width == 0 || width > PNG_UINT_31_MAX)
1475
0
      png_error(png_ptr, "Invalid frame width in fcTL");
1476
0
   if (height == 0 || height > PNG_UINT_31_MAX)
1477
0
      png_error(png_ptr, "Invalid frame height in fcTL");
1478
0
   if (x_offset > PNG_UINT_31_MAX || y_offset > PNG_UINT_31_MAX)
1479
0
      png_error(png_ptr, "Invalid frame offset in fcTL");
1480
0
   if (width + x_offset > png_ptr->first_frame_width ||
1481
0
       height + y_offset > png_ptr->first_frame_height)
1482
0
      png_error(png_ptr, "Oversized frame in fcTL");
1483
1484
0
   if (dispose_op != PNG_fcTL_DISPOSE_OP_NONE &&
1485
0
       dispose_op != PNG_fcTL_DISPOSE_OP_BACKGROUND &&
1486
0
       dispose_op != PNG_fcTL_DISPOSE_OP_PREVIOUS)
1487
0
      png_error(png_ptr, "Invalid dispose_op in fcTL");
1488
1489
0
   if (blend_op != PNG_fcTL_BLEND_OP_SOURCE &&
1490
0
       blend_op != PNG_fcTL_BLEND_OP_OVER)
1491
0
      png_error(png_ptr, "Invalid blend_op in fcTL");
1492
1493
0
   PNG_UNUSED(delay_num)
1494
0
   PNG_UNUSED(delay_den)
1495
0
}
1496
1497
png_uint_32 PNGAPI
1498
png_set_first_frame_is_hidden(png_struct *png_ptr, png_info *info_ptr,
1499
                              png_byte is_hidden)
1500
0
{
1501
0
   png_debug(1, "in png_first_frame_is_hidden");
1502
1503
0
   if (png_ptr == NULL)
1504
0
      return 0;
1505
1506
0
   if (is_hidden)
1507
0
      png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
1508
0
   else
1509
0
      png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
1510
1511
0
   PNG_UNUSED(info_ptr)
1512
1513
0
   return 1;
1514
0
}
1515
#endif /* PNG_APNG_SUPPORTED */
1516
1517
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1518
static png_byte
1519
check_location(const png_struct *png_ptr, int location)
1520
82.3k
{
1521
82.3k
   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
1522
1523
   /* New in 1.6.0; copy the location and check it.  This is an API
1524
    * change; previously the app had to use the
1525
    * png_set_unknown_chunk_location API below for each chunk.
1526
    */
1527
82.3k
   if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1528
0
   {
1529
      /* Write struct, so unknown chunks come from the app */
1530
0
      png_app_warning(png_ptr,
1531
0
          "png_set_unknown_chunks now expects a valid location");
1532
      /* Use the old behavior */
1533
0
      location = (png_byte)(png_ptr->mode &
1534
0
          (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
1535
0
   }
1536
1537
   /* This need not be an internal error - if the app calls
1538
    * png_set_unknown_chunks on a read pointer it must get the location right.
1539
    */
1540
82.3k
   if (location == 0)
1541
2.31k
      png_error(png_ptr, "invalid location in png_set_unknown_chunks");
1542
1543
   /* Now reduce the location to the top-most set bit by removing each least
1544
    * significant bit in turn.
1545
    */
1546
88.5k
   while (location != (location & -location))
1547
8.57k
      location &= ~(location & -location);
1548
1549
   /* The cast is safe because 'location' is a bit mask and only the low four
1550
    * bits are significant.
1551
    */
1552
80.0k
   return (png_byte)location;
1553
82.3k
}
1554
1555
void
1556
png_set_unknown_chunks(const png_struct *png_ptr,
1557
    png_info *info_ptr, const png_unknown_chunk *unknowns, int num_unknowns)
1558
82.3k
{
1559
82.3k
   png_unknown_chunk *np;
1560
82.3k
   png_unknown_chunk *old_unknowns;
1561
1562
82.3k
   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
1563
82.3k
       unknowns == NULL)
1564
0
      return;
1565
1566
   /* Check for the failure cases where support has been disabled at compile
1567
    * time.  This code is hardly ever compiled - it's here because
1568
    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
1569
    * code) but may be meaningless if the read or write handling of unknown
1570
    * chunks is not compiled in.
1571
    */
1572
#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
1573
      defined(PNG_READ_SUPPORTED)
1574
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1575
      {
1576
         png_app_error(png_ptr, "no unknown chunk support on read");
1577
1578
         return;
1579
      }
1580
#  endif
1581
#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
1582
      defined(PNG_WRITE_SUPPORTED)
1583
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1584
      {
1585
         png_app_error(png_ptr, "no unknown chunk support on write");
1586
1587
         return;
1588
      }
1589
#  endif
1590
1591
   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
1592
    * unknown critical chunks could be lost with just a warning resulting in
1593
    * undefined behavior.  Now png_chunk_report is used to provide behavior
1594
    * appropriate to read or write.
1595
    */
1596
82.3k
   np = png_voidcast(png_unknown_chunk *, png_realloc_array(png_ptr,
1597
82.3k
       info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
1598
82.3k
       sizeof *np));
1599
1600
82.3k
   if (np == NULL)
1601
0
   {
1602
0
      png_chunk_report(png_ptr, "too many unknown chunks",
1603
0
          PNG_CHUNK_WRITE_ERROR);
1604
0
      return;
1605
0
   }
1606
1607
   /* Defer freeing the old array until after the copy loop below,
1608
    * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
1609
    */
1610
82.3k
   old_unknowns = info_ptr->unknown_chunks;
1611
1612
82.3k
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
1613
82.3k
   info_ptr->free_me |= PNG_FREE_UNKN;
1614
1615
82.3k
   np += info_ptr->unknown_chunks_num;
1616
1617
   /* Increment unknown_chunks_num each time round the loop to protect the
1618
    * just-allocated chunk data.
1619
    */
1620
164k
   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
1621
82.3k
   {
1622
82.3k
      memcpy(np->name, unknowns->name, (sizeof np->name));
1623
82.3k
      np->name[(sizeof np->name)-1] = '\0';
1624
82.3k
      np->location = check_location(png_ptr, unknowns->location);
1625
1626
82.3k
      if (unknowns->size == 0)
1627
43.9k
      {
1628
43.9k
         np->data = NULL;
1629
43.9k
         np->size = 0;
1630
43.9k
      }
1631
1632
38.4k
      else
1633
38.4k
      {
1634
38.4k
         np->data = png_voidcast(png_byte *,
1635
38.4k
             png_malloc_base(png_ptr, unknowns->size));
1636
1637
38.4k
         if (np->data == NULL)
1638
0
         {
1639
0
            png_chunk_report(png_ptr, "unknown chunk: out of memory",
1640
0
                PNG_CHUNK_WRITE_ERROR);
1641
            /* But just skip storing the unknown chunk */
1642
0
            continue;
1643
0
         }
1644
1645
38.4k
         memcpy(np->data, unknowns->data, unknowns->size);
1646
38.4k
         np->size = unknowns->size;
1647
38.4k
      }
1648
1649
      /* These increments are skipped on out-of-memory for the data - the
1650
       * unknown chunk entry gets overwritten if the png_chunk_report returns.
1651
       * This is correct in the read case (the chunk is just dropped.)
1652
       */
1653
82.3k
      ++np;
1654
82.3k
      ++(info_ptr->unknown_chunks_num);
1655
82.3k
   }
1656
1657
82.3k
   png_free(png_ptr, old_unknowns);
1658
82.3k
}
1659
1660
void
1661
png_set_unknown_chunk_location(const png_struct *png_ptr, png_info *info_ptr,
1662
    int chunk, int location)
1663
0
{
1664
   /* This API is pretty pointless in 1.6.0 because the location can be set
1665
    * before the call to png_set_unknown_chunks.
1666
    *
1667
    * TODO: add a png_app_warning in 1.7
1668
    */
1669
0
   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
1670
0
      chunk < info_ptr->unknown_chunks_num)
1671
0
   {
1672
0
      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
1673
0
      {
1674
0
         png_app_error(png_ptr, "invalid unknown chunk location");
1675
         /* Fake out the pre 1.6.0 behavior: */
1676
0
         if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */
1677
0
            location = PNG_AFTER_IDAT;
1678
1679
0
         else
1680
0
            location = PNG_HAVE_IHDR; /* also undocumented */
1681
0
      }
1682
1683
0
      info_ptr->unknown_chunks[chunk].location =
1684
0
         check_location(png_ptr, location);
1685
0
   }
1686
0
}
1687
#endif /* STORE_UNKNOWN_CHUNKS */
1688
1689
#ifdef PNG_MNG_FEATURES_SUPPORTED
1690
png_uint_32
1691
png_permit_mng_features(png_struct *png_ptr, png_uint_32 mng_features)
1692
6.09k
{
1693
6.09k
   png_debug(1, "in png_permit_mng_features");
1694
1695
6.09k
   if (png_ptr == NULL)
1696
0
      return 0;
1697
1698
6.09k
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1699
1700
6.09k
   return png_ptr->mng_features_permitted;
1701
6.09k
}
1702
#endif
1703
1704
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1705
static unsigned int
1706
add_one_chunk(png_byte *list, unsigned int count, const png_byte *add, int keep)
1707
828k
{
1708
828k
   unsigned int i;
1709
1710
   /* Utility function: update the 'keep' state of a chunk if it is already in
1711
    * the list, otherwise add it to the list.
1712
    */
1713
4.55M
   for (i=0; i<count; ++i, list += 5)
1714
3.72M
   {
1715
3.72M
      if (memcmp(list, add, 4) == 0)
1716
0
      {
1717
0
         list[4] = (png_byte)keep;
1718
1719
0
         return count;
1720
0
      }
1721
3.72M
   }
1722
1723
828k
   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
1724
828k
   {
1725
828k
      ++count;
1726
828k
      memcpy(list, add, 4);
1727
828k
      list[4] = (png_byte)keep;
1728
828k
   }
1729
1730
828k
   return count;
1731
828k
}
1732
1733
void
1734
png_set_keep_unknown_chunks(png_struct *png_ptr, int keep,
1735
    const png_byte *chunk_list, int num_chunks_in)
1736
331k
{
1737
331k
   png_byte *new_list;
1738
331k
   unsigned int num_chunks, old_num_chunks;
1739
1740
331k
   if (png_ptr == NULL)
1741
0
      return;
1742
1743
331k
   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
1744
0
   {
1745
0
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
1746
1747
0
      return;
1748
0
   }
1749
1750
331k
   if (num_chunks_in <= 0)
1751
82.8k
   {
1752
82.8k
      png_ptr->unknown_default = keep;
1753
1754
      /* '0' means just set the flags, so stop here */
1755
82.8k
      if (num_chunks_in == 0)
1756
82.8k
        return;
1757
82.8k
   }
1758
1759
248k
   if (num_chunks_in < 0)
1760
0
   {
1761
      /* Ignore all unknown chunks and all chunks recognized by
1762
       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
1763
       */
1764
0
      static const png_byte chunks_to_ignore[] = {
1765
0
         97,  99,  84,  76, '\0',  /* acTL */
1766
0
         98,  75,  71,  68, '\0',  /* bKGD */
1767
0
         99,  72,  82,  77, '\0',  /* cHRM */
1768
0
         99,  73,  67,  80, '\0',  /* cICP */
1769
0
         99,  76,  76,  73, '\0',  /* cLLI */
1770
0
        101,  88,  73, 102, '\0',  /* eXIf */
1771
0
        102,  99,  84,  76, '\0',  /* fcTL */
1772
0
        102, 100,  65,  84, '\0',  /* fdAT */
1773
0
        103,  65,  77,  65, '\0',  /* gAMA */
1774
0
        104,  73,  83,  84, '\0',  /* hIST */
1775
0
        105,  67,  67,  80, '\0',  /* iCCP */
1776
0
        105,  84,  88, 116, '\0',  /* iTXt */
1777
0
        109,  68,  67,  86, '\0',  /* mDCV */
1778
0
        111,  70,  70, 115, '\0',  /* oFFs */
1779
0
        112,  67,  65,  76, '\0',  /* pCAL */
1780
0
        112,  72,  89, 115, '\0',  /* pHYs */
1781
0
        115,  66,  73,  84, '\0',  /* sBIT */
1782
0
        115,  67,  65,  76, '\0',  /* sCAL */
1783
0
        115,  80,  76,  84, '\0',  /* sPLT */
1784
0
        115,  84,  69,  82, '\0',  /* sTER */
1785
0
        115,  82,  71,  66, '\0',  /* sRGB */
1786
0
        116,  69,  88, 116, '\0',  /* tEXt */
1787
0
        116,  73,  77,  69, '\0',  /* tIME */
1788
0
        122,  84,  88, 116, '\0'   /* zTXt */
1789
0
      };
1790
1791
0
      chunk_list = chunks_to_ignore;
1792
0
      num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U;
1793
0
   }
1794
1795
248k
   else /* num_chunks_in > 0 */
1796
248k
   {
1797
248k
      if (chunk_list == NULL)
1798
0
      {
1799
         /* Prior to 1.6.0 this was silently ignored, now it is an app_error
1800
          * which can be switched off.
1801
          */
1802
0
         png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
1803
1804
0
         return;
1805
0
      }
1806
1807
248k
      num_chunks = (unsigned int)num_chunks_in;
1808
248k
   }
1809
1810
248k
   old_num_chunks = png_ptr->num_chunk_list;
1811
248k
   if (png_ptr->chunk_list == NULL)
1812
82.8k
      old_num_chunks = 0;
1813
1814
   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
1815
    */
1816
248k
   if (num_chunks + old_num_chunks > UINT_MAX/5)
1817
0
   {
1818
0
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
1819
1820
0
      return;
1821
0
   }
1822
1823
   /* If these chunks are being reset to the default then no more memory is
1824
    * required because add_one_chunk above doesn't extend the list if the 'keep'
1825
    * parameter is the default.
1826
    */
1827
248k
   if (keep != 0)
1828
248k
   {
1829
248k
      new_list = png_voidcast(png_byte *, png_malloc(png_ptr,
1830
248k
          5 * (num_chunks + old_num_chunks)));
1831
1832
248k
      if (old_num_chunks > 0)
1833
165k
         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1834
248k
   }
1835
1836
0
   else if (old_num_chunks > 0)
1837
0
      new_list = png_ptr->chunk_list;
1838
1839
0
   else
1840
0
      new_list = NULL;
1841
1842
   /* Add the new chunks together with each one's handling code.  If the chunk
1843
    * already exists the code is updated, otherwise the chunk is added to the
1844
    * end.  (In libpng 1.6.0 order no longer matters because this code enforces
1845
    * the earlier convention that the last setting is the one that is used.)
1846
    */
1847
248k
   if (new_list != NULL)
1848
248k
   {
1849
248k
      const png_byte *inlist;
1850
248k
      png_byte *outlist;
1851
248k
      unsigned int i;
1852
1853
1.07M
      for (i=0; i<num_chunks; ++i)
1854
828k
      {
1855
828k
         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
1856
828k
             chunk_list+5*i, keep);
1857
828k
      }
1858
1859
      /* Now remove any spurious 'default' entries. */
1860
248k
      num_chunks = 0;
1861
1.32M
      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1862
1.07M
      {
1863
1.07M
         if (inlist[4])
1864
1.07M
         {
1865
1.07M
            if (outlist != inlist)
1866
0
               memcpy(outlist, inlist, 5);
1867
1.07M
            outlist += 5;
1868
1.07M
            ++num_chunks;
1869
1.07M
         }
1870
1.07M
      }
1871
1872
      /* This means the application has removed all the specialized handling. */
1873
248k
      if (num_chunks == 0)
1874
0
      {
1875
0
         if (png_ptr->chunk_list != new_list)
1876
0
            png_free(png_ptr, new_list);
1877
1878
0
         new_list = NULL;
1879
0
      }
1880
248k
   }
1881
1882
0
   else
1883
0
      num_chunks = 0;
1884
1885
248k
   png_ptr->num_chunk_list = num_chunks;
1886
1887
248k
   if (png_ptr->chunk_list != new_list)
1888
248k
   {
1889
248k
      if (png_ptr->chunk_list != NULL)
1890
165k
         png_free(png_ptr, png_ptr->chunk_list);
1891
1892
248k
      png_ptr->chunk_list = new_list;
1893
248k
   }
1894
248k
}
1895
#endif
1896
1897
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1898
void
1899
png_set_read_user_chunk_fn(png_struct *png_ptr, void *user_chunk_ptr,
1900
    png_user_chunk_ptr read_user_chunk_fn)
1901
82.8k
{
1902
82.8k
   png_debug(1, "in png_set_read_user_chunk_fn");
1903
1904
82.8k
   if (png_ptr == NULL)
1905
0
      return;
1906
1907
82.8k
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
1908
82.8k
   png_ptr->user_chunk_ptr = user_chunk_ptr;
1909
82.8k
}
1910
#endif
1911
1912
#ifdef PNG_INFO_IMAGE_SUPPORTED
1913
void
1914
png_set_rows(const png_struct *png_ptr, png_info *info_ptr,
1915
    png_byte **row_pointers)
1916
0
{
1917
0
   png_debug(1, "in png_set_rows");
1918
1919
0
   if (png_ptr == NULL || info_ptr == NULL)
1920
0
      return;
1921
1922
0
   if (info_ptr->row_pointers != NULL &&
1923
0
       (info_ptr->row_pointers != row_pointers))
1924
0
      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1925
1926
0
   info_ptr->row_pointers = row_pointers;
1927
1928
0
   if (row_pointers != NULL)
1929
0
      info_ptr->valid |= PNG_INFO_IDAT;
1930
0
}
1931
#endif
1932
1933
void
1934
png_set_compression_buffer_size(png_struct *png_ptr, size_t size)
1935
1.92k
{
1936
1.92k
   png_debug(1, "in png_set_compression_buffer_size");
1937
1938
1.92k
   if (png_ptr == NULL)
1939
0
      return;
1940
1941
1.92k
   if (size == 0 || size > PNG_UINT_31_MAX)
1942
0
      png_error(png_ptr, "invalid compression buffer size");
1943
1944
1.92k
#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1945
1.92k
   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1946
0
   {
1947
0
      png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
1948
0
      return;
1949
0
   }
1950
1.92k
#  endif
1951
1952
1.92k
#  ifdef PNG_WRITE_SUPPORTED
1953
1.92k
   if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1954
1.92k
   {
1955
1.92k
      if (png_ptr->zowner != 0)
1956
0
      {
1957
0
         png_warning(png_ptr,
1958
0
             "Compression buffer size cannot be changed because it is in use");
1959
1960
0
         return;
1961
0
      }
1962
1963
1.92k
#ifndef __COVERITY__
1964
      /* Some compilers complain that this is always false.  However, it
1965
       * can be true when integer overflow happens.
1966
       */
1967
1.92k
      if (size > ZLIB_IO_MAX)
1968
0
      {
1969
0
         png_warning(png_ptr,
1970
0
             "Compression buffer size limited to system maximum");
1971
0
         size = ZLIB_IO_MAX; /* must fit */
1972
0
      }
1973
1.92k
#endif
1974
1975
1.92k
      if (size < 6)
1976
0
      {
1977
         /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
1978
          * if this is permitted.
1979
          */
1980
0
         png_warning(png_ptr,
1981
0
             "Compression buffer size cannot be reduced below 6");
1982
1983
0
         return;
1984
0
      }
1985
1986
1.92k
      if (png_ptr->zbuffer_size != size)
1987
1.92k
      {
1988
1.92k
         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
1989
1.92k
         png_ptr->zbuffer_size = (uInt)size;
1990
1.92k
      }
1991
1.92k
   }
1992
1.92k
#  endif
1993
1.92k
}
1994
1995
void
1996
png_set_invalid(const png_struct *png_ptr, png_info *info_ptr, int mask)
1997
204
{
1998
204
   if (png_ptr != NULL && info_ptr != NULL)
1999
204
      info_ptr->valid &= (unsigned int)(~mask);
2000
204
}
2001
2002
2003
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
2004
/* This function was added to libpng 1.2.6 */
2005
void
2006
png_set_user_limits(png_struct *png_ptr, png_uint_32 user_width_max,
2007
    png_uint_32 user_height_max)
2008
84.7k
{
2009
84.7k
   png_debug(1, "in png_set_user_limits");
2010
2011
   /* Images with dimensions larger than these limits will be
2012
    * rejected by png_set_IHDR().  To accept any PNG datastream
2013
    * regardless of dimensions, set both limits to 0x7fffffff.
2014
    */
2015
84.7k
   if (png_ptr == NULL)
2016
0
      return;
2017
2018
84.7k
   png_ptr->user_width_max = user_width_max;
2019
84.7k
   png_ptr->user_height_max = user_height_max;
2020
84.7k
}
2021
2022
/* This function was added to libpng 1.4.0 */
2023
void
2024
png_set_chunk_cache_max(png_struct *png_ptr, png_uint_32 user_chunk_cache_max)
2025
82.8k
{
2026
82.8k
   png_debug(1, "in png_set_chunk_cache_max");
2027
2028
82.8k
   if (png_ptr != NULL)
2029
82.8k
      png_ptr->user_chunk_cache_max = user_chunk_cache_max;
2030
82.8k
}
2031
2032
/* This function was added to libpng 1.4.1 */
2033
void
2034
png_set_chunk_malloc_max(png_struct *png_ptr,
2035
    png_alloc_size_t user_chunk_malloc_max)
2036
0
{
2037
0
   png_debug(1, "in png_set_chunk_malloc_max");
2038
2039
   /* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in
2040
    * png.c.  This API supports '0' for unlimited, make sure the correct
2041
    * (unlimited) value is set here to avoid a need to check for 0 everywhere
2042
    * the parameter is used.
2043
    */
2044
0
   if (png_ptr != NULL)
2045
0
   {
2046
0
      if (user_chunk_malloc_max == 0U) /* unlimited */
2047
0
      {
2048
#        ifdef PNG_MAX_MALLOC_64K
2049
            png_ptr->user_chunk_malloc_max = 65536U;
2050
#        else
2051
0
            png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX;
2052
0
#        endif
2053
0
      }
2054
0
      else
2055
0
         png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
2056
0
   }
2057
0
}
2058
#endif /* ?SET_USER_LIMITS */
2059
2060
2061
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
2062
void
2063
png_set_benign_errors(png_struct *png_ptr, int allowed)
2064
84.7k
{
2065
84.7k
   png_debug(1, "in png_set_benign_errors");
2066
2067
   /* If allowed is 1, png_benign_error() is treated as a warning.
2068
    *
2069
    * If allowed is 0, png_benign_error() is treated as an error (which
2070
    * is the default behavior if png_set_benign_errors() is not called).
2071
    */
2072
2073
84.7k
   if (allowed != 0)
2074
84.7k
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
2075
84.7k
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
2076
2077
0
   else
2078
0
      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
2079
0
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
2080
84.7k
}
2081
#endif /* BENIGN_ERRORS */
2082
2083
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
2084
   /* Whether to report invalid palette index; added at libpng-1.5.10.
2085
    * It is possible for an indexed (color-type==3) PNG file to contain
2086
    * pixels with invalid (out-of-range) indexes if the PLTE chunk has
2087
    * fewer entries than the image's bit-depth would allow. We recover
2088
    * from this gracefully by filling any incomplete palette with zeros
2089
    * (opaque black).  By default, when this occurs libpng will issue
2090
    * a benign error.  This API can be used to override that behavior.
2091
    */
2092
void
2093
png_set_check_for_invalid_index(png_struct *png_ptr, int allowed)
2094
82.8k
{
2095
82.8k
   png_debug(1, "in png_set_check_for_invalid_index");
2096
2097
82.8k
   if (allowed > 0)
2098
0
      png_ptr->num_palette_max = 0;
2099
2100
82.8k
   else
2101
82.8k
      png_ptr->num_palette_max = -1;
2102
82.8k
}
2103
#endif
2104
2105
#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \
2106
    defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
2107
/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
2108
 * and if invalid, correct the keyword rather than discarding the entire
2109
 * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
2110
 * length, forbids leading or trailing whitespace, multiple internal spaces,
2111
 * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
2112
 *
2113
 * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
2114
 * trailing '\0').  If this routine returns 0 then there was no keyword, or a
2115
 * valid one could not be generated, and the caller must png_error.
2116
 */
2117
png_uint_32 /* PRIVATE */
2118
png_check_keyword(png_struct *png_ptr, const char *key, png_byte *new_key)
2119
6.43k
{
2120
6.43k
#ifdef PNG_WARNINGS_SUPPORTED
2121
6.43k
   const char *orig_key = key;
2122
6.43k
#endif
2123
6.43k
   png_uint_32 key_len = 0;
2124
6.43k
   int bad_character = 0;
2125
6.43k
   int space = 1;
2126
2127
6.43k
   png_debug(1, "in png_check_keyword");
2128
2129
6.43k
   if (key == NULL)
2130
0
   {
2131
0
      *new_key = 0;
2132
0
      return 0;
2133
0
   }
2134
2135
80.3k
   while (*key && key_len < 79)
2136
73.9k
   {
2137
73.9k
      png_byte ch = (png_byte)*key++;
2138
2139
73.9k
      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
2140
73.5k
      {
2141
73.5k
         *new_key++ = ch; ++key_len; space = 0;
2142
73.5k
      }
2143
2144
353
      else if (space == 0)
2145
331
      {
2146
         /* A space or an invalid character when one wasn't seen immediately
2147
          * before; output just a space.
2148
          */
2149
331
         *new_key++ = 32; ++key_len; space = 1;
2150
2151
         /* If the character was not a space then it is invalid. */
2152
331
         if (ch != 32)
2153
283
            bad_character = ch;
2154
331
      }
2155
2156
22
      else if (bad_character == 0)
2157
1
         bad_character = ch; /* just skip it, record the first error */
2158
73.9k
   }
2159
2160
6.43k
   if (key_len > 0 && space != 0) /* trailing space */
2161
276
   {
2162
276
      --key_len; --new_key;
2163
276
      if (bad_character == 0)
2164
0
         bad_character = 32;
2165
276
   }
2166
2167
   /* Terminate the keyword */
2168
6.43k
   *new_key = 0;
2169
2170
6.43k
   if (key_len == 0)
2171
0
      return 0;
2172
2173
6.43k
#ifdef PNG_WARNINGS_SUPPORTED
2174
   /* Try to only output one warning per keyword: */
2175
6.43k
   if (*key != 0) /* keyword too long */
2176
0
      png_warning(png_ptr, "keyword truncated");
2177
2178
6.43k
   else if (bad_character != 0)
2179
282
   {
2180
282
      PNG_WARNING_PARAMETERS(p)
2181
2182
282
      png_warning_parameter(p, 1, orig_key);
2183
282
      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
2184
2185
282
      png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
2186
282
   }
2187
#else /* !WARNINGS */
2188
   PNG_UNUSED(png_ptr)
2189
#endif /* !WARNINGS */
2190
2191
6.43k
   return key_len;
2192
6.43k
}
2193
#endif /* TEXT || pCAL || iCCP || sPLT */
2194
#endif /* READ || WRITE */