Coverage Report

Created: 2026-05-16 06:16

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
8
{
27
8
   png_debug1(1, "in %s storage function", "bKGD");
28
29
8
   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
30
0
      return;
31
32
8
   info_ptr->background = *background;
33
8
   info_ptr->valid |= PNG_INFO_bKGD;
34
8
}
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
26
{
44
26
   png_debug1(1, "in %s storage function", "cHRM fixed");
45
46
26
   if (png_ptr == NULL || info_ptr == NULL)
47
0
      return;
48
49
26
   info_ptr->cHRM.redx = red_x;
50
26
   info_ptr->cHRM.redy = red_y;
51
26
   info_ptr->cHRM.greenx = green_x;
52
26
   info_ptr->cHRM.greeny = green_y;
53
26
   info_ptr->cHRM.bluex = blue_x;
54
26
   info_ptr->cHRM.bluey = blue_y;
55
26
   info_ptr->cHRM.whitex = white_x;
56
26
   info_ptr->cHRM.whitey = white_y;
57
58
26
   info_ptr->valid |= PNG_INFO_cHRM;
59
26
}
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
0
{
103
0
   png_set_cHRM_fixed(png_ptr, info_ptr,
104
0
       png_fixed(png_ptr, white_x, "cHRM White X"),
105
0
       png_fixed(png_ptr, white_y, "cHRM White Y"),
106
0
       png_fixed(png_ptr, red_x, "cHRM Red X"),
107
0
       png_fixed(png_ptr, red_y, "cHRM Red Y"),
108
0
       png_fixed(png_ptr, green_x, "cHRM Green X"),
109
0
       png_fixed(png_ptr, green_y, "cHRM Green Y"),
110
0
       png_fixed(png_ptr, blue_x, "cHRM Blue X"),
111
0
       png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
112
0
}
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
1
{
140
1
   png_debug1(1, "in %s storage function", "cICP");
141
142
1
   if (png_ptr == NULL || info_ptr == NULL)
143
0
      return;
144
145
1
   info_ptr->cicp_colour_primaries = colour_primaries;
146
1
   info_ptr->cicp_transfer_function = transfer_function;
147
1
   info_ptr->cicp_matrix_coefficients = matrix_coefficients;
148
1
   info_ptr->cicp_video_full_range_flag = video_full_range_flag;
149
150
1
   if (info_ptr->cicp_matrix_coefficients != 0)
151
1
   {
152
1
      png_warning(png_ptr, "Invalid cICP matrix coefficients");
153
1
      return;
154
1
   }
155
156
0
   info_ptr->valid |= PNG_INFO_cICP;
157
0
}
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
1
{
168
1
   png_debug1(1, "in %s storage function", "cLLI");
169
170
1
   if (png_ptr == NULL || info_ptr == NULL)
171
0
      return;
172
173
   /* Check the light level range: */
174
1
   if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU)
175
0
   {
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
0
      png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit",
183
0
            PNG_CHUNK_WRITE_ERROR);
184
0
      return;
185
0
   }
186
187
1
   info_ptr->maxCLL = maxCLL;
188
1
   info_ptr->maxFALL = maxFALL;
189
1
   info_ptr->valid |= PNG_INFO_cLLI;
190
1
}
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
40
{
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
40
   v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */
215
40
   if (v > 65535 || v < 0)
216
0
   {
217
0
      *error = 1;
218
0
      return 0;
219
0
   }
220
221
40
   return (png_uint_16)/*SAFE*/v;
222
40
}
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
5
{
233
5
   png_uint_16 rx, ry, gx, gy, bx, by, wx, wy;
234
5
   int error;
235
236
5
   png_debug1(1, "in %s storage function", "mDCV");
237
238
5
   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
5
   error = 0;
243
5
   rx = png_ITU_fixed_16(&error, red_x);
244
5
   ry = png_ITU_fixed_16(&error, red_y);
245
5
   gx = png_ITU_fixed_16(&error, green_x);
246
5
   gy = png_ITU_fixed_16(&error, green_y);
247
5
   bx = png_ITU_fixed_16(&error, blue_x);
248
5
   by = png_ITU_fixed_16(&error, blue_y);
249
5
   wx = png_ITU_fixed_16(&error, white_x);
250
5
   wy = png_ITU_fixed_16(&error, white_y);
251
252
5
   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
5
   if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU)
262
2
   {
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
2
      png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit",
270
2
            PNG_CHUNK_WRITE_ERROR);
271
2
      return;
272
2
   }
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
3
   info_ptr->mastering_red_x = rx;
283
3
   info_ptr->mastering_red_y = ry;
284
3
   info_ptr->mastering_green_x = gx;
285
3
   info_ptr->mastering_green_y = gy;
286
3
   info_ptr->mastering_blue_x = bx;
287
3
   info_ptr->mastering_blue_y = by;
288
3
   info_ptr->mastering_white_x = wx;
289
3
   info_ptr->mastering_white_y = wy;
