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

/* pngerror.c - stub functions for i/o and memory allocation
3
 *
4
 * Last changed in libpng 1.6.8 [December 19, 2013]
5
 * Copyright (c) 1998-2013 Glenn Randers-Pehrson
6 7
 * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
 * (Version 0.88 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 /* PNG_WARNINGS_SUPPORTED */
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))
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 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77

            if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
            {
               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;
      }

      else
      {
         if (png_ptr->flags&PNG_FLAG_STRIP_ERROR_TEXT)
         {
            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 /* PNG_ERROR_TEXT_SUPPORTED */
G
Guy Schalnat 已提交
107

108 109 110 111 112 113 114 115 116
/* 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,
   png_const_charp string)
{
   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 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165
/* 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,
   png_alloc_size_t number)
{
   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;
            if (output || number % 10 != 0)
            {
               *--end = digits[number % 10];
               output = 1;
            }
            number /= 10;
            break;

         case PNG_NUMBER_FORMAT_02u:
            /* Expects at least 2 digits. */
            mincount = 2;
166
            /* FALL THROUGH */
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
            /* FALL THROUGH */
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208

         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: */
      if (format == PNG_NUMBER_FORMAT_fixed) if (count == 5) if (end > start)
      {
         /* 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.
          */
         if (output)
            *--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
   if (png_ptr->flags&
223
       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
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 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283

/* 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,
   png_const_charp string)
{
   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,
   png_alloc_size_t value)
{
   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,
   png_int_32 value)
{
   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 286
   png_const_charp message)
{
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 /* PNG_WARNINGS_SUPPORTED */
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 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384
   if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)
   {
#     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 394
}

void /* PRIVATE */
png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)
{
  if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN)
395 396 397
     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 407 408 409 410

void /* PRIVATE */
png_app_error(png_const_structrp png_ptr, png_const_charp error_message)
{
  if (png_ptr->flags & PNG_FLAG_APP_ERRORS_WARN)
     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
/* These utilities are used internally to build an error message that relates
419 420 421 422 423
 * to the current chunk.  The chunk name comes from png_ptr->chunk_name,
 * this 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 []
 * if the character is invalid.
 */
424
#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
425
static PNG_CONST char png_digit[16] = {
426 427 428
   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F'
};
429

430
#define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */
431 432
#if defined(PNG_WARNINGS_SUPPORTED) || \
   (defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED))
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 446
      if (isnonalpha(c))
      {
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 /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */
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 /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */
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 /* PNG_WARNINGS_SUPPORTED */
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 518
   if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)
      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 /* PNG_READ_SUPPORTED */
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 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
   /* 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)
      if (png_ptr->mode & PNG_IS_READ_STRUCT)
#  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)
      else if (!(png_ptr->mode & PNG_IS_READ_STRUCT))
#  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 576 577
{
#  define fixed_message "fixed point overflow in "
#  define fixed_message_ln ((sizeof fixed_message)-1)
   int  iin;
   char msg[fixed_message_ln+PNG_MAX_ERROR_TEXT];
578
   memcpy(msg, fixed_message, fixed_message_ln);
G
[devel]  
Glenn Randers-Pehrson 已提交
579 580 581 582 583 584 585 586 587 588 589 590
   iin = 0;
   if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
   {
      msg[fixed_message_ln + iin] = name[iin];
      ++iin;
   }
   msg[fixed_message_ln + iin] = 0;
   png_error(png_ptr, msg);
}
#endif
#endif

591
#ifdef PNG_SETJMP_SUPPORTED
592 593
/* This API only exists if ANSI-C style error handling is used,
 * otherwise it is necessary for png_default_error to be overridden.
594 595
 */
jmp_buf* PNGAPI
596
png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,
597
    size_t jmp_buf_size)
598
{
599 600 601 602 603 604 605 606 607 608 609
   /* 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)
610 611
      return NULL;

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

616
      if (jmp_buf_size <= (sizeof png_ptr->jmp_buf_local))
617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
         png_ptr->jmp_buf_ptr = &png_ptr->jmp_buf_local;

      else
      {
         png_ptr->jmp_buf_ptr = png_voidcast(jmp_buf *,
            png_malloc_warn(png_ptr, jmp_buf_size));

         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)
      {
637
         size = (sizeof png_ptr->jmp_buf_local);
638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659
         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.
    */
660
   png_ptr->longjmp_fn = longjmp_fn;
661 662 663 664
   return png_ptr->jmp_buf_ptr;
}

void /* PRIVATE */
665
png_free_jmpbuf(png_structrp png_ptr)
666 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
{
   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;
   }
701 702 703
}
#endif

G
Guy Schalnat 已提交
704
/* This is the default error handling function.  Note that replacements for
705 706 707 708
 * 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().
 */
709
static PNG_FUNCTION(void /* PRIVATE */,
710
png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
711
   PNG_NORETURN)
G
Guy Schalnat 已提交
712
{
713
#ifdef PNG_CONSOLE_IO_SUPPORTED
714
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
715
   /* Check on NULL only added in 1.5.4 */
716
   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
717
   {
718 719 720 721 722
      /* Strip "#nnnn " from beginning of error message. */
      int offset;
      char error_number[16];
      for (offset = 0; offset<15; offset++)
      {
723 724
         error_number[offset] = error_message[offset + 1];
         if (error_message[offset] == ' ')
725 726
            break;
      }
727

728 729 730 731 732 733 734
      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);
      }
735

736 737 738 739 740 741
      else
      {
         fprintf(stderr, "libpng error: %s, offset=%d",
             error_message, offset);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
742 743 744
   }
   else
#endif
745
   {
746 747
      fprintf(stderr, "libpng error: %s", error_message ? error_message :
         "undefined");
748 749
      fprintf(stderr, PNG_STRING_NEWLINE);
   }
