Coverage Report

Created: 2026-07-25 07:06

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
10.6k
{
27
10.6k
   png_debug1(1, "in %s storage function", "bKGD");
28
29
10.6k
   if (png_ptr == NULL || info_ptr == NULL || background == NULL)
30
0
      return;
31
32
10.6k
   info_ptr->background = *background;
33
10.6k
   info_ptr->valid |= PNG_INFO_bKGD;
34
10.6k
}
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
17.7k
{
44
17.7k
   png_debug1(1, "in %s storage function", "cHRM fixed");
45
46
17.7k
   if (png_ptr == NULL || info_ptr == NULL)
47
0
      return;
48
49
17.7k
   info_ptr->cHRM.redx = red_x;
50
17.7k
   info_ptr->cHRM.redy = red_y;
51
17.7k
   info_ptr->cHRM.greenx = green_x;
52
17.7k
   info_ptr->cHRM.greeny = green_y;
53
17.7k
   info_ptr->cHRM.bluex = blue_x;
54
17.7k
   info_ptr->cHRM.bluey = blue_y;
55
17.7k
   info_ptr->cHRM.whitex = white_x;
56
17.7k
   info_ptr->cHRM.whitey = white_y;
57
58
17.7k
   info_ptr->valid |= PNG_INFO_cHRM;
59
17.7k
}
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
5.39k
{
103
5.39k
   png_set_cHRM_fixed(png_ptr, info_ptr,
104
5.39k
       png_fixed(png_ptr, white_x, "cHRM White X"),
105
5.39k
       png_fixed(png_ptr, white_y, "cHRM White Y"),
106
5.39k
       png_fixed(png_ptr, red_x, "cHRM Red X"),
107
5.39k
       png_fixed(png_ptr, red_y, "cHRM Red Y"),
108
5.39k
       png_fixed(png_ptr, green_x, "cHRM Green X"),
109
5.39k
       png_fixed(png_ptr, green_y, "cHRM Green Y"),
110
5.39k
       png_fixed(png_ptr, blue_x, "cHRM Blue X"),
111
5.39k
       png_fixed(png_ptr, blue_y, "cHRM Blue Y"));
112
5.39k
}
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
171
{
140
171
   png_debug1(1, "in %s storage function", "cICP");
141
142
171
   if (png_ptr == NULL || info_ptr == NULL)
143
0
      return;
144
145
171
   info_ptr->cicp_colour_primaries = colour_primaries;
146
171
   info_ptr->cicp_transfer_function = transfer_function;
147
171
   info_ptr->cicp_matrix_coefficients = matrix_coefficients;
148
171
   info_ptr->cicp_video_full_range_flag = video_full_range_flag;
149
150
171
   if (info_ptr->cicp_matrix_coefficients != 0)
151
132
   {
152
132
      png_warning(png_ptr, "Invalid cICP matrix coefficients");
153
132
      return;
154
132
   }
155
156
39
   info_ptr->valid |= PNG_INFO_cICP;
157
39
}
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
750
{
168
750
   png_debug1(1, "in %s storage function", "cLLI");
169
170
750
   if (png_ptr == NULL || info_ptr == NULL)
171
0
      return;
172
173
   /* Check the light level range: */
174
750
   if (maxCLL > 0x7FFFFFFFU || maxFALL > 0x7FFFFFFFU)
175
655
   {
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
655
      png_chunk_report(png_ptr, "cLLI light level exceeds PNG limit",
183
655
            PNG_CHUNK_WRITE_ERROR);
184
655
      return;
185
655
   }
186
187
95
   info_ptr->maxCLL = maxCLL;
188
95
   info_ptr->maxFALL = maxFALL;
189
95
   info_ptr->valid |= PNG_INFO_cLLI;
190
95
}
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
5.09k
{
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
5.09k
   v /= 2; /* rounds to 0 in C: avoids insignificant arithmetic errors */
215
5.09k
   if (v > 65535 || v < 0)
216
0
   {
217
0
      *error = 1;
218
0
      return 0;
219
0
   }
220
221
5.09k
   return (png_uint_16)/*SAFE*/v;
222
5.09k
}
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
637
{
233
637
   png_uint_16 rx, ry, gx, gy, bx, by, wx, wy;
234
637
   int error;
235
236
637
   png_debug1(1, "in %s storage function", "mDCV");
237
238
637
   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
637
   error = 0;
243
637
   rx = png_ITU_fixed_16(&error, red_x);
244
637
   ry = png_ITU_fixed_16(&error, red_y);
245
637
   gx = png_ITU_fixed_16(&error, green_x);
246
637
   gy = png_ITU_fixed_16(&error, green_y);
247
637
   bx = png_ITU_fixed_16(&error, blue_x);
248
637
   by = png_ITU_fixed_16(&error, blue_y);
249
637
   wx = png_ITU_fixed_16(&error, white_x);
250
637
   wy = png_ITU_fixed_16(&error, white_y);
251
252
637
   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
637
   if (maxDL > 0x7FFFFFFFU || minDL > 0x7FFFFFFFU)
262
509
   {
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
509
      png_chunk_report(png_ptr, "mDCV display light level exceeds PNG limit",
270
509
            PNG_CHUNK_WRITE_ERROR);
271
509
      return;
272
509
   }
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
128
   info_ptr->mastering_red_x = rx;
283
128
   info_ptr->mastering_red_y = ry;
284
128
   info_ptr->mastering_green_x = gx;
285
128
   info_ptr->mastering_green_y = gy;
286
128
   info_ptr->mastering_blue_x = bx;
287
128
   info_ptr->mastering_blue_y = by;
288
128
   info_ptr->mastering_white_x = wx;
289
128
   info_ptr->mastering_white_y = wy;
290
128
   info_ptr->mastering_maxDL = maxDL;
291
128
   info_ptr->mastering_minDL = minDL;
292
128
   info_ptr->valid |= PNG_INFO_mDCV;
293
128
}
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
2.83k
{
355
2.83k
   png_debug1(1, "in %s storage function", "gAMA");
356
357
2.83k
   if (png_ptr == NULL || info_ptr == NULL)
358
0
      return;
359
360
2.83k
   info_ptr->gamma = file_gamma;
361
2.83k
   info_ptr->valid |= PNG_INFO_gAMA;
362
2.83k
}
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
1.38k
{
368
1.38k
   png_set_gAMA_fixed(png_ptr, info_ptr, png_fixed(png_ptr, file_gamma,
369
1.38k
       "png_set_gAMA"));
370
1.38k
}
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
338k
{
431
338k
   png_debug1(1, "in %s storage function", "IHDR");
432
433
338k
   if (png_ptr == NULL || info_ptr == NULL)
434
0
      return;
435
436
338k
   info_ptr->width = width;
437
338k
   info_ptr->height = height;
438
338k
   info_ptr->bit_depth = (png_byte)bit_depth;
439
338k
   info_ptr->color_type = (png_byte)color_type;
440
338k
   info_ptr->compression_type = (png_byte)compression_type;
441
338k
   info_ptr->filter_type = (png_byte)filter_type;
442
338k
   info_ptr->interlace_type = (png_byte)interlace_type;
443
444
338k
   png_check_IHDR (png_ptr, info_ptr->width, info_ptr->height,
445
338k
       info_ptr->bit_depth, info_ptr->color_type, info_ptr->interlace_type,
446
338k
       info_ptr->compression_type, info_ptr->filter_type);
447
448
338k
   if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
449
49.9k
      info_ptr->channels = 1;
450
451
288k
   else if ((info_ptr->color_type & PNG_COLOR_MASK_COLOR) != 0)
452
120k
      info_ptr->channels = 3;
453
454
167k
   else
455
167k
      info_ptr->channels = 1;
456
457
338k
   if ((info_ptr->color_type & PNG_COLOR_MASK_ALPHA) != 0)
458
54.0k
      info_ptr->channels++;
459
460
338k
   info_ptr->pixel_depth = (png_byte)(info_ptr->channels * info_ptr->bit_depth);
461
462
338k
   info_ptr->rowbytes = PNG_ROWBYTES(info_ptr->pixel_depth, width);
463
464
338k
#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
338k
   info_ptr->num_frames = 1;
469
338k
#endif
470
338k
}
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
2.52k
{
477
2.52k
   png_debug1(1, "in %s storage function", "oFFs");
478
479
2.52k
   if (png_ptr == NULL || info_ptr == NULL)
480
0
      return;
481
482
2.52k
   info_ptr->x_offset = offset_x;
483
2.52k
   info_ptr->y_offset = offset_y;
484
2.52k
   info_ptr->offset_unit_type = (png_byte)unit_type;
485
2.52k
   info_ptr->valid |= PNG_INFO_oFFs;
486
2.52k
}
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
9.68k
{
735
9.68k
   png_debug1(1, "in %s storage function", "pHYs");
736
737
9.68k
   if (png_ptr == NULL || info_ptr == NULL)
738
0
      return;
739
740
9.68k
   info_ptr->x_pixels_per_unit = res_x;
741
9.68k
   info_ptr->y_pixels_per_unit = res_y;
742
9.68k
   info_ptr->phys_unit_type = (png_byte)unit_type;
743
9.68k
   info_ptr->valid |= PNG_INFO_pHYs;
744
9.68k
}
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
30.3k
{
751
30.3k
   png_color safe_palette[PNG_MAX_PALETTE_LENGTH];
752
30.3k
   png_uint_32 max_palette_length;
753
754
30.3k
   png_debug1(1, "in %s storage function", "PLTE");
755
756
30.3k
   if (png_ptr == NULL || info_ptr == NULL)
757
0
      return;
758
759
30.3k
   max_palette_length = (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE) ?
760
17.2k
      (1 << info_ptr->bit_depth) : PNG_MAX_PALETTE_LENGTH;
761
762
30.3k
   if (num_palette < 0 || num_palette > (int) max_palette_length)
763
2
   {
764
2
      if (info_ptr->color_type == PNG_COLOR_TYPE_PALETTE)
765
2
         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
2
   }
774
775
30.3k
   if ((num_palette > 0 && palette == NULL) ||
776
30.3k
      (num_palette == 0
777
3.89k
#        ifdef PNG_MNG_FEATURES_SUPPORTED
778
3.89k
            && (png_ptr->mng_features_permitted & PNG_FLAG_MNG_EMPTY_PLTE) == 0
779
30.3k
#        endif
780
30.3k
      ))
781
20
   {
782
20
      png_error(png_ptr, "Invalid palette");
783
20
   }
784
785
   /* Snapshot the caller's palette before freeing, in case it points to
786
    * info_ptr->palette (getter-to-setter aliasing).
787
    */
788
30.3k
   if (num_palette > 0)
789
26.4k
      memcpy(safe_palette, palette, (unsigned int)num_palette *
790
26.4k
          (sizeof (png_color)));
791
792
30.3k
   palette = safe_palette;
793
794
30.3k
   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
30.3k
   png_free(png_ptr, png_ptr->palette);
812
30.3k
   png_ptr->palette = NULL;
813
30.3k
   png_ptr->palette = png_voidcast(png_color *, png_calloc(png_ptr,
814
30.3k
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
815
30.3k
   info_ptr->palette = png_voidcast(png_colorp, png_calloc(png_ptr,
816
30.3k
       PNG_MAX_PALETTE_LENGTH * (sizeof (png_color))));
817
30.3k
   png_ptr->num_palette = info_ptr->num_palette = (png_uint_16)num_palette;
818
819
30.3k
   if (num_palette > 0)
820
26.4k
   {
821
26.4k
      memcpy(info_ptr->palette, palette, (unsigned int)num_palette *
822
26.4k
          (sizeof (png_color)));
823
26.4k
      memcpy(png_ptr->palette, palette, (unsigned int)num_palette *
824
26.4k
          (sizeof (png_color)));
825
26.4k
   }
826
827
30.3k
   info_ptr->free_me |= PNG_FREE_PLTE;
828
30.3k
   info_ptr->valid |= PNG_INFO_PLTE;
829
30.3k
}
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
738
{
836
738
   png_debug1(1, "in %s storage function", "sBIT");
837
838
738
   if (png_ptr == NULL || info_ptr == NULL || sig_bit == NULL)
839
0
      return;
840
841
738
   info_ptr->sig_bit = *sig_bit;
842
738
   info_ptr->valid |= PNG_INFO_sBIT;
843
738
}
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
6.26k
{
850
6.26k
   png_debug1(1, "in %s storage function", "sRGB");
851
852
6.26k
   if (png_ptr == NULL || info_ptr == NULL)
853
0
      return;
854
855
6.26k
   info_ptr->rendering_intent = srgb_intent;
856
6.26k
   info_ptr->valid |= PNG_INFO_sRGB;
857
6.26k
}
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
64
{
892
64
   char *new_iccp_name;
893
64
   png_byte *new_iccp_profile;
894
64
   size_t length;
895
896
64
   png_debug1(1, "in %s storage function", "iCCP");
897
898
64
   if (png_ptr == NULL || info_ptr == NULL || name == NULL || profile == NULL)
899
0
      return;
900
901
64
   if (compression_type != PNG_COMPRESSION_TYPE_BASE)
902
0
      png_app_error(png_ptr, "Invalid iCCP compression method");
903
904
64
   length = strlen(name)+1;
905
64
   new_iccp_name = png_voidcast(char *, png_malloc_warn(png_ptr, length));
906
907
64
   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
64
   memcpy(new_iccp_name, name, length);
915
64
   new_iccp_profile = png_voidcast(png_byte *,
916
64
       png_malloc_warn(png_ptr, proflen));
917
918
64
   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
64
   memcpy(new_iccp_profile, profile, proflen);
928
929
64
   png_free_data(png_ptr, info_ptr, PNG_FREE_ICCP, 0);
930
931
64
   info_ptr->iccp_proflen = proflen;
932
64
   info_ptr->iccp_name = new_iccp_name;
933
64
   info_ptr->iccp_profile = new_iccp_profile;
934
64
   info_ptr->free_me |= PNG_FREE_ICCP;
935
64
   info_ptr->valid |= PNG_INFO_iCCP;
936
64
}
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
59.6k
{
944
59.6k
   int ret;
945
59.6k
   ret = png_set_text_2(png_ptr, info_ptr, text_ptr, num_text);
946
947
59.6k
   if (ret != 0)
948
0
      png_error(png_ptr, "Insufficient memory to store text");
949
59.6k
}
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
322k
{
955
322k
   int i;
956
322k
   png_textp old_text = NULL;
957
958
322k
   png_debug1(1, "in text storage function, chunk typeid = 0x%lx",
959
322k
      png_ptr == NULL ? 0xabadca11UL : (unsigned long)png_ptr->chunk_name);
960
961
322k
   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
322k
   if (num_text > info_ptr->max_text - info_ptr->num_text)
970
71.3k
   {
971
71.3k
      int old_num_text = info_ptr->num_text;
972
71.3k
      int max_text;
973
71.3k
      png_text *new_text = NULL;
974
975
      /* Calculate an appropriate max_text, checking for overflow. */
976
71.3k
      max_text = old_num_text;
977
71.3k
      if (num_text <= INT_MAX - max_text)
978
71.3k
      {
979
71.3k
         max_text += num_text;
980
981
         /* Round up to a multiple of 8 */
982
71.3k
         if (max_text < INT_MAX-8)
983
71.3k
            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
71.3k
         new_text = png_voidcast(png_text *,png_realloc_array(png_ptr,
992
71.3k
             info_ptr->text, old_num_text, max_text-old_num_text,
993
71.3k
             sizeof *new_text));
994
71.3k
      }
995
996
71.3k
      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
71.3k
      old_text = info_ptr->text;
1008
1009
71.3k
      info_ptr->text = new_text;
1010
71.3k
      info_ptr->free_me |= PNG_FREE_TEXT;
1011
71.3k
      info_ptr->max_text = max_text;
1012
      /* num_text is adjusted below as the entries are copied in */
1013
1014
71.3k
      png_debug1(3, "allocated %d entries for info_ptr->text", max_text);
1015
71.3k
   }
1016
1017
644k
   for (i = 0; i < num_text; i++)
1018
322k
   {
1019
322k
      size_t text_length, key_len;
1020
322k
      size_t lang_len, lang_key_len;
1021
322k
      png_text *textp = &(info_ptr->text[info_ptr->num_text]);
1022
1023
322k
      if (text_ptr[i].key == NULL)
1024
0
          continue;
1025
1026
322k
      if (text_ptr[i].compression < PNG_TEXT_COMPRESSION_NONE ||
1027
322k
          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
322k
      key_len = strlen(text_ptr[i].key);
1035
1036
322k
      if (text_ptr[i].compression <= 0)
1037
322k
      {
1038
322k
         lang_len = 0;
1039
322k
         lang_key_len = 0;
1040
322k
      }
1041
1042
0
      else
1043
0
#  ifdef PNG_iTXt_SUPPORTED
1044
0
      {
1045
         /* Set iTXt data */
1046
1047
0
         if (text_ptr[i].lang != NULL)
1048
0
            lang_len = strlen(text_ptr[i].lang);
1049
1050
0
         else
1051
0
            lang_len = 0;
1052
1053
0
         if (text_ptr[i].lang_key != NULL)
1054
0
            lang_key_len = strlen(text_ptr[i].lang_key);
1055
1056
0
         else
1057
0
            lang_key_len = 0;
1058
0
      }
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
322k
      if (text_ptr[i].text == NULL || text_ptr[i].text[0] == '\0')
1068
105k
      {
1069
105k
         text_length = 0;
1070
105k
#  ifdef PNG_iTXt_SUPPORTED
1071
105k
         if (text_ptr[i].compression > 0)
1072
0
            textp->compression = PNG_ITXT_COMPRESSION_NONE;
1073
1074
105k
         else
1075
105k
#  endif
1076
105k
            textp->compression = PNG_TEXT_COMPRESSION_NONE;
1077
105k
      }
1078
1079
216k
      else
1080
216k
      {
1081
216k
         text_length = strlen(text_ptr[i].text);
1082
216k
         textp->compression = text_ptr[i].compression;
1083
216k
      }
1084
1085
322k
      textp->key = png_voidcast(char *,png_malloc_base(png_ptr,
1086
322k
          key_len + text_length + lang_len + lang_key_len + 4));
1087
1088
322k
      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
322k
      png_debug2(2, "Allocated %lu bytes at %p in png_set_text",
1098
322k
          (unsigned long)(png_uint_32)
1099
322k
          (key_len + lang_len + lang_key_len + text_length + 4),
1100
322k
          textp->key);
1101
1102
322k
      memcpy(textp->key, text_ptr[i].key, key_len);
1103
322k
      *(textp->key + key_len) = '\0';
1104
1105
322k
      if (text_ptr[i].compression > 0)
1106
0
      {
1107
0
         textp->lang = textp->key + key_len + 1;
1108
0
         memcpy(textp->lang, text_ptr[i].lang, lang_len);
1109
0
         *(textp->lang + lang_len) = '\0';
1110
0
         textp->lang_key = textp->lang + lang_len + 1;
1111
0
         memcpy(textp->lang_key, text_ptr[i].lang_key, lang_key_len);
1112
0
         *(textp->lang_key + lang_key_len) = '\0';
1113
0
         textp->text = textp->lang_key + lang_key_len + 1;
1114
0
      }
1115
1116
322k
      else
1117
322k
      {
1118
322k
         textp->lang=NULL;
1119
322k
         textp->lang_key=NULL;
1120
322k
         textp->text = textp->key + key_len + 1;
1121
322k
      }
1122
1123
322k
      if (text_length != 0)
1124
216k
         memcpy(textp->text, text_ptr[i].text, text_length);
1125
1126
322k
      *(textp->text + text_length) = '\0';
1127
1128
322k
#  ifdef PNG_iTXt_SUPPORTED
1129
322k
      if (textp->compression > 0)
1130
0
      {
1131
0
         textp->text_length = 0;
1132
0
         textp->itxt_length = text_length;
1133
0
      }
1134
1135
322k
      else
1136
322k
#  endif
1137
322k
      {
1138
322k
         textp->text_length = text_length;
1139
322k
         textp->itxt_length = 0;
1140
322k
      }
1141
1142
322k
      info_ptr->num_text++;
1143
322k
      png_debug1(3, "transferred text chunk %d", info_ptr->num_text);
1144
322k
   }
1145
1146
322k
   png_free(png_ptr, old_text);
1147
1148
322k
   return 0;
1149
322k
}
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
0
{
1157
0
   png_debug1(1, "in %s storage function", "tIME");
1158
1159
0
   if (png_ptr == NULL || info_ptr == NULL || mod_time == NULL ||
1160
0
       (png_ptr->mode & PNG_WROTE_tIME) != 0)
1161
0
      return;
1162
1163
0
   if (mod_time->month == 0   || mod_time->month > 12  ||
1164
0
       mod_time->day   == 0   || mod_time->day   > 31  ||
1165
0
       mod_time->hour  > 23   || mod_time->minute > 59 ||
1166
0
       mod_time->second > 60)
1167
0
   {
1168
0
      png_warning(png_ptr, "Ignoring invalid time value");
1169
1170
0
      return;
1171
0
   }
1172
1173
0
   info_ptr->mod_time = *mod_time;
1174
0
   info_ptr->valid |= PNG_INFO_tIME;
1175
0
}
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
33.3k
{
1183
33.3k
   png_debug1(1, "in %s storage function", "tRNS");
1184
1185
33.3k
   if (png_ptr == NULL || info_ptr == NULL)
1186
1187
0
      return;
1188
1189
33.3k
   if (trans_alpha != NULL)
1190
33.3k
   {
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
33.3k
       png_byte safe_trans[PNG_MAX_PALETTE_LENGTH];
1195
1196
33.3k
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1197
33.3k
          memcpy(safe_trans, trans_alpha, (size_t)num_trans);
1198
1199
33.3k
       trans_alpha = safe_trans;
1200
1201
33.3k
       png_free_data(png_ptr, info_ptr, PNG_FREE_TRNS, 0);
1202
1203
33.3k
       if (num_trans > 0 && num_trans <= PNG_MAX_PALETTE_LENGTH)
1204
33.3k
       {
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
33.3k
          info_ptr->trans_alpha = png_voidcast(png_byte *,
1210
33.3k
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1211
33.3k
          memset(info_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1212
33.3k
          memcpy(info_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1213
33.3k
          info_ptr->free_me |= PNG_FREE_TRNS;
1214
33.3k
          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
33.3k
          png_free(png_ptr, png_ptr->trans_alpha);
1225
33.3k
          png_ptr->trans_alpha = NULL;
1226
33.3k
          png_ptr->trans_alpha = png_voidcast(png_bytep,
1227
33.3k
              png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH));
1228
33.3k
          memset(png_ptr->trans_alpha, 0xff, PNG_MAX_PALETTE_LENGTH);
1229
33.3k
          memcpy(png_ptr->trans_alpha, trans_alpha, (size_t)num_trans);
1230
33.3k
       }
1231
0
       else
1232
0
       {
1233
0
          png_free(png_ptr, png_ptr->trans_alpha);
1234
0
          png_ptr->trans_alpha = NULL;
1235
0
       }
1236
33.3k
   }
1237
1238
33.3k
   if (trans_color != NULL)
1239
32.8k
   {
1240
32.8k
#ifdef PNG_WARNINGS_SUPPORTED
1241
32.8k
      if (info_ptr->bit_depth < 16)
1242
32.3k
      {
1243
32.3k
         int sample_max = (1 << info_ptr->bit_depth) - 1;
1244
1245
32.3k
         if ((info_ptr->color_type == PNG_COLOR_TYPE_GRAY &&
1246
3.63k
             trans_color->gray > sample_max) ||
1247
29.0k
             (info_ptr->color_type == PNG_COLOR_TYPE_RGB &&
1248
22.2k
             (trans_color->red > sample_max ||
1249
21.4k
             trans_color->green > sample_max ||
1250
2.76k
             trans_color->blue > sample_max)))
1251
25.3k
            png_warning(png_ptr,
1252
25.3k
                "tRNS chunk has out-of-range samples for bit_depth");
1253
32.3k
      }
1254
32.8k
#endif
1255
1256
32.8k
      info_ptr->trans_color = *trans_color;
1257
1258
32.8k
      if (num_trans == 0)
1259
0
         num_trans = 1;
1260
32.8k
   }
1261
1262
33.3k
   info_ptr->num_trans = (png_uint_16)num_trans;
1263
1264
33.3k
   if (num_trans != 0)
1265
33.3k
   {
1266
33.3k
      info_ptr->free_me |= PNG_FREE_TRNS;
1267
33.3k
      info_ptr->valid |= PNG_INFO_tRNS;
1268
33.3k
   }
1269
33.3k
}
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
275k
{
1523
275k
   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
275k
   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
275k
   if (location == 0)
1543
6.83k
      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
296k
   while (location != (location & -location))
1549
27.6k
      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
268k
   return (png_byte)location;
1555
275k
}
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
275k
{
1561
275k
   png_unknown_chunk *np;
1562
275k
   png_unknown_chunk *old_unknowns;
1563
1564
275k
   if (png_ptr == NULL || info_ptr == NULL || num_unknowns <= 0 ||
1565
275k
       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
275k
   np = png_voidcast(png_unknown_chunk *, png_realloc_array(png_ptr,
1599
275k
       info_ptr->unknown_chunks, info_ptr->unknown_chunks_num, num_unknowns,
1600
275k
       sizeof *np));
1601
1602
275k
   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
275k
   old_unknowns = info_ptr->unknown_chunks;
1613
1614
275k
   info_ptr->unknown_chunks = np; /* safe because it is initialized */
1615
275k
   info_ptr->free_me |= PNG_FREE_UNKN;
1616
1617
275k
   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
551k
   for (; num_unknowns > 0; --num_unknowns, ++unknowns)
1623
275k
   {
1624
275k
      memcpy(np->name, unknowns->name, (sizeof np->name));
1625
275k
      np->name[(sizeof np->name)-1] = '\0';
1626
275k
      np->location = check_location(png_ptr, unknowns->location);
1627
1628
275k
      if (unknowns->size == 0)
1629
170k
      {
1630
170k
         np->data = NULL;
1631
170k
         np->size = 0;
1632
170k
      }
1633
1634
105k
      else
1635
105k
      {
1636
105k
         np->data = png_voidcast(png_byte *,
1637
105k
             png_malloc_base(png_ptr, unknowns->size));
1638
1639
105k
         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
105k
         memcpy(np->data, unknowns->data, unknowns->size);
1648
105k
         np->size = unknowns->size;
1649
105k
      }
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
275k
      ++np;
1656
275k
      ++(info_ptr->unknown_chunks_num);
1657
275k
   }
1658
1659
275k
   png_free(png_ptr, old_unknowns);
1660
275k
}
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
146k
{
1695
146k
   png_debug(1, "in png_permit_mng_features");
1696
1697
146k
   if (png_ptr == NULL)
1698
0
      return 0;
1699
1700
146k
   png_ptr->mng_features_permitted = mng_features & PNG_ALL_MNG_FEATURES;
1701
1702
146k
   return png_ptr->mng_features_permitted;
1703
146k
}
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
3.77M
{
1710
3.77M
   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
22.6M
   for (i=0; i<count; ++i, list += 5)
1716
18.8M
   {
1717
18.8M
      if (memcmp(list, add, 4) == 0)
1718
0
      {
1719
0
         list[4] = (png_byte)keep;
1720
1721
0
         return count;
1722
0
      }
1723
18.8M
   }
1724
1725
3.77M
   if (keep != PNG_HANDLE_CHUNK_AS_DEFAULT)
1726
3.77M
   {
1727
3.77M
      ++count;
1728
3.77M
      memcpy(list, add, 4);
1729
3.77M
      list[4] = (png_byte)keep;
1730
3.77M
   }
1731
1732
3.77M
   return count;
1733
3.77M
}
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
1.03M
{
1739
1.03M
   png_byte *new_list;
1740
1.03M
   unsigned int num_chunks, old_num_chunks;
1741
1742
1.03M
   if (png_ptr == NULL)
1743
0
      return;
1744
1745
1.03M
   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
1.03M
   if (num_chunks_in <= 0)
1753
343k
   {
1754
343k
      png_ptr->unknown_default = keep;
1755
1756
      /* '0' means just set the flags, so stop here */
1757
343k
      if (num_chunks_in == 0)
1758
343k
        return;
1759
343k
   }
1760
1761
687k
   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
687k
   else /* num_chunks_in > 0 */
1798
687k
   {
1799
687k
      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
687k
      num_chunks = (unsigned int)num_chunks_in;
1810
687k
   }
1811
1812
687k
   old_num_chunks = png_ptr->num_chunk_list;
1813
687k
   if (png_ptr->chunk_list == NULL)
1814
343k
      old_num_chunks = 0;
1815
1816
   /* Since num_chunks is always restricted to UINT_MAX/5 this can't overflow.
1817
    */
1818
687k
   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
687k
   if (keep != 0)
1830
687k
   {
1831
687k
      new_list = png_voidcast(png_byte *, png_malloc(png_ptr,
1832
687k
          5 * (num_chunks + old_num_chunks)));
1833
1834
687k
      if (old_num_chunks > 0)
1835
343k
         memcpy(new_list, png_ptr->chunk_list, 5*old_num_chunks);
1836
687k
   }
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
687k
   if (new_list != NULL)
1850
687k
   {
1851
687k
      const png_byte *inlist;
1852
687k
      png_byte *outlist;
1853
687k
      unsigned int i;
1854
1855
4.46M
      for (i=0; i<num_chunks; ++i)
1856
3.77M
      {
1857
3.77M
         old_num_chunks = add_one_chunk(new_list, old_num_chunks,
1858
3.77M
             chunk_list+5*i, keep);
1859
3.77M
      }
1860
1861
      /* Now remove any spurious 'default' entries. */
1862
687k
      num_chunks = 0;
1863
4.81M
      for (i=0, inlist=outlist=new_list; i<old_num_chunks; ++i, inlist += 5)
1864
4.12M
      {
1865
4.12M
         if (inlist[4])
1866
4.12M
         {
1867
4.12M
            if (outlist != inlist)
1868
0
               memcpy(outlist, inlist, 5);
1869
4.12M
            outlist += 5;
1870
4.12M
            ++num_chunks;
1871
4.12M
         }
1872
4.12M
      }
1873
1874
      /* This means the application has removed all the specialized handling. */
1875
687k
      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
687k
   }
1883
1884
0
   else
1885
0
      num_chunks = 0;
1886
1887
687k
   png_ptr->num_chunk_list = num_chunks;
1888
1889
687k
   if (png_ptr->chunk_list != new_list)
1890
687k
   {
1891
687k
      if (png_ptr->chunk_list != NULL)
1892
343k
         png_free(png_ptr, png_ptr->chunk_list);
1893
1894
687k
      png_ptr->chunk_list = new_list;
1895
687k
   }
1896
687k
}
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
343k
{
1904
343k
   png_debug(1, "in png_set_read_user_chunk_fn");
1905
1906
343k
   if (png_ptr == NULL)
1907
0
      return;
1908
1909
343k
   png_ptr->read_user_chunk_fn = read_user_chunk_fn;
1910
343k
   png_ptr->user_chunk_ptr = user_chunk_ptr;
1911
343k
}
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
30.4k
{
1938
30.4k
   png_debug(1, "in png_set_compression_buffer_size");
1939
1940
30.4k
   if (png_ptr == NULL)
1941
0
      return;
1942
1943
30.4k
   if (size == 0 || size > PNG_UINT_31_MAX)
1944
0
      png_error(png_ptr, "invalid compression buffer size");
1945
1946
30.4k
#  ifdef PNG_SEQUENTIAL_READ_SUPPORTED
1947
30.4k
   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
30.4k
#  endif
1953
1954
30.4k
#  ifdef PNG_WRITE_SUPPORTED
1955
30.4k
   if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
1956
30.4k
   {
1957
30.4k
      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
30.4k
#ifndef __COVERITY__
1966
      /* Some compilers complain that this is always false.  However, it
1967
       * can be true when integer overflow happens.
1968
       */
1969
30.4k
      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
30.4k
#endif
1976
1977
30.4k
      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
30.4k
      if (png_ptr->zbuffer_size != size)
1989
30.4k
      {
1990
30.4k
         png_free_buffer_list(png_ptr, &png_ptr->zbuffer_list);
1991
30.4k
         png_ptr->zbuffer_size = (uInt)size;
1992
30.4k
      }
1993
30.4k
   }
1994
30.4k
#  endif
1995
30.4k
}
1996
1997
void
1998
png_set_invalid(const png_struct *png_ptr, png_info *info_ptr, int mask)
1999
0
{
2000
0
   if (png_ptr != NULL && info_ptr != NULL)
2001
0
      info_ptr->valid &= (unsigned int)(~mask);
2002
0
}
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
343k
{
2011
343k
   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
343k
   if (png_ptr == NULL)
2018
0
      return;
2019
2020
343k
   png_ptr->user_width_max = user_width_max;
2021
343k
   png_ptr->user_height_max = user_height_max;
2022
343k
}
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
0
{
2028
0
   png_debug(1, "in png_set_chunk_cache_max");
2029
2030
0
   if (png_ptr != NULL)
2031
0
      png_ptr->user_chunk_cache_max = user_chunk_cache_max;
2032
0
}
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
374k
{
2067
374k
   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
374k
   if (allowed != 0)
2076
374k
      png_ptr->flags |= PNG_FLAG_BENIGN_ERRORS_WARN |
2077
374k
         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
374k
}
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
361k
{
2097
361k
   png_debug(1, "in png_set_check_for_invalid_index");
2098
2099
361k
   if (allowed > 0)
2100
0
      png_ptr->num_palette_max = 0;
2101
2102
361k
   else
2103
361k
      png_ptr->num_palette_max = -1;
2104
361k
}
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
59.4k
{
2122
59.4k
#ifdef PNG_WARNINGS_SUPPORTED
2123
59.4k
   const char *orig_key = key;
2124
59.4k
#endif
2125
59.4k
   png_uint_32 key_len = 0;
2126
59.4k
   int bad_character = 0;
2127
59.4k
   int space = 1;
2128
2129
59.4k
   png_debug(1, "in png_check_keyword");
2130
2131
59.4k
   if (key == NULL)
2132
0
   {
2133
0
      *new_key = 0;
2134
0
      return 0;
2135
0
   }
2136
2137
1.63M
   while (*key && key_len < 79)
2138
1.57M
   {
2139
1.57M
      png_byte ch = (png_byte)*key++;
2140
2141
1.57M
      if ((ch > 32 && ch <= 126) || (ch >= 161 /*&& ch <= 255*/))
2142
1.12M
      {
2143
1.12M
         *new_key++ = ch; ++key_len; space = 0;
2144
1.12M
      }
2145
2146
451k
      else if (space == 0)
2147
281k
      {
2148
         /* A space or an invalid character when one wasn't seen immediately
2149
          * before; output just a space.
2150
          */
2151
281k
         *new_key++ = 32; ++key_len; space = 1;
2152
2153
         /* If the character was not a space then it is invalid. */
2154
281k
         if (ch != 32)
2155
177k
            bad_character = ch;
2156
281k
      }
2157
2158
170k
      else if (bad_character == 0)
2159
20.8k
         bad_character = ch; /* just skip it, record the first error */
2160
1.57M
   }
2161
2162
59.4k
   if (key_len > 0 && space != 0) /* trailing space */
2163
28.2k
   {
2164
28.2k
      --key_len; --new_key;
2165
28.2k
      if (bad_character == 0)
2166
581
         bad_character = 32;
2167
28.2k
   }
2168
2169
   /* Terminate the keyword */
2170
59.4k
   *new_key = 0;
2171
2172
59.4k
   if (key_len == 0)
2173
75
      return 0;
2174
2175
59.3k
#ifdef PNG_WARNINGS_SUPPORTED
2176
   /* Try to only output one warning per keyword: */
2177
59.3k
   if (*key != 0) /* keyword too long */
2178
1.89k
      png_warning(png_ptr, "keyword truncated");
2179
2180
57.4k
   else if (bad_character != 0)
2181
49.9k
   {
2182
49.9k
      PNG_WARNING_PARAMETERS(p)
2183
2184
49.9k
      png_warning_parameter(p, 1, orig_key);
2185
49.9k
      png_warning_parameter_signed(p, 2, PNG_NUMBER_FORMAT_02x, bad_character);
2186
2187
49.9k
      png_formatted_warning(png_ptr, p, "keyword \"@1\": bad character '0x@2'");
2188
49.9k
   }
2189
#else /* !WARNINGS */
2190
   PNG_UNUSED(png_ptr)
2191
#endif /* !WARNINGS */
2192
2193
59.3k
   return key_len;
2194
59.4k
}
2195
#endif /* TEXT || pCAL || iCCP || sPLT */
2196
#endif /* READ || WRITE */