Coverage Report

Created: 2026-06-30 07:12

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
2.00k
{
27
2.00k
   png_debug1(1, "in %s storage function", "bKGD");
28
29
2.00k
   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
30
0
      return;
31
32
2.00k
   info_ptr->background = *background;
33
2.00k
   info_ptr->valid |= PNG_INFO_bKGD;
34
2.00k
}
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.21k
{
44
1.21k
   png_debug1(1, "in %s storage function", "cHRM fixed");
45
46
1.21k
   if (png_ptr == NULL || info_ptr == NULL)
47
0
      return;
48
49
1.21k
   info_ptr->cHRM.redx = red_x;
50
1.21k
   info_ptr->cHRM.redy = red_y;
51
1.21k
   info_ptr->cHRM.greenx = green_x;
52
1.21k
   info_ptr->cHRM.greeny = green_y;
53
1.21k
   info_ptr->cHRM.bluex = blue_x;
54
1.21k
   info_ptr->cHRM.bluey = blue_y;
55
1.21k
   info_ptr->cHRM.whitex = white_x;
56
1.21k
   info_ptr->cHRM.whitey = white_y;
57
58
1.21k
   info_ptr->valid |= PNG_INFO_cHRM;
59
1.21k
}
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
759
{
103
759
   png_set_cHRM_fixed(png_ptr, info_ptr,
104
759
       png_fixed(png_ptr, white_x, "cHRM White X"),
105
759
       png_fixed(png_ptr, white_y, "cHRM White Y"),
106
759
       png_fixed(png_ptr, red_x, "cHRM Red X"),
107
759
       png_fixed(png_ptr, red_y, "cHRM Red Y"),
108
759
       png_fixed(png_ptr, green_x, "cHRM Green X"),
109
759
       png_fixed(png_ptr, green_y, "cHRM Green Y"),
110
759
       png_fixed(png_ptr, blue_x, "cHRM Blue X"),
111
759
       png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
112
759
}
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
61
{
168
61
   png_debug1(1, "in %s storage function", "cLLI");
169
170
61
   if (png_ptr == NULL || info_ptr == NULL)
171
0
      return;
172
173
   /* Check the light level range: */
174
61
   if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU)
175
45
   {
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
45
      png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit",
183
45
            PNG_CHUNK_WRITE_ERROR);
184
45
      return;
185
45
   }
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
102
   {
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
102
      png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit",
270
102
            PNG_CHUNK_WRITE_ERROR);
271
102
      return;
272
102
   }
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
84
   info_ptr->mastering_red_x = rx;
283
84
   info_ptr->mastering_red_y = ry;
284
84
   info_ptr->mastering_green_x = gx;
285
84
   info_ptr->mastering_green_y = gy;
286
84
   info_ptr->mastering_blue_x = bx;
287
84
   info_ptr->mastering_blue_y = by;
288
84
   info_ptr->mastering_white_x = wx;
289
84
   info_ptr->mastering_white_y = wy;
290
84
   info_ptr->mastering_maxDL = maxDL;
291
84
   info_ptr->mastering_minDL = minDL;
292
84
   info_ptr->valid |= PNG_INFO_mDCV;
293
84
}
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
32
{
322
32
   png_byte *new_exif;
323
324
32
   png_debug1(1, "in %s storage function", "eXIf");
325
326
32
   if (png_ptr == NULL || info_ptr == NULL ||
327
32
       (png_ptr->mode & PNG_WROTE_eXIf) != 0 ||
328
32
       exif == NULL)
329
0
      return;
330
331
32
   new_exif = png_voidcast(png_byte *, png_malloc_warn(png_ptr, num_exif));
332
333
32
   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
32
   memcpy(new_exif, exif, (size_t)num_exif);
340
341
32
   png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
342
343
32
   info_ptr->num_exif = num_exif;
344
32
   info_ptr->exif = new_exif;
345
32
   info_ptr->free_me |= PNG_FREE_EXIF;
346
32
   info_ptr->valid |= PNG_INFO_eXIf;
347
32
}
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
682
{
355
682
   png_debug1(1, "in %s storage function", "gAMA");
356
357
682
   if (png_ptr == NULL || info_ptr == NULL)
358
0
      return;
359
360
682
   info_ptr->gamma = file_gamma;
361
682
   info_ptr->valid |= PNG_INFO_gAMA;
362
682
}
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
67.7k
{
431
67.7k
   png_debug1(1, "in %s storage function", "IHDR");
432
433
67.7k
   if (png_ptr == NULL || info_ptr == NULL)
434
0
      return;
435
436
67.7k
   info_ptr->width = width;
437
67.7k
   info_ptr->height = height;
438
67.7k
   info_ptr->bit_depth = (png_byte)bit_depth;
439
67.7k
   info_ptr->color_type = (png_byte)color_type;
440
67.7k
   info_ptr->compression_type = (png_byte)compression_type;
441
67.7k
   info_ptr->filter_type = (png_byte)filter_type;
442
67.7k
   info_ptr->interlace_type = (png_byte)interlace_type;
443
444
67.7k
   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
445
67.7k
       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
446
67.7k
       info_ptr->compression_type, info_ptr->filter_type);
447
448
67.7k
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
449
7.13k
      info_ptr->channels = 1;
450
451
60.5k
   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
452
18.6k
      info_ptr->channels = 3;
453
454
41.8k
   else
455
41.8k
      info_ptr->channels = 1;
456
457
67.7k
   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
458
7.91k
      info_ptr->channels++;
459
460
67.7k
   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
461
462
67.7k
   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
463
464
67.7k
#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
67.7k
   info_ptr->num_frames = 1;
469
67.7k
#endif
470
67.7k
}
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
66
{
477
66
   png_debug1(1, "in %s storage function", "oFFs");
478
479
66
   if (png_ptr == NULL || info_ptr == NULL)
480
0
      return;
481
482
66
   info_ptr->x_offset = offset_x;
483
66
   info_ptr->y_offset = offset_y;
484
66
   info_ptr->offset_unit_type = (png_byte)unit_type;
485
66
   info_ptr->valid |= PNG_INFO_oFFs;
486
66
}
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
311
{
735
311
   png_debug1(1, "in %s storage function", "pHYs");
736
737
311
   if (png_ptr == NULL || info_ptr == NULL)
738
0
      return;
739
740
311
   info_ptr->x_pixels_per_unit = res_x;
741
311
   info_ptr->y_pixels_per_unit = res_y;
742
311
   info_ptr->phys_unit_type = (png_byte)unit_type;
743
311
   info_ptr->valid |= PNG_INFO_pHYs;
744
311
}
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.76k
{
751
2.76k
   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
752
2.76k
   png_uint_32 max_palette_length;
753
754
2.76k
   png_debug1(1, "in %s storage function", "PLTE");
755
756
2.76k
   if (png_ptr == NULL || info_ptr == NULL)
757
0
      return;
758
759
2.76k
   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
760
2.52k
      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
761
762
2.76k
   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.76k
   if ((num_palette > 0 && palette == NULL) ||
776
2.76k
      (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.76k
#        endif
780
2.76k
      ))
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.75k
   if (num_palette > 0)
789
2.71k
      memcpy(safe_palette, palette, (unsigned int)num_palette *
790
2.71k
          (sizeof (png_color)));
791
792
2.75k
   palette = safe_palette;
793
794
2.75k
   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.75k
   png_free(png_ptr, png_ptr->palette);
812
2.75k
   png_ptr->palette = NULL;
813
2.75k
   png_ptr->palette = png_voidcast(png_color *, png_calloc(png_ptr,
814
2.75k
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
815
2.75k
   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
816
2.75k
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
817
2.75k
   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
818
819
2.75k
   if (num_palette > 0)
820
2.71k
   {
821
2.71k
      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
822
2.71k
          (sizeof (png_color)));
823
2.71k
      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
824
2.71k
          (sizeof (png_color)));
825
2.71k
   }
826
827
2.75k
   info_ptr->free_me |= PNG_FREE_PLTE;
828
2.75k
   info_ptr->valid |= PNG_INFO_PLTE;
829
2.75k
}
830
831
#ifdef PNG_sBIT_SUPPORTED
832
void
833
png_set_sBIT(const png_struct *png_ptr, png_info *info_ptr,
834
    const png_color_8 *sig_bit)
835
86
{
836
86
   png_debug1(1, "in %s storage function", "sBIT");
837
838
86
   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
839
0
      return;
840
841
86
   info_ptr->sig_bit = *sig_bit;
842
86
   info_ptr->valid |= PNG_INFO_sBIT;
843
86
}
844
#endif
845
846
#ifdef PNG_sRGB_SUPPORTED
847
void
848
png_set_sRGB(const png_struct *png_ptr, png_info *info_ptr, int srgb_intent)
849
114
{
850
114
   png_debug1(1, "in %s storage function", "sRGB");
851
852
114
   if (png_ptr == NULL || info_ptr == NULL)
853
0
      return;
854
855
114
   info_ptr->rendering_intent = srgb_intent;
856
114
   info_ptr->valid |= PNG_INFO_sRGB;
857
114
}
858
859
void
860
png_set_sRGB_gAMA_and_cHRM(const png_struct *png_ptr, png_info *info_ptr,
861
    int srgb_intent)
862
0
{
863
0
   png_debug1(1, "in %s storage function", "sRGB_gAMA_and_cHRM");
864
865
0
   if (png_ptr == NULL || info_ptr == NULL)
866
0
      return;
867
868
0
   png_set_sRGB(png_ptr, info_ptr, srgb_intent);
869
870
0
#  ifdef PNG_gAMA_SUPPORTED
871
0
      png_set_gAMA_fixed(png_ptr, info_ptr, PNG_GAMMA_sRGB_INVERSE);
872
0
#  endif /* gAMA */
873
874
0
#  ifdef PNG_cHRM_SUPPORTED
875
0
      png_set_cHRM_fixed(png_ptr, info_ptr,
876
         /* color      x       y */
877
0
         /* white */ 31270, 32900,
878
0
         /* red   */ 64000, 33000,
879
0
         /* green */ 30000, 60000,
880
0
         /* blue  */ 15000,  6000);
881
0
#  endif /* cHRM */
882
0
}
883
#endif /* sRGB */
884
885
886
#ifdef PNG_iCCP_SUPPORTED
887
void
888
png_set_iCCP(const png_struct *png_ptr, png_info *info_ptr,
889
    const char *name, int compression_type,
890
    const png_byte *profile, png_uint_32 proflen)
891
17
{
892
17
   char *new_iccp_name;
893
17
   png_byte *new_iccp_profile;
894
17
   size_t length;
895
896
17
   png_debug1(1, "in %s storage function", "iCCP");
897
898
17
   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
899
0
      return;
900
901
17
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
902
0
      png_app_error(png_ptr, "Invalid iCCP compression method");
903
904
17
   length = strlen(name)+1;
905
17
   new_iccp_name = png_voidcast(char *, png_malloc_warn(png_ptr, length));
906
907
17
   if (new_iccp_name == NULL)
908
0
   {
909
0
      png_benign_error(png_ptr, "Insufficient memory to process iCCP chunk");
910
911
0
      return;
912
0
   }
913
914
17
   memcpy(new_iccp_name, name, length);
915
17
   new_iccp_profile = png_voidcast(png_byte *,
916
17
       png_malloc_warn(png_ptr, proflen));
917
918
17
   if (new_iccp_profile == NULL)
919
0
   {
920
0
      png_free(png_ptr, new_iccp_name);
921
0
      png_benign_error(png_ptr,
922
0
          "Insufficient memory to process iCCP profile");
923
924
0
      return;
925
0
   }
926
927
17
   memcpy(new_iccp_profile, profile, proflen);
928
929
17
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
930
931
17
   info_ptr->iccp_proflen = proflen;
932
17
   info_ptr->iccp_name = new_iccp_name;
933
17
   info_ptr->iccp_profile = new_iccp_profile;
934
17
   info_ptr->free_me |= PNG_FREE_ICCP;
935
17
   info_ptr->valid |= PNG_INFO_iCCP;
936
17
}
937
#endif
938
939
#ifdef PNG_TEXT_SUPPORTED
940
void
941
png_set_text(const png_struct *png_ptr, png_info *info_ptr,
942
    const png_text *text_ptr, int num_text)
943
6.42k
{
944
6.42k
   int ret;
945
6.42k
   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
946
947
6.42k
   if (ret != 0)
948
0
      png_error(png_ptr, "Insufficient memory to store text");
949
6.42k
}
950
951
int /* PRIVATE */
952
png_set_text_2(const png_struct *png_ptr, png_info *info_ptr,
953
    const png_text *text_ptr, int num_text)
954
51.9k
{
955
51.9k
   int i;
956
51.9k
   png_textp old_text = NULL;
957
958
51.9k
   png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
959
51.9k
      png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
960
961
51.9k
   if (png_ptr == NULL || info_ptr == NULL || num_text <= 0 || text_ptr == NULL)
962
0
      return 0;
963
964
   /* Make sure we have enough space in the "text" array in info_struct
965
    * to hold all of the incoming text_ptr objects.  This compare can't overflow
966
    * because max_text >= num_text (anyway, subtract of two positive integers
967
    * can't overflow in any case.)
968
    */
969
51.9k
   if (num_text > info_ptr->max_text - info_ptr->num_text)
970
8.77k
   {
971
8.77k
      int old_num_text = info_ptr->num_text;
972
8.77k
      int max_text;
973
8.77k
      png_text *new_text = NULL;
974
975
      /* Calculate an appropriate max_text, checking for overflow. */
976
8.77k
      max_text = old_num_text;
977
8.77k
      if (num_text <= INT_MAX - max_text)
978
8.77k
      {
979
8.77k
         max_text += num_text;
980
981
         /* Round up to a multiple of 8 */
982
8.77k
         if (max_text < INT_MAX-8)
983
8.77k
            max_text = (max_text + 8) & ~0x7;
984
985
0
         else
986
0
            max_text = INT_MAX;
987
988
         /* Now allocate a new array and copy the old members in; this does all
989
          * the overflow checks.
990
          */
991
8.77k
         new_text = png_voidcast(png_text *,png_realloc_array(png_ptr,
992
8.77k
             info_ptr->text, old_num_text, max_text-old_num_text,
993
8.77k
             sizeof *new_text));
994
8.77k
      }
995
996
8.77k
      if (new_text == NULL)
997
0
      {
998
0
         png_chunk_report(png_ptr, "too many text chunks",
999
0
             PNG_CHUNK_WRITE_ERROR);
1000
1001
0
         return 1;
1002
0
      }
1003
1004
      /* Defer freeing the old array until after the copy loop below,
1005
       * in case text_ptr aliases info_ptr->text (getter-to-setter).
1006
       */
1007
8.77k
      old_text = info_ptr->text;
1008
1009
8.77k
      info_ptr->text = new_text;
1010
8.77k
      info_ptr->free_me |= PNG_FREE_TEXT;
1011
8.77k
      info_ptr->max_text = max_text;
1012
      /* num_text is adjusted below as the entries are copied in */
1013
1014
8.77k
      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
1015
8.77k
   }
1016
1017
103k
   for (i = 0; i < num_text; i++)
1018
51.9k
   {
1019
51.9k
      size_t text_length, key_len;
1020
51.9k
      size_t lang_len, lang_key_len;
1021
51.9k
      png_text *textp = &(info_ptr->text[info_ptr->num_text]);
1022
1023
51.9k
      if (text_ptr[i].key == NULL)
1024
0
          continue;
1025
1026
51.9k
      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
1027
51.9k
          text_ptr[i].compression >= PNG_TEXT_COMPRESSION_LAST)
1028
0
      {
1029
0
         png_chunk_report(png_ptr, "text compression mode is out of range",
1030
0
             PNG_CHUNK_WRITE_ERROR);
1031
0
         continue;
1032
0
      }
1033
1034
51.9k
      key_len = strlen(text_ptr[i].key);
1035
1036
51.9k
      if (text_ptr[i].compression <= 0)
1037
51.9k
      {
1038
51.9k
         lang_len = 0;
1039
51.9k
         lang_key_len = 0;
1040
51.9k
      }
1041
1042
65
      else
1043
65
#  ifdef PNG_iTXt_SUPPORTED
1044
65
      {
1045
         /* Set iTXt data */
1046
1047
65
         if (text_ptr[i].lang != NULL)
1048
0
            lang_len = strlen(text_ptr[i].lang);
1049
1050
65
         else
1051
65
            lang_len = 0;
1052
1053
65
         if (text_ptr[i].lang_key != NULL)
1054
0
            lang_key_len = strlen(text_ptr[i].lang_key);
1055
1056
65
         else
1057
65
            lang_key_len = 0;
1058
65
      }
1059
#  else /* iTXt */
1060
      {
1061
         png_chunk_report(png_ptr, "iTXt chunk not supported",
1062
             PNG_CHUNK_WRITE_ERROR);
1063
         continue;
1064
      }
1065
#  endif
1066
1067
51.9k
      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
1068
30.4k
      {
1069
30.4k
         text_length = 0;
1070
30.4k
#  ifdef PNG_iTXt_SUPPORTED
1071
30.4k
         if (text_ptr[i].compression > 0)
1072
0
            textp->compression = PNG_ITXT_COMPRESSION_NONE;
1073
1074
30.4k
         else
1075
30.4k
#  endif
1076
30.4k
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
1077
30.4k
      }
1078
1079
21.5k
      else
1080
21.5k
      {
1081
21.5k
         text_length = strlen(text_ptr[i].text);
1082
21.5k
         textp->compression = text_ptr[i].compression;
1083
21.5k
      }
1084
1085
51.9k
      textp->key = png_voidcast(char *,png_malloc_base(png_ptr,
1086
51.9k
          key_len + text_length + lang_len + lang_key_len + 4));
1087
1088
51.9k
      if (textp->key == NULL)
1089
0
      {
1090
0
         png_chunk_report(png_ptr, "text chunk: out of memory",
1091
0
             PNG_CHUNK_WRITE_ERROR);
1092
0
         png_free(png_ptr, old_text);
1093
1094
0
         return 1;
1095
0
      }
1096
1097
51.9k
      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
1098
51.9k
          (unsigned long)(png_uint_32)
1099
51.9k
          (key_len + lang_len + lang_key_len + text_length + 4),
1100
51.9k
          textp->key);