750
#else
751
   PNG_UNUSED(error_message) /* Make compiler happy */
752
#endif
753
   png_longjmp(png_ptr, 1);
754
}
G
Guy Schalnat 已提交
755

756
PNG_FUNCTION(void,PNGAPI
757
png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
758
{
759
#ifdef PNG_SETJMP_SUPPORTED
760 761
   if (png_ptr && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr)
      png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);
G
Guy Schalnat 已提交
762
#endif
763

764 765
   /* Here if not setjmp support or if png_ptr is null. */
   PNG_ABORT();
G
Guy Schalnat 已提交
766 767
}

768
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
769
/* This function is called when there is a warning, but the library thinks
770
 * it can continue anyway.  Replacement functions don't have to do anything
771
 * here if you don't want them to.  In the default configuration, png_ptr is
772 773
 * not used, but it is passed in case it may be useful.
 */
774
static void /* PRIVATE */
775
png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
G
Guy Schalnat 已提交
776
{
777
#ifdef PNG_CONSOLE_IO_SUPPORTED
778
#  ifdef PNG_ERROR_NUMBERS_SUPPORTED
779
   if (*warning_message == PNG_LITERAL_SHARP)
780
   {
781 782 783 784 785 786
      int offset;
      char warning_number[16];
      for (offset = 0; offset < 15; offset++)
      {
         warning_number[offset] = warning_message[offset + 1];
         if (warning_message[offset] == ' ')
787
            break;
788
      }
789

790 791 792 793 794 795 796
      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);
      }
797

798 799 800 801 802 803
      else
      {
         fprintf(stderr, "libpng warning: %s",
             warning_message);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
804 805 806
   }
   else
#  endif
807

808
   {
809 810
      fprintf(stderr, "libpng warning: %s", warning_message);
      fprintf(stderr, PNG_STRING_NEWLINE);
811
   }
812
#else
813
   PNG_UNUSED(warning_message) /* Make compiler happy */
G
Guy Schalnat 已提交
814
#endif
815
   PNG_UNUSED(png_ptr) /* Make compiler happy */
G
Guy Schalnat 已提交
816
}
817
#endif /* PNG_WARNINGS_SUPPORTED */
G
Guy Schalnat 已提交
818

G
Guy Schalnat 已提交
819
/* This function is called when the application wants to use another method
820 821
 * of handling errors and warnings.  Note that the error function MUST NOT
 * return to the calling routine or serious problems will occur.  The return
822
 * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)
823
 */
824
void PNGAPI
825
png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,
826
    png_error_ptr error_fn, png_error_ptr warning_fn)
G
Guy Schalnat 已提交
827
{
828 829
   if (png_ptr == NULL)
      return;
830

G
Guy Schalnat 已提交
831
   png_ptr->error_ptr = error_ptr;
G
Guy Schalnat 已提交
832
   png_ptr->error_fn = error_fn;
833
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
834
   png_ptr->warning_fn = warning_fn;
835 836 837
#else
   PNG_UNUSED(warning_fn)
#endif
G
Guy Schalnat 已提交
838 839 840
}


G
Guy Schalnat 已提交
841
/* This function returns a pointer to the error_ptr associated with the user
842 843 844
 * functions.  The application should free any memory associated with this
 * pointer before png_write_destroy and png_read_destroy are called.
 */
845
png_voidp PNGAPI
846
png_get_error_ptr(png_const_structrp png_ptr)
G
Guy Schalnat 已提交
847
{
848 849
   if (png_ptr == NULL)
      return NULL;
850

851
   return ((png_voidp)png_ptr->error_ptr);
G
Guy Schalnat 已提交
852 853 854
}


855
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
856
void PNGAPI
857
png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
858
{
859
   if (png_ptr != NULL)
860
   {
861 862 863
      png_ptr->flags &=
         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
864 865 866
   }
}
#endif
867

868 869
#if defined(PNG_SIMPLIFIED_READ_SUPPORTED) ||\
   defined(PNG_SIMPLIFIED_WRITE_SUPPORTED)
870 871 872 873 874
   /* 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:
    */
PNG_FUNCTION(void /* PRIVATE */,
875
png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message),
876 877
   PNG_NORETURN)
{
878
   const png_const_structrp png_ptr = png_nonconst_ptr;
879
   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
880 881 882 883 884 885

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

889 890 891 892
      /* 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.
       */
893
      if (image->opaque != NULL && image->opaque->error_buf != NULL)
894
         longjmp(png_control_jmp_buf(image->opaque), 1);
895 896 897

      /* Missing longjmp buffer, the following is to help debugging: */
      {
898
         size_t pos = png_safecat(image->message, (sizeof image->message), 0,
899
            "bad longjmp: ");
900 901
         png_safecat(image->message, (sizeof image->message), pos,
             error_message);
902 903 904 905 906 907 908 909 910
      }
   }

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

#ifdef PNG_WARNINGS_SUPPORTED
void /* PRIVATE */
911
png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
912
{
913
   const png_const_structrp png_ptr = png_nonconst_ptr;
914
   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
915

916
   /* A warning is only logged if there is no prior warning or error. */
917 918
   if (image->warning_or_error == 0)
   {
919 920
      png_safecat(image->message, (sizeof image->message), 0, warning_message);
      image->warning_or_error |= PNG_IMAGE_WARNING;
921 922 923 924 925
   }
}
#endif

int /* PRIVATE */
926
png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)
927
{
928
   volatile png_imagep image = image_in;
929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952
   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;

   if (result)
   {

      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. */
   if (!result)
      png_image_free(image);

   return result;
}
#endif /* SIMPLIFIED READ/WRITE */
953
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */