pngerror.c 24.7 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.0 [(PENDING RELEASE)]
5
 * Copyright (c) 1998-2011 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
      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), error_message);
G
Guy Schalnat 已提交
84

85 86
   /* If the custom handler doesn't exist, or if it returns,
      use the default handler, which will not return. */
87
   png_default_error(png_ptr, error_message);
G
Guy Schalnat 已提交
88
}
89
#else
90
PNG_FUNCTION(void,PNGAPI
91
png_err,(png_const_structrp png_ptr),PNG_NORETURN)
92
{
93 94 95 96
   /* 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.
97
    */
98
   if (png_ptr != NULL && png_ptr->error_fn != NULL)
99
      (*(png_ptr->error_fn))(png_ptr, "");
100 101 102

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

107 108 109 110 111 112 113 114 115
/* 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)
   {
116 117 118
      if (string != NULL)
         while (*string != '\0' && pos < bufsize-1)
           buffer[pos++] = *string++;
119 120 121 122 123 124 125

      buffer[pos] = '\0';
   }

   return pos;
}

126
#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_TIME_RFC1123_SUPPORTED)
127 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 166 167 168 169 170 171 172 173 174 175 176 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
/* 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;
            /* fall through */

         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;
            /* fall through */

         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

208
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
209
/* This function is called whenever there is a non-fatal error.  This function
210 211 212 213
 * 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.
 */
214
void PNGAPI
215
png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
G
Guy Schalnat 已提交
216
{
217
   int offset = 0;
218 219
   if (png_ptr != NULL)
   {
220
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
221
   if (png_ptr->flags&
222
       (PNG_FLAG_STRIP_ERROR_NUMBERS|PNG_FLAG_STRIP_ERROR_TEXT))
223
#endif
224 225 226 227 228
      {
         if (*warning_message == PNG_LITERAL_SHARP)
         {
            for (offset = 1; offset < 15; offset++)
               if (warning_message[offset] == ' ')
229
                  break;
230 231
         }
      }
232
   }
233
   if (png_ptr != NULL && png_ptr->warning_fn != NULL)
234
      (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
235
         warning_message + offset);
G
Guy Schalnat 已提交
236
   else
237
      png_default_warning(png_ptr, warning_message + offset);
G
Guy Schalnat 已提交
238
}
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

/* 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
283
png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,
284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347
   png_const_charp message)
{
   /* The internal buffer is just 128 bytes - enough for all our messages,
    * overflow doesn't happen because this code checks!
    */
   size_t i;
   char msg[128];

   for (i=0; i<(sizeof msg)-1 && *message != '\0'; ++i)
   {
      if (*message == '@')
      {
         int parameter = -1;
         switch (*++message)
         {
            case '1':
               parameter = 0;
               break;

            case '2':
               parameter = 1;
               break;

            case '\0':
               continue; /* To break out of the for loop above. */

            default:
               break;
         }

         if (parameter >= 0 && parameter < PNG_WARNING_PARAMETER_COUNT)
         {
            /* 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':
             */
            for (; i<(sizeof msg)-1 && parm != '\0' && parm < pend; ++i)
               msg[i] = *parm++;

            ++message;
            continue;
         }

         /* else not a parameter and there is a character after the @ sign; just
          * copy that.
          */
      }

      /* 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.
       */
      msg[i] = *message++;
   }

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

   /* And this is the formatted message: */
   png_warning(png_ptr, msg);
}
348
#endif /* PNG_WARNINGS_SUPPORTED */
G
Guy Schalnat 已提交
349

350 351
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
void PNGAPI
352
png_benign_error(png_const_structrp png_ptr, png_const_charp error_message)
353
{
354
  if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)
355
     png_warning(png_ptr, error_message);
356
  else
357
     png_error(png_ptr, error_message);
358 359 360
}
#endif

361
/* These utilities are used internally to build an error message that relates
362 363 364 365 366
 * 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.
 */
