Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/libpng/pngerror.c
9833 views
1
/* pngerror.c - stub functions for i/o and memory allocation
2
*
3
* Copyright (c) 2018-2025 Cosmin Truta
4
* Copyright (c) 1998-2002,2004,2006-2017 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
* This file provides a location for all error handling. Users who
13
* need special error handling are expected to write replacement functions
14
* and use png_set_error_fn() to use those functions. See the instructions
15
* at each function.
16
*/
17
18
#include "pngpriv.h"
19
20
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
21
22
static PNG_FUNCTION(void /* PRIVATE */,
23
png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
24
PNG_NORETURN);
25
26
#ifdef PNG_WARNINGS_SUPPORTED
27
static void /* PRIVATE */
28
png_default_warning(png_const_structrp png_ptr,
29
png_const_charp warning_message);
30
#endif /* WARNINGS */
31
32
/* This function is called whenever there is a fatal error. This function
33
* should not be changed. If there is a need to handle errors differently,
34
* you should supply a replacement error function and use png_set_error_fn()
35
* to replace the error function at run-time.
36
*/
37
#ifdef PNG_ERROR_TEXT_SUPPORTED
38
PNG_FUNCTION(void,PNGAPI
39
png_error,(png_const_structrp png_ptr, png_const_charp error_message),
40
PNG_NORETURN)
41
{
42
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
43
char msg[16];
44
if (png_ptr != NULL)
45
{
46
if ((png_ptr->flags &
47
(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
48
{
49
if (*error_message == PNG_LITERAL_SHARP)
50
{
51
/* Strip "#nnnn " from beginning of error message. */
52
int offset;
53
for (offset = 1; offset<15; offset++)
54
if (error_message[offset] == ' ')
55
break;
56
57
if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
58
{
59
int i;
60
for (i = 0; i < offset - 1; i++)
61
msg[i] = error_message[i + 1];
62
msg[i - 1] = '\0';
63
error_message = msg;
64
}
65
66
else
67
error_message += offset;
68
}
69
70
else
71
{
72
if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
73
{
74
msg[0] = '0';
75
msg[1] = '\0';
76
error_message = msg;
77
}
78
}
79
}
80
}
81
#endif
82
if (png_ptr != NULL && png_ptr->error_fn != NULL)
83
(*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
84
error_message);
85
86
/* If the custom handler doesn't exist, or if it returns,
87
use the default handler, which will not return. */
88
png_default_error(png_ptr, error_message);
89
}
90
#else
91
PNG_FUNCTION(void,PNGAPI
92
png_err,(png_const_structrp png_ptr),PNG_NORETURN)
93
{
94
/* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
95
* erroneously as '\0', instead of the empty string "". This was
96
* apparently an error, introduced in libpng-1.2.20, and png_default_error
97
* will crash in this case.
98
*/
99
if (png_ptr != NULL && png_ptr->error_fn != NULL)
100
(*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), "");
101
102
/* If the custom handler doesn't exist, or if it returns,
103
use the default handler, which will not return. */
104
png_default_error(png_ptr, "");
105
}
106
#endif /* ERROR_TEXT */
107
108
/* Utility to safely appends strings to a buffer. This never errors out so
109
* error checking is not required in the caller.
110
*/
111
size_t
112
png_safecat(png_charp buffer, size_t bufsize, size_t pos,
113
png_const_charp string)
114
{
115
if (buffer != NULL && pos < bufsize)
116
{
117
if (string != NULL)
118
while (*string != '\0' && pos < bufsize-1)
119
buffer[pos++] = *string++;
120
121
buffer[pos] = '\0';
122
}
123
124
return pos;
125
}
126
127
#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
128
/* Utility to dump an unsigned value into a buffer, given a start pointer and
129
* and end pointer (which should point just *beyond* the end of the buffer!)
130
* Returns the pointer to the start of the formatted string.
131
*/
132
png_charp
133
png_format_number(png_const_charp start, png_charp end, int format,
134
png_alloc_size_t number)
135
{
136
int count = 0; /* number of digits output */
137
int mincount = 1; /* minimum number required */
138
int output = 0; /* digit output (for the fixed point format) */
139
140
*--end = '\0';
141
142
/* This is written so that the loop always runs at least once, even with
143
* number zero.
144
*/
145
while (end > start && (number != 0 || count < mincount))
146
{
147
148
static const char digits[] = "0123456789ABCDEF";
149
150
switch (format)
151
{
152
case PNG_NUMBER_FORMAT_fixed:
153
/* Needs five digits (the fraction) */
154
mincount = 5;
155
if (output != 0 || number % 10 != 0)
156
{
157
*--end = digits[number % 10];
158
output = 1;
159
}
160
number /= 10;
161
break;
162
163
case PNG_NUMBER_FORMAT_02u:
164
/* Expects at least 2 digits. */
165
mincount = 2;
166
/* FALLTHROUGH */
167
168
case PNG_NUMBER_FORMAT_u:
169
*--end = digits[number % 10];
170
number /= 10;
171
break;
172
173
case PNG_NUMBER_FORMAT_02x:
174
/* This format expects at least two digits */
175
mincount = 2;
176
/* FALLTHROUGH */
177
178
case PNG_NUMBER_FORMAT_x:
179
*--end = digits[number & 0xf];
180
number >>= 4;
181
break;
182
183
default: /* an error */
184
number = 0;
185
break;
186
}
187
188
/* Keep track of the number of digits added */
189
++count;
190
191
/* Float a fixed number here: */
192
if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start))
193
{
194
/* End of the fraction, but maybe nothing was output? In that case
195
* drop the decimal point. If the number is a true zero handle that
196
* here.
197
*/
198
if (output != 0)
199
*--end = '.';
200
else if (number == 0) /* and !output */
201
*--end = '0';
202
}
203
}
204
205
return end;
206
}
207
#endif
208
209
#ifdef PNG_WARNINGS_SUPPORTED
210
/* This function is called whenever there is a non-fatal error. This function
211
* should not be changed. If there is a need to handle warnings differently,
212
* you should supply a replacement warning function and use
213
* png_set_error_fn() to replace the warning function at run-time.
214
*/
215
void PNGAPI
216
png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
217
{
218
int offset = 0;
219
if (png_ptr != NULL)
220
{
221
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
222
if ((png_ptr->flags &
223
(PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
224
#endif
225
{
226
if (*warning_message == PNG_LITERAL_SHARP)
227
{
228
for (offset = 1; offset < 15; offset++)
229
if (warning_message[offset] == ' ')
230
break;
231
}
232
}
233
}
234
if (png_ptr != NULL && png_ptr->warning_fn != NULL)
235
(*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
236
warning_message + offset);
237
else
238
png_default_warning(png_ptr, warning_message + offset);
239
}
240
241
/* These functions support 'formatted' warning messages with up to
242
* PNG_WARNING_PARAMETER_COUNT parameters. In the format string the parameter
243
* is introduced by @<number>, where 'number' starts at 1. This follows the
244
* standard established by X/Open for internationalizable error messages.
245
*/
246
void
247
png_warning_parameter(png_warning_parameters p, int number,
248
png_const_charp string)
249
{
250
if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)
251
(void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);
252
}
253
254
void
255
png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
256
png_alloc_size_t value)
257
{
258
char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
259
png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
260
}
261
262
void
263
png_warning_parameter_signed(png_warning_parameters p, int number, int format,
264
png_int_32 value)
265
{
266
png_alloc_size_t u;
267
png_charp str;
268
char buffer[PNG_NUMBER_BUFFER_SIZE] = {0};
269
270
/* Avoid overflow by doing the negate in a png_alloc_size_t: */
271
u = (png_alloc_size_t)value;
272
if (value < 0)
273
u = ~u + 1;
274
275
str = PNG_FORMAT_NUMBER(buffer, format, u);
276
277
if (value < 0 && str > buffer)
278
*--str = '-';
279
280
png_warning_parameter(p, number, str);
281
}
282
283
void
284
png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,
285
png_const_charp message)
286
{
287
/* The internal buffer is just 192 bytes - enough for all our messages,
288
* overflow doesn't happen because this code checks! If someone figures
289
* out how to send us a message longer than 192 bytes, all that will
290
* happen is that the message will be truncated appropriately.
291
*/
292
size_t i = 0; /* Index in the msg[] buffer: */
293
char msg[192];
294
295
/* Each iteration through the following loop writes at most one character
296
* to msg[i++] then returns here to validate that there is still space for
297
* the trailing '\0'. It may (in the case of a parameter) read more than
298
* one character from message[]; it must check for '\0' and continue to the
299
* test if it finds the end of string.
300
*/
301
while (i<(sizeof msg)-1 && *message != '\0')
302
{
303
/* '@' at end of string is now just printed (previously it was skipped);
304
* it is an error in the calling code to terminate the string with @.
305
*/
306
if (p != NULL && *message == '@' && message[1] != '\0')
307
{
308
int parameter_char = *++message; /* Consume the '@' */
309
static const char valid_parameters[] = "123456789";
310
int parameter = 0;
311
312
/* Search for the parameter digit, the index in the string is the
313
* parameter to use.
314
*/
315
while (valid_parameters[parameter] != parameter_char &&
316
valid_parameters[parameter] != '\0')
317
++parameter;
318
319
/* If the parameter digit is out of range it will just get printed. */
320
if (parameter < PNG_WARNING_PARAMETER_COUNT)
321
{
322
/* Append this parameter */
323
png_const_charp parm = p[parameter];
324
png_const_charp pend = p[parameter] + (sizeof p[parameter]);
325
326
/* No need to copy the trailing '\0' here, but there is no guarantee
327
* that parm[] has been initialized, so there is no guarantee of a
328
* trailing '\0':
329
*/
330
while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
331
msg[i++] = *parm++;
332
333
/* Consume the parameter digit too: */
334
++message;
335
continue;
336
}
337
338
/* else not a parameter and there is a character after the @ sign; just
339
* copy that. This is known not to be '\0' because of the test above.
340
*/
341
}
342
343
/* At this point *message can't be '\0', even in the bad parameter case
344
* above where there is a lone '@' at the end of the message string.
345
*/
346
msg[i++] = *message++;
347
}
348
349
/* i is always less than (sizeof msg), so: */
350
msg[i] = '\0';
351
352
/* And this is the formatted message. It may be larger than
353
* PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these
354
* are not (currently) formatted.
355
*/
356
png_warning(png_ptr, msg);
357
}
358
#endif /* WARNINGS */
359
360
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
361
void PNGAPI
362
png_benign_error(png_const_structrp png_ptr, png_const_charp error_message)
363
{
364
if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
365
{
366
# ifdef PNG_READ_SUPPORTED
367
if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
368
png_ptr->chunk_name != 0)
369
png_chunk_warning(png_ptr, error_message);
370
else
371
# endif
372
png_warning(png_ptr, error_message);
373
}
374
375
else
376
{
377
# ifdef PNG_READ_SUPPORTED
378
if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
379
png_ptr->chunk_name != 0)
380
png_chunk_error(png_ptr, error_message);
381
else
382
# endif
383
png_error(png_ptr, error_message);
384
}
385
386
# ifndef PNG_ERROR_TEXT_SUPPORTED
387
PNG_UNUSED(error_message)
388
# endif
389
}
390
391
void /* PRIVATE */
392
png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)
393
{
394
if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0)
395
png_warning(png_ptr, error_message);
396
else
397
png_error(png_ptr, error_message);
398
399
# ifndef PNG_ERROR_TEXT_SUPPORTED
400
PNG_UNUSED(error_message)
401
# endif
402
}
403
404
void /* PRIVATE */
405
png_app_error(png_const_structrp png_ptr, png_const_charp error_message)
406
{
407
if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0)
408
png_warning(png_ptr, error_message);
409
else
410
png_error(png_ptr, error_message);
411
412
# ifndef PNG_ERROR_TEXT_SUPPORTED
413
PNG_UNUSED(error_message)
414
# endif
415
}
416
#endif /* BENIGN_ERRORS */
417
418
#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */
419
#if defined(PNG_WARNINGS_SUPPORTED) || \
420
(defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED))
421
/* These utilities are used internally to build an error message that relates
422
* to the current chunk. The chunk name comes from png_ptr->chunk_name,
423
* which is used to prefix the message. The message is limited in length
424
* to 63 bytes. The name characters are output as hex digits wrapped in []
425
* if the character is invalid.
426
*/
427
#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
428
static const char png_digit[16] = {
429
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
430
'A', 'B', 'C', 'D', 'E', 'F'
431
};
432
433
static void /* PRIVATE */
434
png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp
435
error_message)
436
{
437
png_uint_32 chunk_name = png_ptr->chunk_name;
438
int iout = 0, ishift = 24;
439
440
while (ishift >= 0)
441
{
442
int c = (int)(chunk_name >> ishift) & 0xff;
443
444
ishift -= 8;
445
if (isnonalpha(c) != 0)
446
{
447
buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET;
448
buffer[iout++] = png_digit[(c & 0xf0) >> 4];
449
buffer[iout++] = png_digit[c & 0x0f];
450
buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET;
451
}
452
453
else
454
{
455
buffer[iout++] = (char)c;
456
}
457
}
458
459
if (error_message == NULL)
460
buffer[iout] = '\0';
461
462
else
463
{
464
int iin = 0;
465
466
buffer[iout++] = ':';
467
buffer[iout++] = ' ';
468
469
while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0')
470
buffer[iout++] = error_message[iin++];
471
472
/* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */
473
buffer[iout] = '\0';
474
}
475
}
476
#endif /* WARNINGS || ERROR_TEXT */
477
478
#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
479
PNG_FUNCTION(void,PNGAPI
480
png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),
481
PNG_NORETURN)
482
{
483
char msg[18+PNG_MAX_ERROR_TEXT];
484
if (png_ptr == NULL)
485
png_error(png_ptr, error_message);
486
487
else
488
{
489
png_format_buffer(png_ptr, msg, error_message);
490
png_error(png_ptr, msg);
491
}
492
}
493
#endif /* READ && ERROR_TEXT */
494
495
#ifdef PNG_WARNINGS_SUPPORTED
496
void PNGAPI
497
png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)
498
{
499
char msg[18+PNG_MAX_ERROR_TEXT];
500
if (png_ptr == NULL)
501
png_warning(png_ptr, warning_message);
502
503
else
504
{
505
png_format_buffer(png_ptr, msg, warning_message);
506
png_warning(png_ptr, msg);
507
}
508
}
509
#endif /* WARNINGS */
510
511
#ifdef PNG_READ_SUPPORTED
512
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
513
void PNGAPI
514
png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
515
error_message)
516
{
517
if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
518
png_chunk_warning(png_ptr, error_message);
519
520
else
521
png_chunk_error(png_ptr, error_message);
522
523
# ifndef PNG_ERROR_TEXT_SUPPORTED
524
PNG_UNUSED(error_message)
525
# endif
526
}
527
#endif
528
#endif /* READ */
529
530
void /* PRIVATE */
531
png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
532
{
533
# ifndef PNG_WARNINGS_SUPPORTED
534
PNG_UNUSED(message)
535
# endif
536
537
/* This is always supported, but for just read or just write it
538
* unconditionally does the right thing.
539
*/
540
# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
541
if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
542
# endif
543
544
# ifdef PNG_READ_SUPPORTED
545
{
546
if (error < PNG_CHUNK_ERROR)
547
png_chunk_warning(png_ptr, message);
548
549
else
550
png_chunk_benign_error(png_ptr, message);
551
}
552
# endif
553
554
# if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
555
else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
556
# endif
557
558
# ifdef PNG_WRITE_SUPPORTED
559
{
560
if (error < PNG_CHUNK_WRITE_ERROR)
561
png_app_warning(png_ptr, message);
562
563
else
564
png_app_error(png_ptr, message);
565
}
566
# endif
567
}
568
569
#ifdef PNG_ERROR_TEXT_SUPPORTED
570
#ifdef PNG_FLOATING_POINT_SUPPORTED
571
PNG_FUNCTION(void,
572
png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
573
{
574
# define fixed_message "fixed point overflow in "
575
# define fixed_message_ln ((sizeof fixed_message)-1)
576
unsigned int iin;
577
char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];
578
memcpy(msg, fixed_message, fixed_message_ln);
579
iin = 0;
580
if (name != NULL)
581
while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
582
{
583
msg[fixed_message_ln + iin] = name[iin];
584
++iin;
585
}
586
msg[fixed_message_ln + iin] = 0;
587
png_error(png_ptr, msg);
588
}
589
#endif
590
#endif
591
592
#ifdef PNG_SETJMP_SUPPORTED
593
/* This API only exists if ANSI-C style error handling is used,
594
* otherwise it is necessary for png_default_error to be overridden.
595
*/
596
jmp_buf* PNGAPI
597
png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,
598
size_t jmp_buf_size)
599
{
600
/* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value
601
* and it must not change after that. Libpng doesn't care how big the
602
* buffer is, just that it doesn't change.
603
*
604
* If the buffer size is no *larger* than the size of jmp_buf when libpng is
605
* compiled a built in jmp_buf is returned; this preserves the pre-1.6.0
606
* semantics that this call will not fail. If the size is larger, however,
607
* the buffer is allocated and this may fail, causing the function to return
608
* NULL.
609
*/
610
if (png_ptr == NULL)
611
return NULL;
612
613
if (png_ptr->jmp_buf_ptr == NULL)
614
{
615
png_ptr->jmp_buf_size = 0; /* not allocated */
616
617
if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))
618
png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;
619
620
else
621
{
622
png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,
623
png_malloc_warn(png_ptr, jmp_buf_size));
624
625
if (png_ptr->jmp_buf_ptr == NULL)
626
return NULL; /* new NULL return on OOM */
627
628
png_ptr->jmp_buf_size = jmp_buf_size;
629
}
630
}
631
632
else /* Already allocated: check the size */
633
{
634
size_t size = png_ptr->jmp_buf_size;
635
636
if (size == 0)
637
{
638
size = (sizeof png_ptr->jmp_buf_local);
639
if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local)
640
{
641
/* This is an internal error in libpng: somehow we have been left
642
* with a stack allocated jmp_buf when the application regained
643
* control. It's always possible to fix this up, but for the moment
644
* this is a png_error because that makes it easy to detect.
645
*/
646
png_error(png_ptr, "Libpng jmp_buf still allocated");
647
/* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */
648
}
649
}
650
651
if (size != jmp_buf_size)
652
{
653
png_warning(png_ptr, "Application jmp_buf size changed");
654
return NULL; /* caller will probably crash: no choice here */
655
}
656
}
657
658
/* Finally fill in the function, now we have a satisfactory buffer. It is
659
* valid to change the function on every call.
660
*/
661
png_ptr->longjmp_fn = longjmp_fn;
662
return png_ptr->jmp_buf_ptr;
663
}
664
665
void /* PRIVATE */
666
png_free_jmpbuf(png_structrp png_ptr)
667
{
668
if (png_ptr != NULL)
669
{
670
jmp_buf *jb = png_ptr->jmp_buf_ptr;
671
672
/* A size of 0 is used to indicate a local, stack, allocation of the
673
* pointer; used here and in png.c
674
*/
675
if (jb != NULL && png_ptr->jmp_buf_size > 0)
676
{
677
678
/* This stuff is so that a failure to free the error control structure
679
* does not leave libpng in a state with no valid error handling: the
680
* free always succeeds, if there is an error it gets ignored.
681
*/
682
if (jb != &png_ptr->jmp_buf_local)
683
{
684
/* Make an internal, libpng, jmp_buf to return here */
685
jmp_buf free_jmp_buf;
686
687
if (!setjmp(free_jmp_buf))
688
{
689
png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */
690
png_ptr->jmp_buf_size = 0; /* stack allocation */
691
png_ptr->longjmp_fn = longjmp;
692
png_free(png_ptr, jb); /* Return to setjmp on error */
693
}
694
}
695
}
696
697
/* *Always* cancel everything out: */
698
png_ptr->jmp_buf_size = 0;
699
png_ptr->jmp_buf_ptr = NULL;
700
png_ptr->longjmp_fn = 0;
701
}
702
}
703
#endif
704
705
/* This is the default error handling function. Note that replacements for
706
* this function MUST NOT RETURN, or the program will likely crash. This
707
* function is used by default, or if the program supplies NULL for the
708
* error function pointer in png_set_error_fn().
709
*/
710
static PNG_FUNCTION(void /* PRIVATE */,
711
png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
712
PNG_NORETURN)
713
{
714
#ifdef PNG_CONSOLE_IO_SUPPORTED
715
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
716
/* Check on NULL only added in 1.5.4 */
717
if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
718
{
719
/* Strip "#nnnn " from beginning of error message. */
720
int offset;
721
char error_number[16];
722
for (offset = 0; offset<15; offset++)
723
{
724
error_number[offset] = error_message[offset + 1];
725
if (error_message[offset] == ' ')
726
break;
727
}
728
729
if ((offset > 1) && (offset < 15))
730
{
731
error_number[offset - 1] = '\0';
732
fprintf(stderr, "libpng error no. %s: %s",
733
error_number, error_message + offset + 1);
734
fprintf(stderr, PNG_STRING_NEWLINE);
735
}
736
737
else
738
{
739
fprintf(stderr, "libpng error: %s, offset=%d",
740
error_message, offset);
741
fprintf(stderr, PNG_STRING_NEWLINE);
742
}
743
}
744
else
745
#endif
746
{
747
fprintf(stderr, "libpng error: %s", error_message ? error_message :
748
"undefined");
749
fprintf(stderr, PNG_STRING_NEWLINE);
750
}
751
#else
752
PNG_UNUSED(error_message) /* Make compiler happy */
753
#endif
754
png_longjmp(png_ptr, 1);
755
}
756
757
PNG_FUNCTION(void,PNGAPI
758
png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
759
{
760
#ifdef PNG_SETJMP_SUPPORTED
761
if (png_ptr != NULL && png_ptr->longjmp_fn != NULL &&
762
png_ptr->jmp_buf_ptr != NULL)
763
png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);
764
#else
765
PNG_UNUSED(png_ptr)
766
PNG_UNUSED(val)
767
#endif
768
769
/* If control reaches this point, png_longjmp() must not return. The only
770
* choice is to terminate the whole process (or maybe the thread); to do
771
* this the ANSI-C abort() function is used unless a different method is
772
* implemented by overriding the default configuration setting for
773
* PNG_ABORT().
774
*/
775
PNG_ABORT();
776
}
777
778
#ifdef PNG_WARNINGS_SUPPORTED
779
/* This function is called when there is a warning, but the library thinks
780
* it can continue anyway. Replacement functions don't have to do anything
781
* here if you don't want them to. In the default configuration, png_ptr is
782
* not used, but it is passed in case it may be useful.
783
*/
784
static void /* PRIVATE */
785
png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
786
{
787
#ifdef PNG_CONSOLE_IO_SUPPORTED
788
# ifdef PNG_ERROR_NUMBERS_SUPPORTED
789
if (*warning_message == PNG_LITERAL_SHARP)
790
{
791
int offset;
792
char warning_number[16];
793
for (offset = 0; offset < 15; offset++)
794
{
795
warning_number[offset] = warning_message[offset + 1];
796
if (warning_message[offset] == ' ')
797
break;
798
}
799
800
if ((offset > 1) && (offset < 15))
801
{
802
warning_number[offset + 1] = '\0';
803
fprintf(stderr, "libpng warning no. %s: %s",
804
warning_number, warning_message + offset);
805
fprintf(stderr, PNG_STRING_NEWLINE);
806
}
807
808
else
809
{
810
fprintf(stderr, "libpng warning: %s",
811
warning_message);
812
fprintf(stderr, PNG_STRING_NEWLINE);
813
}
814
}
815
else
816
# endif
817
818
{
819
fprintf(stderr, "libpng warning: %s", warning_message);
820
fprintf(stderr, PNG_STRING_NEWLINE);
821
}
822
#else
823
PNG_UNUSED(warning_message) /* Make compiler happy */
824
#endif
825
PNG_UNUSED(png_ptr) /* Make compiler happy */
826
}
827
#endif /* WARNINGS */
828
829
/* This function is called when the application wants to use another method
830
* of handling errors and warnings. Note that the error function MUST NOT
831
* return to the calling routine or serious problems will occur. The return
832
* method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)
833
*/
834
void PNGAPI
835
png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,
836
png_error_ptr error_fn, png_error_ptr warning_fn)
837
{
838
if (png_ptr == NULL)
839
return;
840
841
png_ptr->error_ptr = error_ptr;
842
png_ptr->error_fn = error_fn;
843
#ifdef PNG_WARNINGS_SUPPORTED
844
png_ptr->warning_fn = warning_fn;
845
#else
846
PNG_UNUSED(warning_fn)
847
#endif
848
}
849
850
851
/* This function returns a pointer to the error_ptr associated with the user
852
* functions. The application should free any memory associated with this
853
* pointer before png_write_destroy and png_read_destroy are called.
854
*/
855
png_voidp PNGAPI
856
png_get_error_ptr(png_const_structrp png_ptr)
857
{
858
if (png_ptr == NULL)
859
return NULL;
860
861
return (png_voidp)png_ptr->error_ptr;
862
}
863
864
865
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
866
void PNGAPI
867
png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
868
{
869
if (png_ptr != NULL)
870
{
871
png_ptr->flags &=
872
((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
873
PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
874
}
875
}
876
#endif
877
878
#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
879
defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
880
/* Currently the above both depend on SETJMP_SUPPORTED, however it would be
881
* possible to implement without setjmp support just so long as there is some
882
* way to handle the error return here:
883
*/
884
PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI
885
png_safe_error),(png_structp png_nonconst_ptr, png_const_charp error_message),
886
PNG_NORETURN)
887
{
888
png_const_structrp png_ptr = png_nonconst_ptr;
889
png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
890
891
/* An error is always logged here, overwriting anything (typically a warning)
892
* that is already there:
893
*/
894
if (image != NULL)
895
{
896
png_safecat(image->message, (sizeof image->message), 0, error_message);
897
image->warning_or_error |= PNG_IMAGE_ERROR;
898
899
/* Retrieve the jmp_buf from within the png_control, making this work for
900
* C++ compilation too is pretty tricky: C++ wants a pointer to the first
901
* element of a jmp_buf, but C doesn't tell us the type of that.
902
*/
903
if (image->opaque != NULL && image->opaque->error_buf != NULL)
904
longjmp(png_control_jmp_buf(image->opaque), 1);
905
906
/* Missing longjmp buffer, the following is to help debugging: */
907
{
908
size_t pos = png_safecat(image->message, (sizeof image->message), 0,
909
"bad longjmp: ");
910
png_safecat(image->message, (sizeof image->message), pos,
911
error_message);
912
}
913
}
914
915
/* Here on an internal programming error. */
916
abort();
917
}
918
919
#ifdef PNG_WARNINGS_SUPPORTED
920
void /* PRIVATE */ PNGCBAPI
921
png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
922
{
923
png_const_structrp png_ptr = png_nonconst_ptr;
924
png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
925
926
/* A warning is only logged if there is no prior warning or error. */
927
if (image->warning_or_error == 0)
928
{
929
png_safecat(image->message, (sizeof image->message), 0, warning_message);
930
image->warning_or_error |= PNG_IMAGE_WARNING;
931
}
932
}
933
#endif
934
935
int /* PRIVATE */
936
png_safe_execute(png_imagep image, int (*function)(png_voidp), png_voidp arg)
937
{
938
const png_voidp saved_error_buf = image->opaque->error_buf;
939
jmp_buf safe_jmpbuf;
940
941
/* Safely execute function(arg), with png_error returning back here. */
942
if (setjmp(safe_jmpbuf) == 0)
943
{
944
int result;
945
946
image->opaque->error_buf = safe_jmpbuf;
947
result = function(arg);
948
image->opaque->error_buf = saved_error_buf;
949
950
if (result)
951
return 1; /* success */
952
}
953
954
/* The function failed either because of a caught png_error and a regular
955
* return of false above or because of an uncaught png_error from the
956
* function itself. Ensure that the error_buf is always set back to the
957
* value saved above:
958
*/
959
image->opaque->error_buf = saved_error_buf;
960
961
/* On the final false return, when about to return control to the caller, the
962
* image is freed (png_image_free does this check but it is duplicated here
963
* for clarity:
964
*/
965
if (saved_error_buf == NULL)
966
png_image_free(image);
967
968
return 0; /* failure */
969
}
970
#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
971
#endif /* READ || WRITE */
972
973