1101
1102
51.9k
      memcpy(textp->key, text_ptr[i].key, key_len);
1103
51.9k
      *(textp->key + key_len) = '\0';
1104
1105
51.9k
      if (text_ptr[i].compression > 0)
1106
65
      {
1107
65
         textp->lang = textp->key + key_len + 1;
1108
65
         memcpy(textp->lang, text_ptr[i].lang, lang_len);
1109
65
         *(textp->lang + lang_len) = '\0';
1110
65
         textp->lang_key = textp->lang + lang_len + 1;
1111
65
         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
1112
65
         *(textp->lang_key + lang_key_len) = '\0';
1113
65
         textp->text = textp->lang_key + lang_key_len + 1;
1114
65
      }
1115
1116
51.9k
      else
1117
51.9k
      {
1118
51.9k
         textp->lang=NULL;
1119
51.9k
         textp->lang_key=NULL;
1120
51.9k
         textp->text = textp->key + key_len + 1;
1121
51.9k
      }
1122
1123
51.9k
      if (text_length != 0)
1124
21.5k
         memcpy(textp->text, text_ptr[i].text, text_length);
1125
1126
51.9k
      *(textp->text + text_length) = '\0';
1127
1128
51.9k
#  ifdef PNG_iTXt_SUPPORTED
1129
51.9k
      if (textp->compression > 0)
1130
65
      {
1131
65
         textp->text_length = 0;
1132
65
         textp->itxt_length = text_length;
1133
65
      }
1134
1135
51.9k
      else
1136
51.9k
#  endif
1137
51.9k
      {
1138
51.9k
         textp->text_length = text_length;
1139
51.9k
         textp->itxt_length = 0;
1140
51.9k
      }
1141
1142
51.9k
      info_ptr->num_text++;
1143
51.9k
      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
1144
51.9k
   }
1145
1146
51.9k
   png_free(png_ptr, old_text);
1147
1148
51.9k
   return 0;
1149
51.9k
}
1150
#endif
1151
1152
#ifdef PNG_tIME_SUPPORTED
1153
void
1154
png_set_tIME(const png_struct *png_ptr, png_info *info_ptr,
1155
    const png_time *mod_time)
1156
1.53k
{
1157
1.53k
   png_debug1(1, "in %s storage function", "tIME");
1158
1159
1.53k
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
1160
1.53k
       (png_ptr->mode & PNG_WROTE_tIME) != 0)
1161
0
      return;
1162
1163
1.53k
   if (mod_time->month == 0   || mod_time->month > 12  ||
1164
1.51k
       mod_time->day   == 0   || mod_time->day   > 31  ||
1165
1.48k
       mod_time->hour  > 23   || mod_time->minute > 59 ||
1166
1.46k
       mod_time->second > 60)
1167
82
   {
1168
82
      png_warning(png_ptr, "Ignoring invalid time value");
1169
1170
82
      return;
1171
82
   }
1172
1173
1.45k
   info_ptr->mod_time = *mod_time;
1174
1.45k
   info_ptr->valid |= PNG_INFO_tIME;
1175
1.45k
}
1176
#endif
1177
1178
#ifdef PNG_tRNS_SUPPORTED
1179
void
1180
png_set_tRNS(png_struct *png_ptr, png_info *info_ptr,
1181
    const png_byte *trans_alpha, int num_trans, const png_color_16 *trans_color)
1182
1.62k
{
1183
1.62k
   png_debug1(1, "in %s storage function", "tRNS");
1184
1185
1.62k
   if (png_ptr == NULL || info_ptr == NULL)
1186
1187
0
      return;
1188
1189
1.62k
   if (trans_alpha != NULL)
1190
1.52k
   {
1191
       /* Snapshot the caller's trans_alpha before freeing, in case it
1192
        * points to info_ptr->trans_alpha (getter-to-setter aliasing).
1193
        */
1194
1.52k
       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
1195
1196
1.52k
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1197
1.51k
          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
1198
1199
1.52k
       trans_alpha = safe_trans;
1200
1201
1.52k
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
1202
1203
1.52k
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1204
1.51k
       {
1205
          /* Allocate info_ptr's copy of the transparency data.
1206
           * Initialize all entries to fully opaque (0xff), then overwrite
1207
           * the first num_trans entries with the actual values.
1208
           */
1209
1.51k
          info_ptr->trans_alpha = png_voidcast(png_byte *,
1210
1.51k
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1211
1.51k
          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1212
1.51k
          memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1213
1.51k
          info_ptr->free_me |= PNG_FREE_TRNS;
1214
1.51k
          info_ptr->valid |= PNG_INFO_tRNS;
1215
1216
          /* Allocate an independent copy for png_struct, so that the
1217
           * lifetime of png_ptr->trans_alpha is decoupled from the
1218
           * lifetime of info_ptr->trans_alpha.  Previously these two
1219
           * pointers were aliased, which caused a use-after-free if
1220
           * png_free_data freed info_ptr->trans_alpha while
1221
           * png_ptr->trans_alpha was still in use by the row transform
1222
           * functions (e.g. png_do_expand_palette).
1223
           */
1224
1.51k
          png_free(png_ptr, png_ptr->trans_alpha);
1225
1.51k
          png_ptr->trans_alpha = NULL;
1226
1.51k
          png_ptr->trans_alpha = png_voidcast(png_bytep,
1227
1.51k
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1228
1.51k
          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1229
1.51k
          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1230
1.51k
       }
1231
11
       else
1232
11
       {
1233
11
          png_free(png_ptr, png_ptr->trans_alpha);
1234
11
          png_ptr->trans_alpha = NULL;
1235
11
       }
1236
1.52k
   }
1237
1238
1.62k
   if (trans_color != NULL)
1239
1.55k
   {
1240
1.55k
#ifdef PNG_WARNINGS_SUPPORTED
1241
1.55k
      if (info_ptr->bit_depth < 16)
1242
1.12k
      {
1243
1.12k
         int sample_max = (1 << info_ptr->bit_depth) - 1;
1244
1245
1.12k
         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1246
343
             trans_color->gray > sample_max) ||
1247
1.02k
             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1248
504
             (trans_color->red > sample_max ||
1249
455
             trans_color->green > sample_max ||
1250
419
             trans_color->blue > sample_max)))
1251
233
            png_warning(png_ptr,
1252
233
                "tRNS chunk has out-of-range samples for bit_depth");
1253
1.12k
      }
1254
1.55k
#endif
1255
1256
1.55k
      info_ptr->trans_color = *trans_color;
1257
1258
1.55k
      if (num_trans == 0)
1259
94
         num_trans = 1;
1260
1.55k
   }
1261
1262
1.62k
   info_ptr->num_trans = (png_uint_16)num_trans;
1263
1264
1.62k
   if (num_trans != 0)
1265
1.61k
   {
1266
1.61k
      info_ptr->free_me |= PNG_FREE_TRNS;
1267
1.61k
      info_ptr->valid |= PNG_INFO_tRNS;
1268
1.61k
   }
1269
1.62k
}
1270
#endif
1271
1272
#ifdef PNG_sPLT_SUPPORTED
1273
void
1274
png_set_sPLT(const png_struct *png_ptr,
1275
    png_info *info_ptr, const png_sPLT_t *entries, int nentries)
1276
/*
1277
 *  entries        - array of png_sPLT_t structures
1278
 *                   to be added to the list of palettes
1279
 *                   in the info structure.
1280
 *
1281
 *  nentries       - number of palette structures to be
1282
 *                   added.
1283
 */
1284
0
{
1285
0
   png_sPLT_t *np;
1286
0
   png_sPLT_t *old_spalettes;
1287
1288
0
   png_debug1(1, "in %s storage function", "sPLT");
1289
1290
0
   if (png_ptr == NULL || info_ptr == NULL || nentries <= 0 || entries == NULL)
1291
0
      return;
1292
1293
   /* Use the internal realloc function, which checks for all the possible
1294
    * overflows.  Notice that the parameters are (int) and (size_t)
1295
    */
1296
0
   np = png_voidcast(png_sPLT_t *,png_realloc_array(png_ptr,
1297
0
       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
1298
0
       sizeof *np));
1299
1300
0
   if (np == NULL)
1301
0
   {
1302
      /* Out of memory or too many chunks */
1303
0
      png_chunk_report(png_ptr, "too many sPLT chunks", PNG_CHUNK_WRITE_ERROR);
1304
0
      return;
1305
0
   }
1306
1307
   /* Defer freeing the old array until after the copy loop below,
1308
    * in case entries aliases info_ptr->splt_palettes (getter-to-setter).
1309
    */
1310
0
   old_spalettes = info_ptr->splt_palettes;
1311
1312
0
   info_ptr->splt_palettes = np;
1313
0
   info_ptr->free_me |= PNG_FREE_SPLT;
1314
1315
0
   np += info_ptr->splt_palettes_num;
1316
1317
0
   do
1318
0
   {
1319
0
      size_t length;
1320
1321
      /* Skip invalid input entries */
1322
0
      if (entries->name == NULL || entries->entries == NULL)
1323
0
      {
1324
         /* png_handle_sPLT doesn't do this, so this is an app error */
1325
0
         png_app_error(png_ptr, "png_set_sPLT: invalid sPLT");
1326
         /* Just skip the invalid entry */
1327
0
         continue;
1328
0
      }
1329
1330
0
      np->depth = entries->depth;
1331
1332
      /* In the event of out-of-memory just return - there's no point keeping
1333
       * on trying to add sPLT chunks.
1334
       */
1335
0
      length = strlen(entries->name) + 1;
1336
0
      np->name = png_voidcast(char *, png_malloc_base(png_ptr, length));
1337
1338
0
      if (np->name == NULL)
1339
0
         break;
1340
1341
0
      memcpy(np->name, entries->name, length);
1342
1343
      /* IMPORTANT: we have memory now that won't get freed if something else
1344
       * goes wrong; this code must free it.  png_malloc_array produces no
1345
       * warnings; use a png_chunk_report (below) if there is an error.
1346
       */
1347
0
      np->entries = png_voidcast(png_sPLT_entry *, png_malloc_array(png_ptr,
1348
0
          entries->nentries, sizeof (png_sPLT_entry)));
1349
1350
0
      if (np->entries == NULL)
1351
0
      {
1352
0
         png_free(png_ptr, np->name);
1353
0
         np->name = NULL;
1354
0
         break;
1355
0
      }
1356
1357
0
      np->nentries = entries->nentries;
1358
      /* This multiply can't overflow because png_malloc_array has already
1359
       * checked it when doing the allocation.
1360
       */
1361
0
      memcpy(np->entries, entries->entries,
1362
0
          (unsigned int)entries->nentries * sizeof (png_sPLT_entry));
1363
1364
      /* Note that 'continue' skips the advance of the out pointer and out
1365
       * count, so an invalid entry is not added.
1366
       */
1367
0
      info_ptr->valid |= PNG_INFO_sPLT;
1368
0
      ++(info_ptr->splt_palettes_num);
1369
0
      ++np;
1370
0
      ++entries;
1371
0
   }
1372
0
   while (--nentries);
1373
1374
0
   png_free(png_ptr, old_spalettes);
1375
1376
0
   if (nentries > 0)
1377
0
      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
1378
0
}
1379
#endif /* sPLT */
1380
1381
#ifdef PNG_APNG_SUPPORTED
1382
png_uint_32 PNGAPI
1383
png_set_acTL(png_struct *png_ptr, png_info *info_ptr,
1384
             png_uint_32 num_frames, png_uint_32 num_plays)
1385
0
{
1386
0
   png_debug1(1, "in %s storage function", "acTL");
1387
1388
0
   if (png_ptr == NULL || info_ptr == NULL)
1389
0
   {
1390
0
      png_warning(png_ptr,
1391
0
                  "Ignoring call to png_set_acTL with NULL libpng object args");
1392
0
      return 0;
1393
0
   }
1394
0
   if (num_frames == 0)
1395
0
   {
1396
0
      png_warning(png_ptr,
1397
0
                  "Ignoring attempt to set acTL with num_frames zero");
1398
0
      return 0;
1399
0
   }
1400
0
   if (num_frames > PNG_UINT_31_MAX)
1401
0
   {
1402
0
      png_warning(png_ptr,
1403
0
                  "Ignoring attempt to set acTL with num_frames > 2^31-1");
1404
0
      return 0;
1405
0
   }
1406
0
   if (num_plays > PNG_UINT_31_MAX)
1407
0
   {
1408
0
      png_warning(png_ptr,
1409
0
                  "Ignoring attempt to set acTL with num_plays > 2^31-1");
1410
0
      return 0;
1411
0
   }
1412
1413
0
   info_ptr->num_frames = num_frames;
1414
0
   info_ptr->num_plays = num_plays;
1415
1416
0
   info_ptr->valid |= PNG_INFO_acTL;
1417
1418
0
   return 1;
1419
0
}
1420
1421
png_uint_32 PNGAPI
1422
png_set_next_frame_fcTL(png_struct *png_ptr, png_info *info_ptr,
1423
                        png_uint_32 width, png_uint_32 height,
1424
                        png_uint_32 x_offset, png_uint_32 y_offset,
1425
                        png_uint_16 delay_num, png_uint_16 delay_den,
1426
                        png_byte dispose_op, png_byte blend_op)
1427
0
{
1428
0
   png_debug1(1, "in %s storage function", "fcTL");
1429
1430
0
   if (png_ptr == NULL || info_ptr == NULL)
1431
0
   {
1432
0
      png_warning(png_ptr,
1433
0
                  "Ignoring call to png_set_fcTL with NULL libpng object args");
1434
0
      return 0;
1435
0
   }
1436
1437
0
   png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1438
0
                            delay_num, delay_den, dispose_op, blend_op);
1439
1440
   /* No checking is required for delay_num and delay_den.
1441
    * They can hold any 16-bit value, including zero.
1442
    */
1443
1444
0
   if (blend_op == PNG_fcTL_BLEND_OP_OVER)
1445
0
   {
1446
0
      if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
1447
0
          !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
1448
0
      {
1449
0
         png_warning(png_ptr,
1450
0
                     "Ignoring wasteful fcTL BLEND_OP_OVER in opaque images");
1451
0
         blend_op = PNG_fcTL_BLEND_OP_SOURCE;
1452
0
      }
1453
0
   }
1454
1455
0
   info_ptr->next_frame_width = width;
1456
0
   info_ptr->next_frame_height = height;
1457
0
   info_ptr->next_frame_x_offset = x_offset;
1458
0
   info_ptr->next_frame_y_offset = y_offset;
1459
0
   info_ptr->next_frame_delay_num = delay_num;
1460
0
   info_ptr->next_frame_delay_den = delay_den;
1461
0
   info_ptr->next_frame_dispose_op = dispose_op;
1462
0
   info_ptr->next_frame_blend_op = blend_op;
1463
1464
0
   info_ptr->valid |= PNG_INFO_fcTL;
1465
1466
0
   return 1;
1467
0
}
1468
1469
void /* PRIVATE */
1470
png_ensure_fcTL_is_valid(png_struct *png_ptr,
1471
                         png_uint_32 width, png_uint_32 height,
1472
                         png_uint_32 x_offset, png_uint_32 y_offset,
1473
                         png_uint_16 delay_num, png_uint_16 delay_den,
1474
                         png_byte dispose_op, png_byte blend_op)
1475
0
{
1476
0
   if (width == 0 || width > PNG_UINT_31_MAX)
1477
0
      png_error(png_ptr, "Invalid frame width in fcTL");
1478
0
   if (height == 0 || height > PNG_UINT_31_MAX)
1479
0
      png_error(png_ptr, "Invalid frame height in fcTL");
1480
0
   if (x_offset > PNG_UINT_31_MAX || y_offset > PNG_UINT_31_MAX)
1481
0
      png_error(png_ptr, "Invalid frame offset in fcTL");
1482
0
   if (width + x_offset > png_ptr->first_frame_width ||
1483
0
       height + y_offset > png_ptr->first_frame_height)
1484
0
      png_error(png_ptr, "Oversized frame in fcTL");
1485
1486
0
   if (dispose_op != PNG_fcTL_DISPOSE_OP_NONE &&
1487
0
       dispose_op != PNG_fcTL_DISPOSE_OP_BACKGROUND &&
1488
0
       dispose_op != PNG_fcTL_DISPOSE_OP_PREVIOUS)
1489
0
      png_error(png_ptr, "Invalid dispose_op in fcTL");
1490
1491
0
   if (blend_op != PNG_fcTL_BLEND_OP_SOURCE &&
1492
0
       blend_op != PNG_fcTL_BLEND_OP_OVER)
1493
0
      png_error(png_ptr, "Invalid blend_op in fcTL");
1494
1495
0
   PNG_UNUSED(delay_num)
1496
0
   PNG_UNUSED(delay_den)
1497
0
}
1498
1499
png_uint_32 PNGAPI
1500
png_set_first_frame_is_hidden(png_struct *png_ptr, png_info *info_ptr,
1501
                              png_byte is_hidden)
1502
0
{
1503
0
   png_debug(1, "in png_first_frame_is_hidden");
1504
1505
0
   if (png_ptr == NULL)
1506
0
      return 0;
1507
1508
0
   if (is_hidden)
1509
0
      png_ptr->apng_flags |= PNG_FIRST_FRAME_HIDDEN;
1510
0
   else
1511
0
      png_ptr->apng_flags &= ~PNG_FIRST_FRAME_HIDDEN;
1512
1513
0
   PNG_UNUSED(info_ptr)
1514
1515
0
   return 1;
1516
0
}
1517
#endif /* PNG_APNG_SUPPORTED */
1518
1519
#ifdef PNG_STORE_UNKNOWN_CHUNKS_SUPPORTED
1520
static png_byte
1521
check_location(const png_struct *png_ptr, int location)
1522
79.8k
{
1523
79.8k
   location &= (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT);
1524
1525
   /* New in 1.6.0; copy the location and check it.  This is an API
1526
    * change; previously the app had to use the
1527
    * png_set_unknown_chunk_location API below for each chunk.
1528
    */
1529
79.8k
   if (location == 0 && (png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1530
0
   {
1531
      /* Write struct, so unknown chunks come from the app */
1532
0
      png_app_warning(png_ptr,
1533
0
          "png_set_unknown_chunks now expects a valid location");
1534
      /* Use the old behavior */
1535
0
      location = (png_byte)(png_ptr->mode &
1536
0
          (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT));
1537
0
   }
1538
1539
   /* This need not be an internal error - if the app calls
1540
    * png_set_unknown_chunks on a read pointer it must get the location right.
1541
    */
1542
79.8k
   if (location == 0)
1543
2.36k
      png_error(png_ptr, "invalid location in png_set_unknown_chunks");
1544
1545
   /* Now reduce the location to the top-most set bit by removing each least
1546
    * significant bit in turn.
1547
    */
1548
87.2k
   while (location != (location & -location))
1549
9.82k
      location &= ~(location & -location);
1550
1551
   /* The cast is safe because 'location' is a bit mask and only the low four
1552
    * bits are significant.
1553
    */
1554
77.4k
   return (png_byte)location;
1555
79.8k
}
1556
1557
void
1558
png_set_unknown_chunks(const png_struct *png_ptr,
1559
    png_info *info_ptr, const png_unknown_chunk *unknowns, int num_unknowns)
1560
79.8k
{
1561
79.8k
   png_unknown_chunk *np;
1562
79.8k
   png_unknown_chunk *old_unknowns;
1563
1564
79.8k
   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
1565
79.8k
       unknowns == NULL)
1566
0
      return;
1567
1568
   /* Check for the failure cases where support has been disabled at compile
1569
    * time.  This code is hardly ever compiled - it's here because
1570
    * STORE_UNKNOWN_CHUNKS is set by both read and write code (compiling in this
1571
    * code) but may be meaningless if the read or write handling of unknown
1572
    * chunks is not compiled in.
1573
    */
1574
#  if !defined(PNG_READ_UNKNOWN_CHUNKS_SUPPORTED) && \
1575
      defined(PNG_READ_SUPPORTED)
1576
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1577
      {
1578
         png_app_error(png_ptr, "no unknown chunk support on read");
1579
1580
         return;
1581
      }
1582
#  endif
1583
#  if !defined(PNG_WRITE_UNKNOWN_CHUNKS_SUPPORTED) && \
1584
      defined(PNG_WRITE_SUPPORTED)
1585
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1586
      {
1587
         png_app_error(png_ptr, "no unknown chunk support on write");
1588
1589
         return;
1590
      }
1591
#  endif
1592
1593
   /* Prior to 1.6.0 this code used png_malloc_warn; however, this meant that
1594
    * unknown critical chunks could be lost with just a warning resulting in
1595
    * undefined behavior.  Now png_chunk_report is used to provide behavior
1596
    * appropriate to read or write.
1597
    */
1598
79.8k
   np = png_voidcast(png_unknown_chunk *, png_realloc_array(png_ptr,
1599
79.8k
       info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
1600
79.8k
       sizeof *np));
1601
1602
79.8k
   if (np == NULL)
1603
0
   {
1604
0
      png_chunk_report(png_ptr, "too many unknown chunks",
1605
0
          PNG_CHUNK_WRITE_ERROR);
1606
0
      return;
1607
0
   }
1608
1609
   /* Defer freeing the old array until after the copy loop below,
1610
    * in case unknowns aliases info_ptr->unknown_chunks (getter-to-setter).
1611
    */
1612
79.8k
   old_unknowns = info_ptr->unknown_chunks;
1613
1614
79.8k
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
1615
79.8k
   info_ptr->free_me |= PNG_FREE_UNKN;
1616
1617
79.8k
   np += info_ptr->unknown_chunks_num;
1618
1619
   /* Increment unknown_chunks_num each time round the loop to protect the
1620
    * just-allocated chunk data.
1621
    */
1622
159k
   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
1623
79.8k
   {
1624
79.8k
      memcpy(np->name, unknowns->name, (sizeof np->name));
1625
79.8k
      np->name[(sizeof np->name)-1] = '\0';
1626
79.8k
      np->location = check_location(png_ptr, unknowns->location);
1627
1628
79.8k
      if (unknowns->size == 0)
1629
41.6k
      {
1630
41.6k
         np->data = NULL;
1631
41.6k
         np->size = 0;
1632
41.6k
      }
1633
1634
38.2k
      else
1635
38.2k
      {
1636
38.2k
         np->data = png_voidcast(png_byte *,
1637
38.2k
             png_malloc_base(png_ptr, unknowns->size));
1638
1639
38.2k
         if (np->data == NULL)
1640
0
         {
1641
0
            png_chunk_report(png_ptr, "unknown chunk: out of memory",
1642
0
                PNG_CHUNK_WRITE_ERROR);
1643
            /* But just skip storing the unknown chunk */
1644
0
            continue;
1645
0
         }
1646
1647
38.2k
         memcpy(np->data, unknowns->data, unknowns->size);
1648
38.2k
         np->size = unknowns->size;
1649
38.2k
      }
1650
1651
      /* These increments are skipped on out-of-memory for the data - the
1652
       * unknown chunk entry gets overwritten if the png_chunk_report returns.
1653
       * This is correct in the read case (the chunk is just dropped.)
1654
       */
1655
79.8k
      ++np;
1656
79.8k
      ++(info_ptr->unknown_chunks_num);
1657
79.8k
   }
1658
1659
79.8k
   png_free(png_ptr, old_unknowns);
1660
79.8k
}
1661
1662
void
1663
png_set_unknown_chunk_location(const png_struct *png_ptr, png_info *info_ptr,
1664
    int chunk, int location)
1665
0
{
1666
   /* This API is pretty pointless in 1.6.0 because the location can be set
1667
    * before the call to png_set_unknown_chunks.
1668
    *
1669
    * TODO: add a png_app_warning in 1.7
1670
    */
1671
0
   if (png_ptr != NULL && info_ptr != NULL && chunk >= 0 &&
1672
0
      chunk < info_ptr->unknown_chunks_num)
1673
0
   {
1674
0
      if ((location & (PNG_HAVE_IHDR|PNG_HAVE_PLTE|PNG_AFTER_IDAT)) == 0)
1675
0
      {
1676
0
         png_app_error(png_ptr, "invalid unknown chunk location");
1677
         /* Fake out the pre 1.6.0 behavior: */
1678
0
         if (((unsigned int)location & PNG_HAVE_IDAT) != 0) /* undocumented! */
1679
0
            location = PNG_AFTER_IDAT;
1680
1681
0
         else
1682
0
            location = PNG_HAVE_IHDR; /* also undocumented */
1683
0
      }
1684
1685
0
      info_ptr->unknown_chunks[chunk].location =
1686
0
         check_location(png_ptr, location);
1687
0
   }
1688
0
}
1689
#endif /* STORE_UNKNOWN_CHUNKS */
1690
1691
#ifdef PNG_MNG_FEATURES_SUPPORTED
1692
png_uint_32
1693
png_permit_mng_features(png_struct *png_ptr, png_uint_32 mng_features)
1694
6.10k
{
1695
6.10k
   png_debug(1, "in png_permit_mng_features");
1696
1697
6.10k
   if (png_ptr == NULL)
1698
0
      return 0;
1699
1700
6.10k
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1701
1702
6.10k
   return png_ptr->mng_features_permitted;
1703
6.10k
}
1704
#endif
1705
1706
#ifdef PNG_HANDLE_AS_UNKNOWN_SUPPORTED
1707
static unsigned int
1708
add_one_chunk(png_byte *list, unsigned int count, const png_byte *add, int keep)
1709
845k
{
1710
845k
   unsigned int i;
1711
1712
   /* Utility function: update the 'keep' state of a chunk if it is already in
1713
    * the list, otherwise add it to the list.
1714
    */
1715
4.65M
   for (i=0; i<count; ++i, list += 5)
1716
3.80M
   {
1717
3.80M
      if (memcmp(list, add, 4) == 0)
1718
0
      {
1719
0
         list[4] = (png_byte)keep;
1720
1721
0
         return count;
1722
0
      }
1723
3.80M
   }
1724
1725
845k
   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
1726
845k
   {
1727
845k
      ++count;
1728
845k
      memcpy(list, add, 4);
1729
845k
      list[4] = (png_byte)keep;
1730
845k
   }
1731
1732
845k
   return count;
1733
845k
}
1734
1735
void
1736
png_set_keep_unknown_chunks(png_struct *png_ptr, int keep,
1737
    const png_byte *chunk_list, int num_chunks_in)
1738
338k
{
1739
338k
   png_byte *new_list;
1740
338k
   unsigned int num_chunks, old_num_chunks;
1741
1742
338k
   if (png_ptr == NULL)
1743
0
      return;
1744
1745
338k
   if (keep < 0 || keep >= PNG_HANDLE_CHUNK_LAST)
1746
0
   {
1747
0
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: invalid keep");
1748
1749
0
      return;
1750
0
   }
1751
1752
338k
   if (num_chunks_in <= 0)
1753
84.5k
   {
1754
84.5k
      png_ptr->unknown_default = keep;
1755
1756
      /* '0' means just set the flags, so stop here */
1757
84.5k
      if (num_chunks_in == 0)
1758
84.5k
        return;
1759
84.5k
   }
1760
1761
253k
   if (num_chunks_in < 0)
1762
0
   {
1763
      /* Ignore all unknown chunks and all chunks recognized by
1764
       * libpng except for IHDR, PLTE, tRNS, IDAT, and IEND
1765
       */
1766
0
      static const png_byte chunks_to_ignore[] = {
1767
0
         97,  99,  84,  76, '\0',  /* acTL */
1768
0
         98,  75,  71,  68, '\0',  /* bKGD */
1769
0
         99,  72,  82,  77, '\0',  /* cHRM */
1770
0
         99,  73,  67,  80, '\0',  /* cICP */
1771
0
         99,  76,  76,  73, '\0',  /* cLLI */
1772
0
        101,  88,  73, 102, '\0',  /* eXIf */
1773
0
        102,  99,  84,  76, '\0',  /* fcTL */
1774
0
        102, 100,  65,  84, '\0',  /* fdAT */
1775
0
        103,  65,  77,  65, '\0',  /* gAMA */
1776
0
        104,  73,  83,  84, '\0',  /* hIST */
1777
0
        105,  67,  67,  80, '\0',  /* iCCP */
1778
0
        105,  84,  88, 116, '\0',  /* iTXt */
1779
0
        109,  68,  67,  86, '\0',  /* mDCV */
1780
0
        111,  70,  70, 115, '\0',  /* oFFs */
1781
0
        112,  67,  65,  76, '\0',  /* pCAL */
1782
0
        112,  72,  89, 115, '\0',  /* pHYs */
1783
0
        115,  66,  73,  84, '\0',  /* sBIT */
1784
0
        115,  67,  65,  76, '\0',  /* sCAL */
1785
0
        115,  80,  76,  84, '\0',  /* sPLT */
1786
0
        115,  84,  69,  82, '\0',  /* sTER */
1787
0
        115,  82,  71,  66, '\0',  /* sRGB */
1788
0
        116,  69,  88, 116, '\0',  /* tEXt */
1789
0
        116,  73,  77,  69, '\0',  /* tIME */
1790
0
        122,  84,  88, 116, '\0'   /* zTXt */
1791
0
      };
1792
1793
0
      chunk_list = chunks_to_ignore;
1794
0
      num_chunks = (unsigned int)/*SAFE*/(sizeof chunks_to_ignore)/5U;
1795
0
   }
1796
1797
253k
   else /* num_chunks_in > 0 */
1798
253k
   {
1799
253k
      if (chunk_list == NULL)
1800
0
      {
1801
         /* Prior to 1.6.0 this was silently ignored, now it is an app_error
1802
          * which can be switched off.
1803
          */
1804
0
         png_app_error(png_ptr, "png_set_keep_unknown_chunks: no chunk list");
1805
1806
0
         return;
1807
0
      }
1808
1809
253k
      num_chunks = (unsigned int)num_chunks_in;
1810
253k
   }
1811
1812
253k
   old_num_chunks = png_ptr->num_chunk_list;
1813
253k
   if (png_ptr->chunk_list == NULL)
1814
84.5k
      old_num_chunks = 0;
1815
1816
   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
1817
    */
1818
253k
   if (num_chunks + old_num_chunks > UINT_MAX/5)
1819
0
   {
1820
0
      png_app_error(png_ptr, "png_set_keep_unknown_chunks: too many chunks");
1821
1822
0
      return;
1823
0
   }
1824
1825
   /* If these chunks are being reset to the default then no more memory is
1826
    * required because add_one_chunk above doesn't extend the list if the 'keep'
1827
    * parameter is the default.
1828
    */
1829
253k
   if (keep != 0)
1830
253k
   {
1831
253k
      new_list = png_voidcast(png_byte *, png_malloc(png_ptr,
1832
253k
          5 * (num_chunks + old_num_chunks)));
1833
1834
253k
      if (old_num_chunks > 0)
1835
169k
         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1836
253k
   }
1837
1838
0
   else if (old_num_chunks > 0)
1839
0
      new_list = png_ptr->chunk_list;
1840
1841
0
   else
1842
0
      new_list = NULL;
1843
1844
   /* Add the new chunks together with each one's handling code.  If the chunk
1845
    * already exists the code is updated, otherwise the chunk is added to the
1846
    * end.  (In libpng 1.6.0 order no longer matters because this code enforces
1847
    * the earlier convention that the last setting is the one that is used.)
1848
    */
1849
253k
   if (new_list != NULL)
1850
253k
   {
1851
253k
      const png_byte *inlist;
1852
253k
      png_byte *outlist;
1853
253k
      unsigned int i;
1854
1855
1.09M
      for (i=0; i<num_chunks; ++i)
1856
845k
      {
1857
845k
         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
1858
845k
             chunk_list+5*i, keep);
1859
845k
      }
1860
1861
      /* Now remove any spurious 'default' entries. */
1862
253k
      num_chunks = 0;
1863
1.35M
      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1864
1.09M
      {
1865
1.09M
         if (inlist[4])
1866
1.09M
         {
1867
1.09M
            if (outlist != inlist)
1868
0
               memcpy(outlist, inlist, 5);
1869
1.09M
            outlist += 5;
1870
1.09M
            ++num_chunks;
1871
1.09M
         }
1872
1.09M
      }
1873
1874
      /* This means the application has removed all the specialized handling. */
1875
253k
      if (num_chunks == 0)
1876
0
      {
1877
0
         if (png_ptr->chunk_list != new_list)
1878
0
            png_free(png_ptr, new_list);
1879
1880
0
         new_list = NULL;
1881
0
      }
1882
253k
   }
1883
1884
0
   else
1885
0
      num_chunks = 0;
1886
1887
253k
   png_ptr->num_chunk_list = num_chunks;
1888
1889
253k
   if (png_ptr->chunk_list != new_list)
1890
253k
   {
1891
253k
      if (png_ptr->chunk_list != NULL)
1892
169k
         png_free(png_ptr, png_ptr->chunk_list);
1893
1894
253k
      png_ptr->chunk_list = new_list;
1895
253k
   }
1896
253k
}
1897
#endif
1898
1899
#ifdef PNG_READ_USER_CHUNKS_SUPPORTED
1900
void
1901
png_set_read_user_chunk_fn(png_struct *png_ptr, void *user_chunk_ptr,
1902
    png_user_chunk_ptr read_user_chunk_fn)
1903
84.5k
{
1904
84.5k
   png_debug(1, "in png_set_read_user_chunk_fn");
1905
1906
84.5k
   if (png_ptr == NULL)
1907
0
      return;
1908
1909
84.5k
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
1910
84.5k
   png_ptr->user_chunk_ptr = user_chunk_ptr;
1911
84.5k
}
1912
#endif
1913
1914
#ifdef PNG_INFO_IMAGE_SUPPORTED
1915
void
1916
png_set_rows(const png_struct *png_ptr, png_info *info_ptr,
1917
    png_byte **row_pointers)
1918
0
{
1919
0
   png_debug(1, "in png_set_rows");
1920
1921
0
   if (png_ptr == NULL || info_ptr == NULL)
1922
0
      return;
1923
1924
0
   if (info_ptr->row_pointers != NULL &&
1925
0
       (info_ptr->row_pointers != row_pointers))
1926
0
      png_free_data(png_ptr, info_ptr, PNG_FREE_ROWS, 0);
1927
1928
0
   info_ptr->row_pointers = row_pointers;
1929
1930
0
   if (row_pointers != NULL)
1931
0
      info_ptr->valid |= PNG_INFO_IDAT;
1932
0
}
1933
#endif
1934
1935
void
1936
png_set_compression_buffer_size(png_struct *png_ptr, size_t size)
1937
1.91k
{
1938
1.91k
   png_debug(1, "in png_set_compression_buffer_size");
1939
1940
1.91k
   if (png_ptr == NULL)
1941
0
      return;
1942
1943
1.91k
   if (size == 0 || size > PNG_UINT_31_MAX)
1944
0
      png_error(png_ptr, "invalid compression buffer size");
1945
1946
1.91k
#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1947
1.91k
   if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
1948
0
   {
1949
0
      png_ptr->IDAT_read_size = (png_uint_32)size; /* checked above */
1950
0
      return;
1951
0
   }
1952
1.91k
#  endif
1953
1954
1.91k
#  ifdef PNG_WRITE_SUPPORTED
1955
1.91k
   if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1956
1.91k
   {
1957
1.91k
      if (png_ptr->zowner != 0)
1958
0
      {
1959
0
         png_warning(png_ptr,
1960
0
             "Compression buffer size cannot be changed because it is in use");
1961
1962
0
         return;
1963
0
      }
1964
1965
1.91k
#ifndef __COVERITY__
1966
      /* Some compilers complain that this is always false.  However, it
1967
       * can be true when integer overflow happens.
1968
       */
1969
1.91k
      if (size > ZLIB_IO_MAX)
1970
0
      {
1971
0
         png_warning(png_ptr,
1972
0
             "Compression buffer size limited to system maximum");
1973
0
         size = ZLIB_IO_MAX; /* must fit */
1974
0
      }
1975
1.91k
#endif
1976
1977
1.91k
      if (size < 6)
1978
0
      {
1979
         /* Deflate will potentially go into an infinite loop on a SYNC_FLUSH
1980
          * if this is permitted.
1981
          */
1982
0
         png_warning(png_ptr,
1983
0
             "Compression buffer size cannot be reduced below 6");
1984
1985
0
         return;
1986
0
      }
1987
1988
1.91k
      if (png_ptr->zbuffer_size != size)
1989
1.91k
      {
1990
1.91k
         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
1991
1.91k
         png_ptr->zbuffer_size = (uInt)size;
1992
1.91k
      }
1993
1.91k
   }
1994
1.91k
#  endif
1995
1.91k
}
1996
1997
void
1998
png_set_invalid(const png_struct *png_ptr, png_info *info_ptr, int mask)
1999
202
{
2000
202
   if (png_ptr != NULL && info_ptr != NULL)
2001
202
      info_ptr->valid &= (unsigned int)(~mask);
2002
202
}
2003
2004
2005
#ifdef PNG_SET_USER_LIMITS_SUPPORTED
2006
/* This function was added to libpng 1.2.6 */
2007
void
2008
png_set_user_limits(png_struct *png_ptr, png_uint_32 user_width_max,
2009
    png_uint_32 user_height_max)
2010
86.4k
{
2011
86.4k
   png_debug(1, "in png_set_user_limits");
2012
2013
   /* Images with dimensions larger than these limits will be
2014
    * rejected by png_set_IHDR().  To accept any PNG datastream
2015
    * regardless of dimensions, set both limits to 0x7fffffff.
2016
    */
2017
86.4k
   if (png_ptr == NULL)
2018
0
      return;
2019
2020
86.4k
   png_ptr->user_width_max = user_width_max;
2021
86.4k
   png_ptr->user_height_max = user_height_max;
2022
86.4k
}
2023
2024
/* This function was added to libpng 1.4.0 */
2025
void
2026
png_set_chunk_cache_max(png_struct *png_ptr, png_uint_32 user_chunk_cache_max)
2027
84.5k
{
2028
84.5k
   png_debug(1, "in png_set_chunk_cache_max");
2029
2030
84.5k
   if (png_ptr != NULL)
2031
84.5k
      png_ptr->user_chunk_cache_max = user_chunk_cache_max;
2032
84.5k
}
2033
2034
/* This function was added to libpng 1.4.1 */
2035
void
2036
png_set_chunk_malloc_max(png_struct *png_ptr,
2037
    png_alloc_size_t user_chunk_malloc_max)
2038
0
{
2039
0
   png_debug(1, "in png_set_chunk_malloc_max");
2040
2041
   /* pngstruct::user_chunk_malloc_max is initialized to a non-zero value in
2042
    * png.c.  This API supports '0' for unlimited, make sure the correct
2043
    * (unlimited) value is set here to avoid a need to check for 0 everywhere
2044
    * the parameter is used.
2045
    */
2046
0
   if (png_ptr != NULL)
2047
0
   {
2048
0
      if (user_chunk_malloc_max == 0U) /* unlimited */
2049
0
      {
2050
#        ifdef PNG_MAX_MALLOC_64K
2051
            png_ptr->user_chunk_malloc_max = 65536U;
2052
#        else
2053
0
            png_ptr->user_chunk_malloc_max = PNG_SIZE_MAX;
2054
0
#        endif
2055
0
      }
2056
0
      else
2057
0
         png_ptr->user_chunk_malloc_max = user_chunk_malloc_max;
2058
0
   }
2059
0
}
2060
#endif /* ?SET_USER_LIMITS */
2061
2062
2063
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
2064
void
2065
png_set_benign_errors(png_struct *png_ptr, int allowed)
2066
86.4k
{
2067
86.4k
   png_debug(1, "in png_set_benign_errors");
2068
2069
   /* If allowed is 1, png_benign_error() is treated as a warning.
2070
    *
2071
    * If allowed is 0, png_benign_error() is treated as an error (which
2072
    * is the default behavior if png_set_benign_errors() is not called).
2073
    */
2074
2075
86.4k
   if (allowed != 0)
2076
86.4k
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
2077
86.4k
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN;
2078
2079
0
   else
2080
0
      png_ptr->flags &= ~(PNG_FLAG_BENIGN_ERRORS_WARN |
2081
0
         PNG_FLAG_APP_WARNINGS_WARN | PNG_FLAG_APP_ERRORS_WARN);
2082
86.4k
}
2083
#endif /* BENIGN_ERRORS */
2084
2085
#ifdef PNG_CHECK_FOR_INVALID_INDEX_SUPPORTED
2086
   /* Whether to report invalid palette index; added at libpng-1.5.10.
2087
    * It is possible for an indexed (color-type==3) PNG file to contain
2088
    * pixels with invalid (out-of-range) indexes if the PLTE chunk has
2089
    * fewer entries than the image's bit-depth would allow. We recover
2090
    * from this gracefully by filling any incomplete palette with zeros
2091
    * (opaque black).  By default, when this occurs libpng will issue
2092
    * a benign error.  This API can be used to override that behavior.
2093
    */
2094
void
2095
png_set_check_for_invalid_index(png_struct *png_ptr, int allowed)
2096
84.5k
{
2097
84.5k
   png_debug(1, "in png_set_check_for_invalid_index");
2098
2099
84.5k
   if (allowed > 0)
2100
0
      png_ptr->num_palette_max = 0;
2101
2102
84.5k
   else
2103
84.5k
      png_ptr->num_palette_max = -1;
2104
84.5k
}
2105
#endif
2106
2107
#if defined(PNG_TEXT_SUPPORTED) || defined(PNG_pCAL_SUPPORTED) || \
2108
    defined(PNG_iCCP_SUPPORTED) || defined(PNG_sPLT_SUPPORTED)
2109
/* Check that the tEXt or zTXt keyword is valid per PNG 1.0 specification,
2110
 * and if invalid, correct the keyword rather than discarding the entire
2111
 * chunk.  The PNG 1.0 specification requires keywords 1-79 characters in
2112
 * length, forbids leading or trailing whitespace, multiple internal spaces,
2113
 * and the non-break space (0x80) from ISO 8859-1.  Returns keyword length.
2114
 *
2115
 * The 'new_key' buffer must be 80 characters in size (for the keyword plus a
2116
 * trailing '\0').  If this routine returns 0 then there was no keyword, or a
2117
 * valid one could not be generated, and the caller must png_error.
2118
 */
2119
png_uint_32 /* PRIVATE */
2120
png_check_keyword(png_struct *png_ptr, const char *key, png_byte *new_key)
2121
6.44k
{
2122
6.44k
#ifdef PNG_WARNINGS_SUPPORTED
2123
6.44k
   const char *orig_key = key;
2124
6.44k
#endif
2125
6.44k
   png_uint_32 key_len = 0;
2126
6.44k
   int bad_character = 0;
2127
6.44k
   int space = 1;
2128
2129
6.44k
   png_debug(1, "in png_check_keyword");
2130
2131
6.44k
   if (key == NULL)
2132
0
   {
2133
0
      *new_key = 0;
2134
0
      return 0;
2135
0
   }
2136
2137
80.4k
   while (*key && key_len < 79)
2138
73.9k
   {
2139
73.9k
      png_byte ch = (png_byte)*key++;
2140
2141
73.9k
      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
2142
73.6k
      {
2143
73.6k
         *new_key++ = ch; ++key_len; space = 0;
2144
73.6k
      }
2145
2146
367
      else if (space == 0)
2147
341
      {
2148
         /* A space or an invalid character when one wasn't seen immediately
2149
          * before; output just a space.
2150
          */
2151
341
         *new_key++ = 32; ++key_len; space = 1;
2152
2153
         /* If the character was not a space then it is invalid. */
2154
341
         if (ch != 32)
2155
290
            bad_character = ch;
2156
341
      }
2157
2158
26
      else if (bad_character == 0)
2159
2
         bad_character = ch; /* just skip it, record the first error */
2160
73.9k
   }
2161
2162
6.44k
   if (key_len > 0 && space != 0) /* trailing space */
2163
282
   {
2164
282
      --key_len; --new_key;
2165
282
      if (bad_character == 0)
2166
0
         bad_character = 32;
2167
282
   }
2168
2169
   /* Terminate the keyword */
2170
6.44k
   *new_key = 0;
2171
2172
6.44k
   if (key_len == 0)
2173
0
      return 0;
2174
2175
6.44k
#ifdef PNG_WARNINGS_SUPPORTED
2176
   /* Try to only output one warning per keyword: */
2177
6.44k
   if (*key != 0) /* keyword too long */
2178
0
      png_warning(png_ptr, "keyword truncated");
2179
2180
6.44k
   else if (bad_character != 0)
2181
288
   {
2182
288
      PNG_WARNING_PARAMETERS(p)
2183
2184
288
      png_warning_parameter(p, 1, orig_key);
2185
288
      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
2186
2187
288
      png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
2188
288
   }
2189
#else /* !WARNINGS */
2190
   PNG_UNUSED(png_ptr)
2191
#endif /* !WARNINGS */
2192
2193
6.44k
   return key_len;
2194
6.44k
}
2195
#endif /* TEXT || pCAL || iCCP || sPLT */
2196
#endif /* READ || WRITE */