367
#define isnonalpha(c) ((c) < 65 || (c) > 122 || ((c) > 90 && (c) < 97))
368
static PNG_CONST char png_digit[16] = {
369 370 371
   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
   'A', 'B', 'C', 'D', 'E', 'F'
};
372

373
#define PNG_MAX_ERROR_TEXT 64
374
#if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)
375
static void /* PRIVATE */
376
png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp
377
    error_message)
378
{
379 380
   png_uint_32 chunk_name = png_ptr->chunk_name;
   int iout = 0, ishift = 24;
381

382
   while (ishift >= 0)
383
   {
384 385 386
      int c = (int)(chunk_name >> ishift) & 0xff;

      ishift -= 8;
387 388
      if (isnonalpha(c))
      {
389
         buffer[iout++] = PNG_LITERAL_LEFT_SQUARE_BRACKET;
390
         buffer[iout++] = png_digit[(c & 0xf0) >> 4];
391
         buffer[iout++] = png_digit[c & 0x0f];
392
         buffer[iout++] = PNG_LITERAL_RIGHT_SQUARE_BRACKET;
393
      }
394

395 396
      else
      {
397
         buffer[iout++] = (char)c;
398 399 400
      }
   }

401
   if (error_message == NULL)
402
      buffer[iout] = '\0';
403

404 405
   else
   {
406 407
      int iin = 0;

408 409
      buffer[iout++] = ':';
      buffer[iout++] = ' ';
410 411 412 413 414 415

      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';
416 417
   }
}
418
#endif /* PNG_WARNINGS_SUPPORTED || PNG_ERROR_TEXT_SUPPORTED */
419

420
#if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
421
PNG_FUNCTION(void,PNGAPI
422
png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),
423
   PNG_NORETURN)
424
{
425
   char msg[18+PNG_MAX_ERROR_TEXT];
426
   if (png_ptr == NULL)
427
      png_error(png_ptr, error_message);
428

429 430
   else
   {
431 432
      png_format_buffer(png_ptr, msg, error_message);
      png_error(png_ptr, msg);
433
   }
434
}
435
#endif /* PNG_READ_SUPPORTED && PNG_ERROR_TEXT_SUPPORTED */
436

437
#ifdef PNG_WARNINGS_SUPPORTED
438
void PNGAPI
439
png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)
440
{
441
   char msg[18+PNG_MAX_ERROR_TEXT];
442
   if (png_ptr == NULL)
443
      png_warning(png_ptr, warning_message);
444

445 446
   else
   {
447 448
      png_format_buffer(png_ptr, msg, warning_message);
      png_warning(png_ptr, msg);
449
   }
450
}
451
#endif /* PNG_WARNINGS_SUPPORTED */
452

453
#ifdef PNG_READ_SUPPORTED
454 455
#ifdef PNG_BENIGN_ERRORS_SUPPORTED
void PNGAPI
456
png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp error_message)
457
{
458 459
   if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)
      png_chunk_warning(png_ptr, error_message);
460

461 462
   else
      png_chunk_error(png_ptr, error_message);
463 464
}
#endif
465
#endif /* PNG_READ_SUPPORTED */
466

G
[devel]  
Glenn Randers-Pehrson 已提交
467 468
#ifdef PNG_ERROR_TEXT_SUPPORTED
#ifdef PNG_FLOATING_POINT_SUPPORTED
469
PNG_FUNCTION(void,
470
png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
G
[devel]  
Glenn Randers-Pehrson 已提交
471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488
{
#  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];
   png_memcpy(msg, fixed_message, fixed_message_ln);
   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

489
#ifdef PNG_SETJMP_SUPPORTED
490 491
/* This API only exists if ANSI-C style error handling is used,
 * otherwise it is necessary for png_default_error to be overridden.
492 493
 */
jmp_buf* PNGAPI
494
png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,
495
    size_t jmp_buf_size)
496
{
497 498 499 500 501 502 503 504 505 506 507
   /* 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)
508 509
      return NULL;

510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557
   if (png_ptr->jmp_buf_ptr == NULL)
   {
      png_ptr->jmp_buf_size = 0; /* not allocated */

      if (jmp_buf_size <= sizeof png_ptr->jmp_buf_local)
         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)
      {
         size = sizeof png_ptr->jmp_buf_local;
         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.
    */
558
   png_ptr->longjmp_fn = longjmp_fn;
559 560 561 562
   return png_ptr->jmp_buf_ptr;
}

void /* PRIVATE */
563
png_free_jmpbuf(png_structrp png_ptr)
564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
{
   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;
   }
599 600 601
}
#endif

G
Guy Schalnat 已提交
602
/* This is the default error handling function.  Note that replacements for
603 604 605 606
 * 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().
 */
607
static PNG_FUNCTION(void /* PRIVATE */,
608
png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
609
   PNG_NORETURN)
G
Guy Schalnat 已提交
610
{
611
#ifdef PNG_CONSOLE_IO_SUPPORTED
612
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
613
   /* Check on NULL only added in 1.5.4 */
614
   if (error_message != NULL && *error_message == PNG_LITERAL_SHARP)
615
   {
616 617 618 619 620
      /* Strip "#nnnn " from beginning of error message. */
      int offset;
      char error_number[16];
      for (offset = 0; offset<15; offset++)
      {
621 622
         error_number[offset] = error_message[offset + 1];
         if (error_message[offset] == ' ')
623 624
            break;
      }
625

626 627 628 629 630 631 632
      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);
      }
633

634 635 636 637 638 639
      else
      {
         fprintf(stderr, "libpng error: %s, offset=%d",
             error_message, offset);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
640 641 642
   }
   else
#endif
643
   {
644 645
      fprintf(stderr, "libpng error: %s", error_message ? error_message :
         "undefined");
646 647
      fprintf(stderr, PNG_STRING_NEWLINE);
   }
648
#else
649
   PNG_UNUSED(error_message) /* Make compiler happy */
650
#endif
651
   png_longjmp(png_ptr, 1);
652
}
G
Guy Schalnat 已提交
653

654
PNG_FUNCTION(void,PNGAPI
655
png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
656
{
657
#ifdef PNG_SETJMP_SUPPORTED
658 659
   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 已提交
660
#endif
661

662 663
   /* Here if not setjmp support or if png_ptr is null. */
   PNG_ABORT();
G
Guy Schalnat 已提交
664 665
}

666
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
667
/* This function is called when there is a warning, but the library thinks
668
 * it can continue anyway.  Replacement functions don't have to do anything
669
 * here if you don't want them to.  In the default configuration, png_ptr is
670 671
 * not used, but it is passed in case it may be useful.
 */
672
static void /* PRIVATE */
673
png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
G
Guy Schalnat 已提交
674
{
675
#ifdef PNG_CONSOLE_IO_SUPPORTED
676
#  ifdef PNG_ERROR_NUMBERS_SUPPORTED
677
   if (*warning_message == PNG_LITERAL_SHARP)
678
   {
679 680 681 682 683 684
      int offset;
      char warning_number[16];
      for (offset = 0; offset < 15; offset++)
      {
         warning_number[offset] = warning_message[offset + 1];
         if (warning_message[offset] == ' ')
685
            break;
686
      }
687

688 689 690 691 692 693 694
      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);
      }
695

696 697 698 699 700 701
      else
      {
         fprintf(stderr, "libpng warning: %s",
             warning_message);
         fprintf(stderr, PNG_STRING_NEWLINE);
      }
702 703 704
   }
   else
#  endif
705

706
   {
707 708
      fprintf(stderr, "libpng warning: %s", warning_message);
      fprintf(stderr, PNG_STRING_NEWLINE);
709
   }
710
#else
711
   PNG_UNUSED(warning_message) /* Make compiler happy */
G
Guy Schalnat 已提交
712
#endif
713
   PNG_UNUSED(png_ptr) /* Make compiler happy */
G
Guy Schalnat 已提交
714
}
715
#endif /* PNG_WARNINGS_SUPPORTED */
G
Guy Schalnat 已提交
716

G
Guy Schalnat 已提交
717
/* This function is called when the application wants to use another method
718 719
 * of handling errors and warnings.  Note that the error function MUST NOT
 * return to the calling routine or serious problems will occur.  The return
720
 * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)
721
 */
722
void PNGAPI
723
png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,
724
    png_error_ptr error_fn, png_error_ptr warning_fn)
G
Guy Schalnat 已提交
725
{
726 727
   if (png_ptr == NULL)
      return;
728

G
Guy Schalnat 已提交
729
   png_ptr->error_ptr = error_ptr;
G
Guy Schalnat 已提交
730
   png_ptr->error_fn = error_fn;
731
#ifdef PNG_WARNINGS_SUPPORTED
G
Guy Schalnat 已提交
732
   png_ptr->warning_fn = warning_fn;
733 734 735
#else
   PNG_UNUSED(warning_fn)
#endif
G
Guy Schalnat 已提交
736 737 738
}


G
Guy Schalnat 已提交
739
/* This function returns a pointer to the error_ptr associated with the user
740 741 742
 * functions.  The application should free any memory associated with this
 * pointer before png_write_destroy and png_read_destroy are called.
 */
743
png_voidp PNGAPI
744
png_get_error_ptr(png_const_structrp png_ptr)
G
Guy Schalnat 已提交
745
{
746 747
   if (png_ptr == NULL)
      return NULL;
748

749
   return ((png_voidp)png_ptr->error_ptr);
G
Guy Schalnat 已提交
750 751 752
}


753
#ifdef PNG_ERROR_NUMBERS_SUPPORTED
754
void PNGAPI
755
png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
756
{
757
   if (png_ptr != NULL)
758
   {
759 760 761
      png_ptr->flags &=
         ((~(PNG_FLAG_STRIP_ERROR_NUMBERS |
         PNG_FLAG_STRIP_ERROR_TEXT))&strip_mode);
762 763 764
   }
}
#endif
765 766 767 768 769 770 771 772

#if defined PNG_SIMPLIFIED_READ_SUPPORTED ||\
   defined PNG_SIMPLIFIED_WRITE_SUPPORTED
   /* 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 */,
773
png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message),
774 775
   PNG_NORETURN)
{
776
   const png_const_structrp png_ptr = png_nonconst_ptr;
777
   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
778 779 780 781 782 783 784 785 786

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

787 788 789 790
      /* 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.
       */
791
      if (image->opaque != NULL && image->opaque->error_buf != NULL)
792
         longjmp(png_control_jmp_buf(image->opaque), 1);
793 794 795 796 797 798 799 800 801 802 803 804 805 806 807

      /* Missing longjmp buffer, the following is to help debugging: */
      {
         size_t pos = png_safecat(image->message, sizeof image->message, 0,
            "bad longjmp: ");
         png_safecat(image->message, sizeof image->message, pos, error_message);
      }
   }

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

#ifdef PNG_WARNINGS_SUPPORTED
void /* PRIVATE */
808
png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
809
{
810
   const png_const_structrp png_ptr = png_nonconst_ptr;
811
   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
812

813
   /* A warning is only logged if there is no prior warning or error. */
814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849
   if (image->warning_or_error == 0)
   {
      png_safecat(image->message, sizeof image->message, 0, warning_message);
      image->warning_or_error = 2;
   }
}
#endif

int /* PRIVATE */
png_safe_execute(png_imagep imageIn, int (*function)(png_voidp), png_voidp arg)
{
   volatile png_imagep image = imageIn;
   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 */
850
#endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */