pngerror.c 28.5 KB
Newer Older
G
Guy Schalnat 已提交
1 2

/* pngerror.c - stub functions for i/o and memory allocation
3
 *
4
 * Copyright (c) 2018 Cosmin Truta
5
 * Copyright (c) 1998-2002,2004,2006-2017 Glenn Randers-Pehrson
6 7
 * Copyright (c) 1996-1997 Andreas Dilger
 * Copyright (c) 1995-1996 Guy Eric Schalnat, Group 42, Inc.
8
 *
9
 * This code is released under the libpng license.
10
 * For conditions of distribution and use, see the disclaimer
11
 * and license in png.h
12
 *
13
 * This file provides a location for all error handling.  Users who
14 15 16 17
 * need special error handling are expected to write replacement functions
 * and use png_set_error_fn() to use those functions.  See the instructions
 * at each function.
 */
G
Guy Schalnat 已提交
18

19
#include "pngpriv.h"
G
Guy Schalnat 已提交
20

21 22
#if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)

23
static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,
24 25
    png_const_charp error_message)),PNG_NORETURN);

26
#ifdef PNG_WARNINGS_SUPPORTED
27
static void /* PRIVATE */
28
png_default_warning PNGARG((png_const_structrp png_ptr,
29
    png_const_charp warning_message));
30
#endif /* WARNINGS */
G
Guy Schalnat 已提交
31

G
Guy Schalnat 已提交
32
/* This function is called whenever there is a fatal error.  This function
33 34 35 36
 * should not be changed.  If there is a need to handle errors differently,
 * you should supply a replacement error function and use png_set_error_fn()
 * to replace the error function at run-time.
 */
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)
G
Guy Schalnat 已提交
41
{
42 43
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
   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 50 51 52 53 54
      {
         if (*error_message == PNG_LITERAL_SHARP)
         {
            /* Strip "#nnnn " from beginning of error message. */
            int offset;
            for (offset = 1; offset<15; offset++)
               if (error_message[offset] == ' ')
55
                  break;
56

57
            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
58 59 60 61 62 63 64 65 66 67
            {
               int i;
               for (i = 0; i < offset - 1; i++)
                  msg[i] = error_message[i + 1];
               msg[i - 1] = '\0';
               error_message = msg;
            }

            else
               error_message += offset;
68
         }
69

70
         else
71
         {
72 73 74 75 76 77
            if ((png_ptr->flags & PNG_FLAG_STRIP_ERROR_TEXT) != 0)
            {
               msg[0] = '0';
               msg[1] = '\0';
               error_message = msg;
            }
78
         }
79
      }
80 81
   }
#endif
82
   if (png_ptr != NULL && png_ptr->error_fn != NULL)
83 84
      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
          error_message);
G
Guy Schalnat 已提交
85

86 87
   /* If the custom handler doesn't exist, or if it returns,
      use the default handler, which will not return. */
88
   png_default_error(png_ptr, error_message);
G
Guy Schalnat 已提交
89
}
90
#else
91
PNG_FUNCTION(void,PNGAPI
92
png_err,(png_const_structrp png_ptr),PNG_NORETURN)
93
{
94 95 96 97
   /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
    * erroneously as '\0', instead of the empty string "".  This was
    * apparently an error, introduced in libpng-1.2.20, and png_default_error
    * 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 103

   /* If the custom handler doesn't exist, or if it returns,
      use the default handler, which will not return. */
104
   png_default_error(png_ptr, "");
105
}
106
#endif /* ERROR_TEXT */
G
Guy Schalnat 已提交
107

108 109 110 111 112
/* Utility to safely appends strings to a buffer.  This never errors out so
 * error checking is not required in the caller.
 */
size_t
png_safecat(png_charp buffer, size_t bufsize, size_t pos,
113
    png_const_charp string)
114 115 116
{
   if (buffer != NULL && pos < bufsize)
   {
117 118 119
      if (string != NULL)
         while (*string != '\0' && pos < bufsize-1)
           buffer[pos++] = *string++;
120 121 122 123 124 125 126

      buffer[pos] = '\0';
   }

   return pos;
}

127
#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
128 129 130 131 132 133
/* Utility to dump an unsigned value into a buffer, given a start pointer and
 * and end pointer (which should point just *beyond* the end of the buffer!)
 * Returns the pointer to the start of the formatted string.
 */
png_charp
png_format_number(png_const_charp start, png_charp end, int format,
134
    png_alloc_size_t number)
135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154
{
   int count = 0;    /* number of digits output */
   int mincount = 1; /* minimum number required */
   int output = 0;   /* digit output (for the fixed point format) */

   *--end = '\0';

   /* This is written so that the loop always runs at least once, even with
    * number zero.
    */
   while (end > start && (number != 0 || count < mincount))
   {

      static const char digits[] = "0123456789ABCDEF";

      switch (format)
      {
         case PNG_NUMBER_FORMAT_fixed:
            /* Needs five digits (the fraction) */
            mincount = 5;
155
            if (output != 0 || number % 10 != 0)
156 157 158 159 160 161 162 163 164 165
            {
               *--end = digits[number % 10];
               output = 1;
            }
            number /= 10;
            break;

         case PNG_NUMBER_FORMAT_02u:
            /* Expects at least 2 digits. */
            mincount = 2;
166
            /* FALLTHROUGH */
167 168 169 170 171 172 173 174 175

         case PNG_NUMBER_FORMAT_u:
            *--end = digits[number % 10];
            number /= 10;
            break;

         case PNG_NUMBER_FORMAT_02x:
            /* This format expects at least two digits */
            mincount = 2;
176
            /* FALLTHROUGH */
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191

         case PNG_NUMBER_FORMAT_x:
            *--end = digits[number & 0xf];
            number >>= 4;
            break;

         default: /* an error */
            number = 0;
            break;
      }

      /* Keep track of the number of digits added */
      ++count;

      /* Float a fixed number here: */
192
      if ((format == PNG_NUMBER_FORMAT_fixed) && (count == 5) && (end > start))
193 194 195 196 197
      {
         /* End of the fraction, but maybe nothing was output?  In that case
          * drop the decimal point.  If the number is a true zero handle that
          * here.
          */
198
         if (output != 0)
199 200 201 202 203 204 205 206 207 208
            *--end = '.';
         else if (number == 0) /* and !output */
            *--end = '0';
      }
   }

   return end;
}
#endif

209
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
210
/* This function is called whenever there is a non-fatal error.  This function
211 212 213 214
 * should not be changed.  If there is a need to handle warnings differently,
 * you should supply a replacement warning function and use
 * png_set_error_fn() to replace the warning function at run-time.
 */
215
void PNGAPI
216
png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
G
Guy Schalnat 已提交
217
{
218
   int offset = 0;
219 220
   if (png_ptr != NULL)
   {
221
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
222 223
   if ((png_ptr->flags &
       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT)) != 0)
224
#endif
225 226 227 228 229
      {
         if (*warning_message == PNG_LITERAL_SHARP)
         {
            for (offset = 1; offset < 15; offset++)
               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);
G
Guy Schalnat 已提交
237
   else
238
      png_default_warning(png_ptr, warning_message + offset);
G
Guy Schalnat 已提交
239
}
240 241 242 243 244 245 246 247

/* These functions support 'formatted' warning messages with up to
 * PNG_WARNING_PARAMETER_COUNT parameters.  In the format string the parameter
 * is introduced by @<number>, where 'number' starts at 1.  This follows the
 * standard established by X/Open for internationalizable error messages.
 */
void
png_warning_parameter(png_warning_parameters p, int number,
248
    png_const_charp string)
249 250 251 252 253 254 255
{
   if (number > 0 && number <= PNG_WARNING_PARAMETER_COUNT)
      (void)png_safecat(p[number-1], (sizeof p[number-1]), 0, string);
}

void
png_warning_parameter_unsigned(png_warning_parameters p, int number, int format,
256
    png_alloc_size_t value)
257 258 259 260 261 262 263
{
   char buffer[PNG_NUMBER_BUFFER_SIZE];
   png_warning_parameter(p, number, PNG_FORMAT_NUMBER(buffer, format, value));
}

void
png_warning_parameter_signed(png_warning_parameters p, int number, int format,
264
    png_int_32 value)
265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283
{
   png_alloc_size_t u;
   png_charp str;
   char buffer[PNG_NUMBER_BUFFER_SIZE];

   /* Avoid overflow by doing the negate in a png_alloc_size_t: */
   u = (png_alloc_size_t)value;
   if (value < 0)
      u = ~u + 1;

   str = PNG_FORMAT_NUMBER(buffer, format, u);

   if (value < 0 && str > buffer)
      *--str = '-';

   png_warning_parameter(p, number, str);
}

void
284
png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,
285
    png_const_charp message)
286
{
287 288 289 290
   /* The internal buffer is just 192 bytes - enough for all our messages,
    * overflow doesn't happen because this code checks!  If someone figures
    * out how to send us a message longer than 192 bytes, all that will
    * 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 296 297 298 299 300 301
   /* Each iteration through the following loop writes at most one character
    * to msg[i++] then returns here to validate that there is still space for
    * the trailing '\0'.  It may (in the case of a parameter) read more than
    * one character from message[]; it must check for '\0' and continue to the
    * test if it finds the end of string.
    */
   while (i<(sizeof msg)-1 && *message != '\0')
302
   {
303 304 305 306
      /* '@' at end of string is now just printed (previously it was skipped);
       * it is an error in the calling code to terminate the string with @.
       */
      if (p != NULL && *message == '@' && message[1] != '\0')
307
      {
308 309 310
         int parameter_char = *++message; /* Consume the '@' */
         static const char valid_parameters[] = "123456789";
         int parameter = 0;
311

312 313 314 315 316 317
         /* Search for the parameter digit, the index in the string is the
          * parameter to use.
          */
         while (valid_parameters[parameter] != parameter_char &&
            valid_parameters[parameter] != '\0')
            ++parameter;
318

319 320
         /* If the parameter digit is out of range it will just get printed. */
         if (parameter < PNG_WARNING_PARAMETER_COUNT)
321 322 323 324 325 326 327 328 329
         {
            /* Append this parameter */
            png_const_charp parm = p[parameter];
            png_const_charp pend = p[parameter] + (sizeof p[parameter]);

            /* No need to copy the trailing '\0' here, but there is no guarantee
             * that parm[] has been initialized, so there is no guarantee of a
             * trailing '\0':
             */
330 331
            while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
               msg[i++] = *parm++;
332

333
            /* Consume the parameter digit too: */
334 335 336 337 338
            ++message;
            continue;
         }

         /* 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 344 345
          */
      }

      /* At this point *message can't be '\0', even in the bad parameter case
       * above where there is a lone '@' at the end of the message string.
       */
346
      msg[i++] = *message++;
347 348 349 350 351
   }

   /* i is always less than (sizeof msg), so: */
   msg[i] = '\0';

352 353 354
   /* And this is the formatted message. It may be larger than
    * PNG_MAX_ERROR_TEXT, but that is only used for 'chunk' errors and these
    * are not (currently) formatted.
355
    */
356 357
   png_warning(png_ptr, msg);
}
358
#endif /* WARNINGS */
G
Guy Schalnat 已提交
359

360 361
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
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 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
   {
#     ifdef PNG_READ_SUPPORTED
         if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
            png_ptr->chunk_name != 0)
            png_chunk_warning(png_ptr, error_message);
         else
#     endif
      png_warning(png_ptr, error_message);
   }

   else
   {
#     ifdef PNG_READ_SUPPORTED
         if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0 &&
            png_ptr->chunk_name != 0)
            png_chunk_error(png_ptr, error_message);
         else
#     endif
      png_error(png_ptr, error_message);
   }
385 386 387 388

#  ifndef PNG_ERROR_TEXT_SUPPORTED
      PNG_UNUSED(error_message)
#  endif
389 390 391 392 393
}

void /* PRIVATE */
png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)
{
394 395 396 397
   if ((png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN) != 0)
      png_warning(png_ptr, error_message);
   else
      png_error(png_ptr, error_message);
398 399 400 401

#  ifndef PNG_ERROR_TEXT_SUPPORTED
      PNG_UNUSED(error_message)
#  endif
402
}
403 404 405 406

void /* PRIVATE */
png_app_error(png_const_structrp png_ptr, png_const_charp error_message)
{
407 408 409 410
   if ((png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN) != 0)
      png_warning(png_ptr, error_message);
   else
      png_error(png_ptr, error_message);
411 412 413 414

#  ifndef PNG_ERROR_TEXT_SUPPORTED
      PNG_UNUSED(error_message)
#  endif
415 416
}
#endif /* BENIGN_ERRORS */
417

418
#define PNG_MAX_ERROR_TEXT 196 /* Currently limited by profile_error in png.c */
419 420
#if defined(PNG_WARNINGS_SUPPORTED) || \
   (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 424
 * which is used to prefix the message.  The message is limited in length
 * to 63 bytes. The name characters are output as hex digits wrapped in []
425 426
 * if the character is invalid.
 */
427
#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
428
static const char png_digit[16] = {
429 430 431
   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F'
};
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 438
   png_uint_32 chunk_name = png_ptr->chunk_name;
   int iout = 0, ishift = 24;
439

440
   while (ishift >= 0)
441
   {
442 443 444
      int c = (int)(chunk_name >> ishift) & 0xff;

      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 454
      else
      {
455
         buffer[iout++] = (char)c;
456 457 458
      }
   }

459
   if (error_message == NULL)
460
      buffer[iout] = '\0';
461

462 463
   else
   {
464 465
      int iin = 0;

466 467
      buffer[iout++] = ':';
      buffer[iout++] = ' ';
468 469 470 471 472 473

      while (iin < PNG_MAX_ERROR_TEXT-1 && error_message[iin] != '\0')
         buffer[iout++] = error_message[iin++];

      /* iin < PNG_MAX_ERROR_TEXT, so the following is safe: */
      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 488
   else
   {
489 490
      png_format_buffer(png_ptr, msg, error_message);
      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 504
   else
   {
505 506
      png_format_buffer(png_ptr, msg, warning_message);
      png_warning(png_ptr, msg);
507
   }
508
}
509
#endif /* WARNINGS */
510

511
#ifdef PNG_READ_SUPPORTED
512 513
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
void PNGAPI
514 515
png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
    error_message)
516
{
517
   if ((png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN) != 0)
518
      png_chunk_warning(png_ptr, error_message);
519

520 521
   else
      png_chunk_error(png_ptr, error_message);
522 523 524 525

#  ifndef PNG_ERROR_TEXT_SUPPORTED
      PNG_UNUSED(error_message)
#  endif
526 527
}
#endif
528
#endif /* READ */
529

530 531 532
void /* PRIVATE */
png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
{
533 534 535 536
#  ifndef PNG_WARNINGS_SUPPORTED
      PNG_UNUSED(message)
#  endif

537 538 539 540
   /* This is always supported, but for just read or just write it
    * unconditionally does the right thing.
    */
#  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
541
      if ((png_ptr->mode & PNG_IS_READ_STRUCT) != 0)
542 543 544 545 546 547 548 549 550 551 552 553 554
#  endif

#  ifdef PNG_READ_SUPPORTED
      {
         if (error < PNG_CHUNK_ERROR)
            png_chunk_warning(png_ptr, message);

         else
            png_chunk_benign_error(png_ptr, message);
      }
#  endif

#  if defined(PNG_READ_SUPPORTED) && defined(PNG_WRITE_SUPPORTED)
555
      else if ((png_ptr->mode & PNG_IS_READ_STRUCT) == 0)
556 557 558 559 560 561 562 563 564 565 566 567 568
#  endif

#  ifdef PNG_WRITE_SUPPORTED
      {
         if (error < PNG_CHUNK_WRITE_ERROR)
            png_app_warning(png_ptr, message);

         else
            png_app_error(png_ptr, message);
      }
#  endif
}

G
[devel]  
Glenn Randers-Pehrson 已提交
569 570
#ifdef PNG_ERROR_TEXT_SUPPORTED
#ifdef PNG_FLOATING_POINT_SUPPORTED
571
PNG_FUNCTION(void,
572
png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
G
[devel]  
Glenn Randers-Pehrson 已提交
573 574 575
{
#  define fixed_message "fixed point overflow in "
#  define fixed_message_ln ((sizeof fixed_message)-1)
576
   unsigned int  iin;
G
[devel]  
Glenn Randers-Pehrson 已提交
577
   char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];
578
   memcpy(msg, fixed_message, fixed_message_ln);
G
[devel]  
Glenn Randers-Pehrson 已提交
579
   iin = 0;
580 581 582 583 584 585
   if (name != NULL)
      while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
      {
         msg[fixed_message_ln + iin] = name[iin];
         ++iin;
      }
G
[devel]  
Glenn Randers-Pehrson 已提交
586 587 588 589 590 591
   msg[fixed_message_ln + iin] = 0;
   png_error(png_ptr, msg);
}
#endif
#endif

592
#ifdef PNG_SETJMP_SUPPORTED
593 594
/* This API only exists if ANSI-C style error handling is used,
 * 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 601 602 603 604 605 606 607 608 609 610
   /* From libpng 1.6.0 the app gets one chance to set a 'jmpbuf_size' value
    * and it must not change after that.  Libpng doesn't care how big the
    * buffer is, just that it doesn't change.
    *
    * If the buffer size is no *larger* than the size of jmp_buf when libpng is
    * compiled a built in jmp_buf is returned; this preserves the pre-1.6.0
    * semantics that this call will not fail.  If the size is larger, however,
    * the buffer is allocated and this may fail, causing the function to return
    * NULL.
    */
   if (png_ptr == NULL)
611 612
      return NULL;

613 614 615 616
   if (png_ptr->jmp_buf_ptr == NULL)
   {
      png_ptr->jmp_buf_size = 0; /* not allocated */

617
      if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))