290
3
   info_ptr->mastering_maxDL = maxDL;
291
3
   info_ptr->mastering_minDL = minDL;
292
3
   info_ptr->valid |= PNG_INFO_mDCV;
293
3
}
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
0
{
322
0
   png_byte *new_exif;
323
324
0
   png_debug1(1, "in %s storage function", "eXIf");
325
326
0
   if (png_ptr == NULL || info_ptr == NULL ||
327
0
       (png_ptr->mode & PNG_WROTE_eXIf) != 0 ||
328
0
       exif == NULL)
329
0
      return;
330
331
0
   new_exif = png_voidcast(png_byte *, png_malloc_warn(png_ptr, num_exif));
332
333
0
   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
0
   memcpy(new_exif, exif, (size_t)num_exif);
340
341
0
   png_free_data(png_ptr, info_ptr, PNG_FREE_EXIF, 0);
342
343
0
   info_ptr->num_exif = num_exif;
344
0
   info_ptr->exif = new_exif;
345
0
   info_ptr->free_me |= PNG_FREE_EXIF;
346
0
   info_ptr->valid |= PNG_INFO_eXIf;
347
0
}
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
82
{
355
82
   png_debug1(1, "in %s storage function", "gAMA");
356
357
82
   if (png_ptr == NULL || info_ptr == NULL)
358
0
      return;
359
360
82
   info_ptr->gamma = file_gamma;
361
82
   info_ptr->valid |= PNG_INFO_gAMA;
362
82
}
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
0
{
368
0
   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
369
0
       "png_set_gAMA"));
370
0
}
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
5
{
379
5
   png_uint_16 safe_hist[PNG_MAX_PALETTE_LENGTH];
380
5
   int i;
381
382
5
   png_debug1(1, "in %s storage function", "hIST");
383
384
5
   if (png_ptr == NULL || info_ptr == NULL || hist == NULL)
385
0
      return;
386
387
5
   if (info_ptr->num_palette == 0 || info_ptr->num_palette
388
0
       > PNG_MAX_PALETTE_LENGTH)
389
5
   {
390
5
      png_warning(png_ptr,
391
5
          "Invalid palette size, hIST allocation skipped");
392
393
5
      return;
394
5
   }
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
73.7k
{
431
73.7k
   png_debug1(1, "in %s storage function", "IHDR");
432
433
73.7k
   if (png_ptr == NULL || info_ptr == NULL)
434
0
      return;
435
436
73.7k
   info_ptr->width = width;
437
73.7k
   info_ptr->height = height;
438
73.7k
   info_ptr->bit_depth = (png_byte)bit_depth;
439
73.7k
   info_ptr->color_type = (png_byte)color_type;
440
73.7k
   info_ptr->compression_type = (png_byte)compression_type;
441
73.7k
   info_ptr->filter_type = (png_byte)filter_type;
442
73.7k
   info_ptr->interlace_type = (png_byte)interlace_type;
443
444
73.7k
   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
445
73.7k
       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
446
73.7k
       info_ptr->compression_type, info_ptr->filter_type);
447
448
73.7k
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
449
572
      info_ptr->channels = 1;
450
451
73.2k
   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
452
1.17k
      info_ptr->channels = 3;
453
454
72.0k
   else
455
72.0k
      info_ptr->channels = 1;
456
457
73.7k
   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
458
223
      info_ptr->channels++;
459
460
73.7k
   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
461
462
73.7k
   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
463
464
73.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
73.7k
   info_ptr->num_frames = 1;
469
73.7k
#endif
470
73.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
12
{
477
12
   png_debug1(1, "in %s storage function", "oFFs");
478
479
12
   if (png_ptr == NULL || info_ptr == NULL)
480
0
      return;
481
482
12
   info_ptr->x_offset = offset_x;
483
12
   info_ptr->y_offset = offset_y;
484
12
   info_ptr->offset_unit_type = (png_byte)unit_type;
485
12
   info_ptr->valid |= PNG_INFO_oFFs;
486
12
}
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
2
{
495
2
   size_t length;
496
2
   int i;
497
498
2
   png_debug1(1, "in %s storage function", "pCAL");
499
500
2
   if (png_ptr == NULL || info_ptr == NULL || purpose == NULL || units == NULL
501
2
       || (nparams > 0 && params == NULL))
502
0
      return;
503
504
2
   length = strlen(purpose) + 1;
505
2
   png_debug1(3, "allocating purpose for info (%lu bytes)",
506
2
       (unsigned long)length);
507
508
   /* TODO: validate format of calibration name and unit name */
509
510
   /* Check that the type matches the specification. */
511
2
   if (type < 0 || type > 3)
512
2
   {
513
2
      png_chunk_report(png_ptr, "Invalid pCAL equation type",
514
2
            PNG_CHUNK_WRITE_ERROR);
515
2
      return;
516
2
   }
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
55.8k
{
735
55.8k
   png_debug1(1, "in %s storage function", "pHYs");
736
737
55.8k
   if (png_ptr == NULL || info_ptr == NULL)
738
0
      return;
739
740
55.8k
   info_ptr->x_pixels_per_unit = res_x;
741
55.8k
   info_ptr->y_pixels_per_unit = res_y;
742
55.8k
   info_ptr->phys_unit_type = (png_byte)unit_type;
743
55.8k
   info_ptr->valid |= PNG_INFO_pHYs;
744
55.8k
}
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
483
{
751
483
   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
752
483
   png_uint_32 max_palette_length;
753
754
483
   png_debug1(1, "in %s storage function", "PLTE");
755
756
483
   if (png_ptr == NULL || info_ptr == NULL)
757
0
      return;
758
759
483
   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
760
464
      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
761
762
483
   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
483
   if ((num_palette > 0 && palette == NULL) ||
776
483
      (num_palette == 0
777
2
#        ifdef PNG_MNG_FEATURES_SUPPORTED
778
2
            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
779
483
#        endif
780
483
      ))
781
2
   {
782
2
      png_error(png_ptr, "Invalid palette");
783
2
   }
784
785
   /* Snapshot the caller's palette before freeing, in case it points to
786
    * info_ptr->palette (getter-to-setter aliasing).
787
    */
788
481
   if (num_palette > 0)
789
481
      memcpy(safe_palette, palette, (unsigned int)num_palette *
790
481
          (sizeof (png_color)));
791
792
481
   palette = safe_palette;
793
794
481
   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
481
   png_free(png_ptr, png_ptr->palette);
812
481
   png_ptr->palette = png_voidcast(png_color *, png_calloc(png_ptr,
813
481
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
814
481
   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
815
481
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
816
481
   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
817
818
481
   if (num_palette > 0)
819
481
   {
820
481
      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
821
481
          (sizeof (png_color)));
822
481
      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
823
481
          (sizeof (png_color)));
824
481
   }
825
826
481
   info_ptr->free_me |= PNG_FREE_PLTE;
827
481
   info_ptr->valid |= PNG_INFO_PLTE;
828
481
}
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
1
{
835
1
   png_debug1(1, "in %s storage function", "sBIT");
836
837
1
   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
838
0
      return;
839
840
1
   info_ptr->sig_bit = *sig_bit;
841
1
   info_ptr->valid |= PNG_INFO_sBIT;
842
1
}
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
21
{
849
21
   png_debug1(1, "in %s storage function", "sRGB");
850
851
21
   if (png_ptr == NULL || info_ptr == NULL)
852
0
      return;
853
854
21
   info_ptr->rendering_intent = srgb_intent;
855
21
   info_ptr->valid |= PNG_INFO_sRGB;
856
21
}
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
0
{
891
0
   char *new_iccp_name;
892
0
   png_byte *new_iccp_profile;
893
0
   size_t length;
894
895
0
   png_debug1(1, "in %s storage function", "iCCP");
896
897
0
   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
898
0
      return;
899
900
0
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
901
0
      png_app_error(png_ptr, "Invalid iCCP compression method");
902
903
0
   length = strlen(name)+1;
904
0
   new_iccp_name = png_voidcast(char *, png_malloc_warn(png_ptr, length));
905
906
0
   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
0
   memcpy(new_iccp_name, name, length);
914
0
   new_iccp_profile = png_voidcast(png_byte *,
915
0
       png_malloc_warn(png_ptr, proflen));
916
917
0
   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
0
   memcpy(new_iccp_profile, profile, proflen);
927
928
0
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
929
930
0
   info_ptr->iccp_proflen = proflen;
931
0
   info_ptr->iccp_name = new_iccp_name;
932
0
   info_ptr->iccp_profile = new_iccp_profile;
933
0
   info_ptr->free_me |= PNG_FREE_ICCP;
934
0
   info_ptr->valid |= PNG_INFO_iCCP;
935
0
}
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
0
{
943
0
   int ret;
944
0
   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
945
946
0
   if (ret != 0)
947
0
      png_error(png_ptr, "Insufficient memory to store text");
948
0
}
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
38.9k
{
954
38.9k
   int i;
955
38.9k
   png_textp old_text = NULL;
956
957
38.9k
   png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
958
38.9k
      png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
959
960
38.9k
   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
38.9k
   if (num_text > info_ptr->max_text - info_ptr->num_text)
969
33.7k
   {
970
33.7k
      int old_num_text = info_ptr->num_text;
971
33.7k
      int max_text;
972
33.7k
      png_text *new_text = NULL;
973
974
      /* Calculate an appropriate max_text, checking for overflow. */
975
33.7k
      max_text = old_num_text;
976
33.7k
      if (num_text <= INT_MAX - max_text)
977
33.7k
      {
978
33.7k
         max_text += num_text;
979
980
         /* Round up to a multiple of 8 */
981
33.7k
         if (max_text < INT_MAX-8)
982
33.7k
            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
33.7k
         new_text = png_voidcast(png_text *,png_realloc_array(png_ptr,
991
33.7k
             info_ptr->text, old_num_text, max_text-old_num_text,
992
33.7k
             sizeof *new_text));
993
33.7k
      }
994
995
33.7k
      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
33.7k
      old_text = info_ptr->text;
1007
1008
33.7k
      info_ptr->text = new_text;
1009
33.7k
      info_ptr->free_me |= PNG_FREE_TEXT;
1010
33.7k
      info_ptr->max_text = max_text;
1011
      /* num_text is adjusted below as the entries are copied in */
1012
1013
33.7k
      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
1014
33.7k
   }
1015
1016
77.9k
   for (i = 0; i < num_text; i++)
1017
38.9k
   {
1018
38.9k
      size_t text_length, key_len;
1019
38.9k
      size_t lang_len, lang_key_len;
1020
38.9k
      png_text *textp = &(info_ptr->text[info_ptr->num_text]);
1021
1022
38.9k
      if (text_ptr[i].key == NULL)
1023
0
          continue;
1024
1025
38.9k
      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
1026
38.9k
          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
38.9k
      key_len = strlen(text_ptr[i].key);
1034
1035
38.9k
      if (text_ptr[i].compression <= 0)
1036
37.3k
      {
1037
37.3k
         lang_len = 0;
1038
37.3k
         lang_key_len = 0;
1039
37.3k
      }
1040
1041
1.58k
      else
1042
1.58k
#  ifdef PNG_iTXt_SUPPORTED
1043
1.58k
      {
1044
         /* Set iTXt data */
1045
1046
1.58k
         if (text_ptr[i].lang != NULL)
1047
1.58k
            lang_len = strlen(text_ptr[i].lang);
1048
1049
0
         else
1050
0
            lang_len = 0;
1051
1052
1.58k
         if (text_ptr[i].lang_key != NULL)
1053
1.58k
            lang_key_len = strlen(text_ptr[i].lang_key);
1054
1055
0
         else
1056
0
            lang_key_len = 0;
1057
1.58k
      }
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
38.9k
      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
1067
5.65k
      {
1068
5.65k
         text_length = 0;
1069
5.65k
#  ifdef PNG_iTXt_SUPPORTED
1070
5.65k
         if (text_ptr[i].compression > 0)
1071
1.58k
            textp->compression = PNG_ITXT_COMPRESSION_NONE;
1072
1073
4.07k
         else
1074
4.07k
#  endif
1075
4.07k
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
1076
5.65k
      }
1077
1078
33.2k
      else
1079
33.2k
      {
1080
33.2k
         text_length = strlen(text_ptr[i].text);
1081
33.2k
         textp->compression = text_ptr[i].compression;
1082
33.2k
      }
1083
1084
38.9k
      textp->key = png_voidcast(char *,png_malloc_base(png_ptr,
1085
38.9k
          key_len + text_length + lang_len + lang_key_len + 4));
1086
1087
38.9k
      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
38.9k
      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
1097
38.9k
          (unsigned long)(png_uint_32)
1098
38.9k
          (key_len + lang_len + lang_key_len + text_length + 4),
1099
38.9k
          textp->key);
1100
1101
38.9k
      memcpy(textp->key, text_ptr[i].key, key_len);
1102
38.9k
      *(textp->key + key_len) = '\0';
1103
1104
38.9k
      if (text_ptr[i].compression > 0)
1105
1.58k
      {
1106
1.58k
         textp->lang = textp->key + key_len + 1;
1107
1.58k
         memcpy(textp->lang, text_ptr[i].lang, lang_len);
1108
1.58k
         *(textp->lang + lang_len) = '\0';
1109
1.58k
         textp->lang_key = textp->lang + lang_len + 1;
1110
1.58k
         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
1111
1.58k
         *(textp->lang_key + lang_key_len) = '\0';
1112
1.58k
         textp->text = textp->lang_key + lang_key_len + 1;
1113
1.58k
      }
1114
1115
37.3k
      else
1116
37.3k
      {
1117
37.3k
         textp->lang=NULL;
1118
37.3k
         textp->lang_key=NULL;
1119
37.3k
         textp->text = textp->key + key_len + 1;
1120
37.3k
      }
1121
1122
38.9k
      if (text_length != 0)
1123
33.2k
         memcpy(textp->text, text_ptr[i].text, text_length);
1124
1125
38.9k
      *(textp->text + text_length) = '\0';
1126
1127
38.9k
#  ifdef PNG_iTXt_SUPPORTED
1128
38.9k
      if (textp->compression > 0)
1129
1.58k
      {
1130
1.58k
         textp->text_length = 0;
1131
1.58k
         textp->itxt_length = text_length;
1132
1.58k
      }
1133
1134
37.3k
      else
1135
37.3k
#  endif
1136
37.3k
      {
1137
37.3k
         textp->text_length = text_length;
1138
37.3k
         textp->itxt_length = 0;
1139
37.3k
      }
1140
1141
38.9k
      info_ptr->num_text++;
1142
38.9k
      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
1143
38.9k
   }
1144
1145
38.9k
   png_free(png_ptr, old_text);
1146
1147
38.9k
   return 0;
1148
38.9k
}
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
4
{
1156
4
   png_debug1(1, "in %s storage function", "tIME");
1157
1158
4
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
1159
4
       (png_ptr->mode & PNG_WROTE_tIME) != 0)
1160
0
      return;
1161
1162
4
   if (mod_time->month == 0   || mod_time->month > 12  ||
1163
2
       mod_time->day   == 0   || mod_time->day   > 31  ||
1164
0
       mod_time->hour  > 23   || mod_time->minute > 59 ||
1165
0
       mod_time->second > 60)
1166
4
   {
1167
4
      png_warning(png_ptr, "Ignoring invalid time value");
1168
1169
4
      return;
1170
4
   }
1171
1172
0
   info_ptr->mod_time = *mod_time;
1173
0
   info_ptr->valid |= PNG_INFO_tIME;
1174
0
}
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
365
{
1182
365
   png_debug1(1, "in %s storage function", "tRNS");
1183
1184
365
   if (png_ptr == NULL || info_ptr == NULL)
1185
1186
0
      return;
1187
1188
365
   if (trans_alpha != NULL)
1189
365
   {
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
365
       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
1194
1195
365
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1196
365
          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
1197
1198
365
       trans_alpha = safe_trans;
1199
1200
365
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
1201
1202
365
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1203
365
       {
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
365
          info_ptr->trans_alpha = png_voidcast(png_byte *,
1209
365
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1210
365
          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1211
365
          memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1212
365
          info_ptr->free_me |= PNG_FREE_TRNS;
1213
365
          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
365
          png_free(png_ptr, png_ptr->trans_alpha);
1224
365
          png_ptr->trans_alpha = png_voidcast(png_bytep,
1225
365
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1226
365
          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1227
365
          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1228
365
       }
1229
0
       else
1230
0
       {
1231
0
          png_free(png_ptr, png_ptr->trans_alpha);
1232
0
          png_ptr->trans_alpha = NULL;
1233
0
       }
1234
365
   }
1235
1236
365
   if (trans_color != NULL)
1237
121
   {
1238
121
#ifdef PNG_WARNINGS_SUPPORTED
1239
121
      if (info_ptr->bit_depth < 16)
1240
121
      {
1241
121
         int sample_max = (1 << info_ptr->bit_depth) - 1;
1242
1243
121
         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1244
42
             trans_color->gray > sample_max) ||
1245
80
             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1246
12
             (trans_color->red > sample_max ||
1247
3
             trans_color->green > sample_max ||
1248
1
             trans_color->blue > sample_max)))
1249
52
            png_warning(png_ptr,
1250
52
                "tRNS chunk has out-of-range samples for bit_depth");
1251
121
      }
1252
121
#endif
1253
1254
121
      info_ptr->trans_color = *trans_color;
1255
1256
121
      if (num_trans == 0)
1257
0
         num_trans = 1;
1258
121
   }
1259
1260
365
   info_ptr->num_trans = (png_uint_16)num_trans;
1261
1262
365
   if (num_trans != 0)
1263
365
   {
1264
365
      info_ptr->free_me |= PNG_FREE_TRNS;
1265
365
      info_ptr->valid |= PNG_INFO_tRNS;
1266
365
   }
1267
365
}
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
860
{
1283
860
   png_sPLT_t *np;
1284
860
   png_sPLT_t *old_spalettes;
1285
1286
860
   png_debug1(1, "in %s storage function", "sPLT");
1287
1288
860
   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
860
   np = png_voidcast(png_sPLT_t *,png_realloc_array(png_ptr,
1295
860
       info_ptr->splt_palettes, info_ptr->splt_palettes_num, nentries,
1296
860
       sizeof *np));
1297
1298
860
   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
860
   old_spalettes = info_ptr->splt_palettes;
1309
1310
860
   info_ptr->splt_palettes = np;
1311
860
   info_ptr->free_me |= PNG_FREE_SPLT;
1312
1313
860
   np += info_ptr->splt_palettes_num;
1314
1315
860
   do
1316
860
   {
1317
860
      size_t length;
1318
1319
      /* Skip invalid input entries */
1320
860
      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
860
      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
860
      length = strlen(entries->name) + 1;
1334
860
      np->name = png_voidcast(char *, png_malloc_base(png_ptr, length));
1335
1336
860
      if (np->name == NULL)
1337
0
         break;
1338
1339
860
      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
860
      np->entries = png_voidcast(png_sPLT_entry *, png_malloc_array(png_ptr,
1346
860
          entries->nentries, sizeof (png_sPLT_entry)));
1347
1348
860
      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
860
      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
860
      memcpy(np->entries, entries->entries,
1360
860
          (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
860
      info_ptr->valid |= PNG_INFO_sPLT;
1366
860
      ++(info_ptr->splt_palettes_num);
1367
860
      ++np;
1368
860
      ++entries;
1369
860
   }
1370
860
   while (--nentries);
1371
1372
860
   png_free(png_ptr, old_spalettes);
1373
1374
860
   if (nentries > 0)
1375
0
      png_chunk_report(png_ptr, "sPLT out of memory", PNG_CHUNK_WRITE_ERROR);
1376
860
}
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
76
{
1384
76
   png_debug1(1, "in %s storage function", "acTL");
1385
1386
76
   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
76
   if (num_frames == 0)
1393
29
   {
1394
29
      png_warning(png_ptr,
1395
29
                  "Ignoring attempt to set acTL with num_frames zero");
1396
29
      return 0;
1397
29
   }
1398
47
   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
47
   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
47
   info_ptr->num_frames = num_frames;
1412
47
   info_ptr->num_plays = num_plays;
1413
1414
47
   info_ptr->valid |= PNG_INFO_acTL;
1415
1416
47
   return 1;
1417
47
}
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
16
{
1426
16
   png_debug1(1, "in %s storage function", "fcTL");
1427
1428
16
   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
16
   png_ensure_fcTL_is_valid(png_ptr, width, height, x_offset, y_offset,
1436
16
                            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
16
   if (blend_op == PNG_fcTL_BLEND_OP_OVER)
1443
1
   {
1444
1
      if (!(png_ptr->color_type & PNG_COLOR_MASK_ALPHA) &&
1445
1
          !(png_get_valid(png_ptr, info_ptr, PNG_INFO_tRNS)))
1446
1
      {
1447
1
         png_warning(png_ptr,
1448
1
                     "Ignoring wasteful fcTL BLEND_OP_OVER in opaque images");
1449
1
         blend_op = PNG_fcTL_BLEND_OP_SOURCE;
1450
1
      }
1451
1
   }
1452
1453
16
   info_ptr->next_frame_width = width;
1454
16
   info_ptr->next_frame_height = height;
1455
16
   info_ptr->next_frame_x_offset = x_offset;
1456
16
   info_ptr->next_frame_y_offset = y_offset;
1457
16
   info_ptr->next_frame_delay_num = delay_num;
1458
16
   info_ptr->next_frame_delay_den = delay_den;
1459
16
   info_ptr->next_frame_dispose_op = dispose_op;
1460
16
   info_ptr->next_frame_blend_op = blend_op;
1461
1462
16
   info_ptr->valid |= PNG_INFO_fcTL;
1463
1464
16
   return 1;
1465
16
}
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
16
{
1474
16
   if (width == 0 || width > PNG_UINT_31_MAX)
1475
0
      png_error(png_ptr, "Invalid frame width in fcTL");
1476
16
   if (height == 0 || height > PNG_UINT_31_MAX)
1477
0
      png_error(png_ptr, "Invalid frame height in fcTL");
1478
16
   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
16
   if (width + x_offset > png_ptr->first_frame_width ||
1481
16
       height + y_offset > png_ptr->first_frame_height)
1482
0
      png_error(png_ptr, "Oversized frame in fcTL");
1483
1484
16
   if (dispose_op != PNG_fcTL_DISPOSE_OP_NONE &&
1485
11
       dispose_op != PNG_fcTL_DISPOSE_OP_BACKGROUND &&
1486
8
       dispose_op != PNG_fcTL_DISPOSE_OP_PREVIOUS)
1487
6
      png_error(png_ptr, "Invalid dispose_op in fcTL");
1488
1489
10
   if (blend_op != PNG_fcTL_BLEND_OP_SOURCE &&
1490
8
       blend_op != PNG_fcTL_BLEND_OP_OVER)
1491
7
      png_error(png_ptr, "Invalid blend_op in fcTL");
1492
1493
3
   PNG_UNUSED(delay_num)
1494
3
   PNG_UNUSED(delay_den)
1495
3
}
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
0
{
1521
0
   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
0
   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
0
   if (location == 0)
1541
0
      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
0
   while (location != (location & -location))
1547
0
      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
0
   return (png_byte)location;
1553
0
}
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
0
{
1559
0
   png_unknown_chunk *np;
1560
0
   png_unknown_chunk *old_unknowns;
1561
1562
0
   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
1563
0
       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
0
   np = png_voidcast(png_unknown_chunk *, png_realloc_array(png_ptr,
1597
0
       info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
1598
0
       sizeof *np));
1599
1600
0
   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
0
   old_unknowns = info_ptr->unknown_chunks;
1611
1612
0
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
1613
0
   info_ptr->free_me |= PNG_FREE_UNKN;
1614
1615
0
   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
0
   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
1621
0
   {
1622
0
      memcpy(np->name, unknowns->name, (sizeof np->name));
1623
0
      np->name[(sizeof np->name)-1] = '\0';
1624
0
      np->location = check_location(png_ptr, unknowns->location);
1625
1626
0
      if (unknowns->size == 0)
1627
0
      {
1628
0
         np->data = NULL;
1629
0
         np->size = 0;
1630
0
      }
1631
1632
0
      else
1633
0
      {
1634
0
         np->data = png_voidcast(png_byte *,
1635
0
             png_malloc_base(png_ptr, unknowns->size));
1636
1637
0
         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
0
         memcpy(np->data, unknowns->data, unknowns->size);
1646
0
         np->size = unknowns->size;
1647
0
      }
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
0
      ++np;
1654
0
      ++(info_ptr->unknown_chunks_num);
1655
0
   }
1656
1657
0
   png_free(png_ptr, old_unknowns);
1658
0
}
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
0
{
1693
0
   png_debug(1, "in png_permit_mng_features");
1694
1695
0
   if (png_ptr == NULL)
1696
0
      return 0;
1697
1698
0
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1699
1700
0
   return png_ptr->mng_features_permitted;
1701
0
}
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
0
{
1708
0
   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
0
   for (i=0; i<count; ++i, list += 5)
1714
0
   {
1715
0
      if (memcmp(list, add, 4) == 0)
1716
0
      {
1717
0
         list[4] = (png_byte)keep;
1718
1719
0
         return count;
1720
0
      }
1721
0
   }
1722
1723
0
   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
1724
0
   {
1725
0
      ++count;
1726
0
      memcpy(list, add, 4);
1727
0
      list[4] = (png_byte)keep;
1728
0
   }
1729
1730
0
   return count;
1731
0
}
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
0
{
1737
0
   png_byte *new_list;
1738
0
   unsigned int num_chunks, old_num_chunks;
1739
1740
0
   if (png_ptr == NULL)
1741
0
      return;
1742
1743
0
   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
0
   if (num_chunks_in <= 0)
1751
0
   {
1752
0
      png_ptr->unknown_default = keep;
1753
1754
      /* '0' means just set the flags, so stop here */
1755
0
      if (num_chunks_in == 0)
1756
0
        return;
1757
0
   }
1758
1759
0
   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
0
   else /* num_chunks_in > 0 */
1796
0
   {
1797
0
      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
0
      num_chunks = (unsigned int)num_chunks_in;
1808
0
   }
1809
1810
0
   old_num_chunks = png_ptr->num_chunk_list;
1811
0
   if (png_ptr->chunk_list == NULL)
1812
0
      old_num_chunks = 0;
1813
1814
   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
1815
    */
1816
0
   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
0
   if (keep != 0)
1828
0
   {
1829
0
      new_list = png_voidcast(png_byte *, png_malloc(png_ptr,
1830
0
          5 * (num_chunks + old_num_chunks)));
1831
1832
0
      if (old_num_chunks > 0)
1833
0
         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1834
0
   }
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
0
   if (new_list != NULL)
1848
0
   {
1849
0
      const png_byte *inlist;
1850
0
      png_byte *outlist;
1851
0
      unsigned int i;
1852
1853
0
      for (i=0; i<num_chunks; ++i)
1854
0
      {
1855
0
         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
1856
0
             chunk_list+5*i, keep);
1857
0
      }
1858
1859
      /* Now remove any spurious 'default' entries. */
1860
0
      num_chunks = 0;
1861
0
      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1862
0
      {
1863
0
         if (inlist[4])
1864
0
         {
1865
0
            if (outlist != inlist)
1866
0
               memcpy(outlist, inlist, 5);
1867
0
            outlist += 5;
1868
0
            ++num_chunks;
1869
0
         }
1870
0
      }
1871
1872
      /* This means the application has removed all the specialized handling. */
1873
0
      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
0
   }
1881
1882
0
   else
1883
0
      num_chunks = 0;
1884
1885
0
   png_ptr->num_chunk_list = num_chunks;
1886
1887
0
   if (png_ptr->chunk_list != new_list)
1888
0
   {
1889
0
      if (png_ptr->chunk_list != NULL)
1890
0
         png_free(png_ptr, png_ptr->chunk_list);
1891
1892
0
      png_ptr->chunk_list = new_list;
1893
0
   }
1894
0
}
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
0
{
1902
0
   png_debug(1, "in png_set_read_user_chunk_fn");
1903
1904
0
   if (png_ptr == NULL)
1905
0
      return;
1906
1907
0
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
1908
0
   png_ptr->user_chunk_ptr = user_chunk_ptr;
1909
0
}
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
1.43k
{
1917
1.43k
   png_debug(1, "in png_set_rows");
1918
1919
1.43k
   if (png_ptr == NULL || info_ptr == NULL)
1920
0
      return;
1921
1922
1.43k
   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
1.43k
   info_ptr->row_pointers = row_pointers;
1927
1928
1.43k
   if (row_pointers != NULL)
1929
1.43k
      info_ptr->valid |= PNG_INFO_IDAT;
1930
1.43k
}
1931
#endif
1932
1933
void
1934
png_set_compression_buffer_size(png_struct *png_ptr, size_t size)
1935
0
{
1936
0
   png_debug(1, "in png_set_compression_buffer_size");
1937
1938
0
   if (png_ptr == NULL)
1939
0
      return;
1940
1941
0
   if (size == 0 || size > PNG_UINT_31_MAX)
1942
0
      png_error(png_ptr, "invalid compression buffer size");
1943
1944
0
#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1945
0
   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
0
#  endif
1951
1952
0
#  ifdef PNG_WRITE_SUPPORTED
1953
0
   if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1954
0
   {
1955
0
      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
0
#ifndef __COVERITY__
1964
      /* Some compilers complain that this is always false.  However, it
1965
       * can be true when integer overflow happens.
1966
       */
1967
0
      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
0
#endif
1974
1975
0
      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
0
      if (png_ptr->zbuffer_size != size)
1987
0
      {
1988
0
         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
1989
0
         png_ptr->zbuffer_size = (uInt)size;
1990
0
      }
1991
0
   }
1992
0
#  endif
1993
0
}
1994
1995
void
1996
png_set_invalid(const png_struct *png_ptr, png_info *info_ptr, int mask)
1997
0
{
1998
0
   if (png_ptr != NULL && info_ptr != NULL)
1999
0
      info_ptr->valid &= (unsigned int)(~mask);
2000
0
}
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
0
{
2009
0
   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
0
   if (png_ptr == NULL)
2016
0
      return;
2017
2018
0
   png_ptr->user_width_max = user_width_max;
2019
0
   png_ptr->user_height_max = user_height_max;
2020
0
}
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
0
{
2026
0
   png_debug(1, "in png_set_chunk_cache_max");
2027
2028
0
   if (png_ptr != NULL)
2029
0
      png_ptr->user_chunk_cache_max = user_chunk_cache_max;
2030
0
}
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
0
{
2065
0
   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
0
   if (allowed != 0)
2074
0
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
2075
0
         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
0
}
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
0
{
2095
0
   png_debug(1, "in png_set_check_for_invalid_index");
2096
2097
0
   if (allowed > 0)
2098
0
      png_ptr->num_palette_max = 0;
2099
2100
0
   else
2101
0
      png_ptr->num_palette_max = -1;
2102
0
}
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
0
{
2120
0
#ifdef PNG_WARNINGS_SUPPORTED
2121
0
   const char *orig_key = key;
2122
0
#endif
2123
0
   png_uint_32 key_len = 0;
2124
0
   int bad_character = 0;
2125
0
   int space = 1;
2126
2127
0
   png_debug(1, "in png_check_keyword");
2128
2129
0
   if (key == NULL)
2130
0
   {
2131
0
      *new_key = 0;
2132
0
      return 0;
2133
0
   }
2134
2135
0
   while (*key && key_len < 79)
2136
0
   {
2137
0
      png_byte ch = (png_byte)*key++;
2138
2139
0
      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
2140
0
      {
2141
0
         *new_key++ = ch; ++key_len; space = 0;
2142
0
      }
2143
2144
0
      else if (space == 0)
2145
0
      {
2146
         /* A space or an invalid character when one wasn't seen immediately
2147
          * before; output just a space.
2148
          */
2149
0
         *new_key++ = 32; ++key_len; space = 1;
2150
2151
         /* If the character was not a space then it is invalid. */
2152
0
         if (ch != 32)
2153
0
            bad_character = ch;
2154
0
      }
2155
2156
0
      else if (bad_character == 0)
2157
0
         bad_character = ch; /* just skip it, record the first error */
2158
0
   }
2159
2160
0
   if (key_len > 0 && space != 0) /* trailing space */
2161
0
   {
2162
0
      --key_len; --new_key;
2163
0
      if (bad_character == 0)
2164
0
         bad_character = 32;
2165
0
   }
2166
2167
   /* Terminate the keyword */
2168
0
   *new_key = 0;
2169
2170
0
   if (key_len == 0)
2171
0
      return 0;
2172
2173
0
#ifdef PNG_WARNINGS_SUPPORTED
2174
   /* Try to only output one warning per keyword: */
2175
0
   if (*key != 0) /* keyword too long */
2176
0
      png_warning(png_ptr, "keyword truncated");
2177
2178
0
   else if (bad_character != 0)
2179
0
   {
2180
0
      PNG_WARNING_PARAMETERS(p)
2181
2182
0
      png_warning_parameter(p, 1, orig_key);
2183
0
      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
2184
2185
0
      png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
2186
0
   }
2187
#else /* !WARNINGS */
2188
   PNG_UNUSED(png_ptr)
2189
#endif /* !WARNINGS */
2190
2191
0
   return key_len;
2192
0
}
2193
#endif /* TEXT || pCAL || iCCP || sPLT */
2194
#endif /* READ || WRITE */