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