618 619 620 621 622
         png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;

      else
      {
         png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,
623
             png_malloc_warn(png_ptr, jmp_buf_size));
624 625 626 627 628 629 630 631 632 633 634 635 636 637

         if (png_ptr->jmp_buf_ptr == NULL)
            return NULL; /* new NULL return on OOM */

         png_ptr->jmp_buf_size = jmp_buf_size;
      }
   }

   else /* Already allocated: check the size */
   {
      size_t size = png_ptr->jmp_buf_size;

      if (size == 0)
      {
638
         size = (sizeof png_ptr->jmp_buf_local);
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660
         if (png_ptr->jmp_buf_ptr != &png_ptr->jmp_buf_local)
         {
            /* This is an internal error in libpng: somehow we have been left
             * with a stack allocated jmp_buf when the application regained
             * control.  It's always possible to fix this up, but for the moment
             * this is a png_error because that makes it easy to detect.
             */
            png_error(png_ptr, "Libpng jmp_buf still allocated");
            /* png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local; */
         }
      }

      if (size != jmp_buf_size)
      {
         png_warning(png_ptr, "Application jmp_buf size changed");
         return NULL; /* caller will probably crash: no choice here */
      }
   }

   /* Finally fill in the function, now we have a satisfactory buffer. It is
    * valid to change the function on every call.
    */
661
   png_ptr->longjmp_fn = longjmp_fn;
662 663 664 665
   return png_ptr->jmp_buf_ptr;
}

void /* PRIVATE */
666
png_free_jmpbuf(png_structrp png_ptr)
667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701
{
   if (png_ptr != NULL)
   {
      jmp_buf *jb = png_ptr->jmp_buf_ptr;

      /* A size of 0 is used to indicate a local, stack, allocation of the
       * pointer; used here and in png.c
       */
      if (jb != NULL && png_ptr->jmp_buf_size > 0)
      {

         /* This stuff is so that a failure to free the error control structure
          * does not leave libpng in a state with no valid error handling: the
          * free always succeeds, if there is an error it gets ignored.
          */
         if (jb != &png_ptr->jmp_buf_local)
         {
            /* Make an internal, libpng, jmp_buf to return here */
            jmp_buf free_jmp_buf;

            if (!setjmp(free_jmp_buf))
            {
               png_ptr->jmp_buf_ptr = &free_jmp_buf; /* come back here */
               png_ptr->jmp_buf_size = 0; /* stack allocation */
               png_ptr->longjmp_fn = longjmp;
               png_free(png_ptr, jb); /* Return to setjmp on error */
            }
         }
      }

      /* *Always* cancel everything out: */
      png_ptr->jmp_buf_size = 0;
      png_ptr->jmp_buf_ptr = NULL;
      png_ptr->longjmp_fn = 0;
   }
702 703 704
}
#endif

G
Guy Schalnat 已提交
705
/* This is the default error handling function.  Note that replacements for
706 707 708 709
 * this function MUST NOT RETURN, or the program will likely crash.  This
 * function is used by default, or if the program supplies NULL for the
 * error function pointer in png_set_error_fn().
 */
710
static PNG_FUNCTION(void /* PRIVATE */,
711
png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
712
    PNG_NORETURN)
G
Guy Schalnat 已提交
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 720 721 722 723
      /* Strip "#nnnn " from beginning of error message. */
      int offset;
      char error_number[16];
      for (offset = 0; offset<15; offset++)
      {
724 725
         error_number[offset] = error_message[offset + 1];
         if (error_message[offset] == ' ')
726 727
            break;
      }
728

729 730 731 732 733 734 735
      if ((offset > 1) && (offset < 15))
      {
         error_number[offset - 1] = '\0';
         fprintf(stderr, "libpng error no. %s: %s",
             error_number, error_message + offset + 1);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
736

737 738 739 740 741 742
      else
      {
         fprintf(stderr, "libpng error: %s, offset=%d",
             error_message, offset);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
743 744 745
   }
   else
#endif
746
   {
747 748
      fprintf(stderr, "libpng error: %s", error_message ? error_message :
         "undefined");
749 750
      fprintf(stderr, PNG_STRING_NEWLINE);
   }
751
#else
752
   PNG_UNUSED(error_message) /* Make compiler happy */
753
#endif
754
   png_longjmp(png_ptr, 1);
755
}
G
Guy Schalnat 已提交
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 762
   if (png_ptr != NULL && png_ptr->longjmp_fn != NULL &&
       png_ptr->jmp_buf_ptr != NULL)
763
      png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);
764 765 766
#else
   PNG_UNUSED(png_ptr)
   PNG_UNUSED(val)
G
Guy Schalnat 已提交
767
#endif
768

769 770
   /* If control reaches this point, png_longjmp() must not return. The only
    * 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 773 774
    * implemented by overriding the default configuration setting for
    * PNG_ABORT().
    */
775
   PNG_ABORT();
G
Guy Schalnat 已提交
776 777
}

778
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
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 783
 * not used, but it is passed in case it may be useful.
 */
784
static void /* PRIVATE */
785
png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
G
Guy Schalnat 已提交
786
{
787
#ifdef PNG_CONSOLE_IO_SUPPORTED
788
#  ifdef PNG_ERROR_NUMBERS_SUPPORTED
789
   if (*warning_message == PNG_LITERAL_SHARP)
790
   {
791 792 793 794 795 796
      int offset;
      char warning_number[16];
      for (offset = 0; offset < 15; offset++)
      {
         warning_number[offset] = warning_message[offset + 1];
         if (warning_message[offset] == ' ')
797
            break;
798
      }
799

800 801 802 803 804 805 806
      if ((offset > 1) && (offset < 15))
      {
         warning_number[offset + 1] = '\0';
         fprintf(stderr, "libpng warning no. %s: %s",
             warning_number, warning_message + offset);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
807

808 809 810 811 812 813
      else
      {
         fprintf(stderr, "libpng warning: %s",
             warning_message);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
814 815 816
   }
   else
#  endif
817

818
   {
819 820
      fprintf(stderr, "libpng warning: %s", warning_message);
      fprintf(stderr, PNG_STRING_NEWLINE);
821
   }
822
#else
823
   PNG_UNUSED(warning_message) /* Make compiler happy */
G
Guy Schalnat 已提交
824
#endif
825
   PNG_UNUSED(png_ptr) /* Make compiler happy */
G
Guy Schalnat 已提交
826
}
827
#endif /* WARNINGS */
G
Guy Schalnat 已提交
828

G
Guy Schalnat 已提交
829
/* This function is called when the application wants to use another method
830 831
 * of handling errors and warnings.  Note that the error function MUST NOT
 * 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)
G
Guy Schalnat 已提交
837
{
838 839
   if (png_ptr == NULL)
      return;
840

G
Guy Schalnat 已提交
841
   png_ptr->error_ptr = error_ptr;
G
Guy Schalnat 已提交
842
   png_ptr->error_fn = error_fn;
843
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
844
   png_ptr->warning_fn = warning_fn;
845 846 847
#else
   PNG_UNUSED(warning_fn)
#endif
G
Guy Schalnat 已提交
848 849 850
}


G
Guy Schalnat 已提交
851
/* This function returns a pointer to the error_ptr associated with the user
852 853 854
 * functions.  The application should free any memory associated with this
 * pointer before png_write_destroy and png_read_destroy are called.
 */
855
png_voidp PNGAPI
856
png_get_error_ptr(png_const_structrp png_ptr)
G
Guy Schalnat 已提交
857
{
858 859
   if (png_ptr == NULL)
      return NULL;
860

861
   return ((png_voidp)png_ptr->error_ptr);
G
Guy Schalnat 已提交
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 872 873
      png_ptr->flags &=
         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
874 875 876
   }
}
#endif
877

878 879
#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
880 881 882 883
   /* Currently the above both depend on SETJMP_SUPPORTED, however it would be
    * possible to implement without setjmp support just so long as there is some
    * way to handle the error return here:
    */
884 885
PNG_FUNCTION(void /* PRIVATE */, (PNGCBAPI
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 892 893 894 895

   /* An error is always logged here, overwriting anything (typically a warning)
    * that is already there:
    */
   if (image != NULL)
   {
896 897
      png_safecat(image->message, (sizeof image->message), 0, error_message);
      image->warning_or_error |= PNG_IMAGE_ERROR;
898

899 900 901 902
      /* Retrieve the jmp_buf from within the png_control, making this work for
       * C++ compilation too is pretty tricky: C++ wants a pointer to the first
       * element of a jmp_buf, but C doesn't tell us the type of that.
       */
903
      if (image->opaque != NULL && image->opaque->error_buf != NULL)
904
         longjmp(png_control_jmp_buf(image->opaque), 1);
905 906 907

      /* Missing longjmp buffer, the following is to help debugging: */
      {
908
         size_t pos = png_safecat(image->message, (sizeof image->message), 0,
909
             "bad longjmp: ");
910 911
         png_safecat(image->message, (sizeof image->message), pos,
             error_message);
912 913 914 915 916 917 918 919
      }
   }

   /* Here on an internal programming error. */
   abort();
}

#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 928
   if (image->warning_or_error == 0)
   {
929 930
      png_safecat(image->message, (sizeof image->message), 0, warning_message);
      image->warning_or_error |= PNG_IMAGE_WARNING;
931 932 933 934 935
   }
}
#endif

int /* PRIVATE */
936
png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)
937
{
938
   volatile png_imagep image = image_in;
939 940 941 942 943 944 945 946
   volatile int result;
   volatile png_voidp saved_error_buf;
   jmp_buf safe_jmpbuf;

   /* Safely execute function(arg) with png_error returning to this function. */
   saved_error_buf = image->opaque->error_buf;
   result = setjmp(safe_jmpbuf) == 0;

947
   if (result != 0)
948 949 950 951 952 953 954 955 956
   {

      image->opaque->error_buf = safe_jmpbuf;
      result = function(arg);
   }

   image->opaque->error_buf = saved_error_buf;

   /* And do the cleanup prior to any failure return. */
957
   if (result == 0)
958 959 960 961
      png_image_free(image);

   return result;
}
962 963
#endif /* SIMPLIFIED READ || SIMPLIFIED_WRITE */
#endif /* READ || WRITE */