]> git.saurik.com Git - wxWidgets.git/blobdiff - src/png/pngerror.c
wxMessageBox off the main thread lost result code.
[wxWidgets.git] / src / png / pngerror.c
index 1ed9f8a2af5f398c0808789339b353b7b1911a2e..f469206ee46a115341802d05f09f46f0ebcc50e2 100644 (file)
@@ -1,8 +1,8 @@
 
 /* pngerror.c - stub functions for i/o and memory allocation
  *
- * Last changed in libpng 1.5.6 [November 3, 2011]
- * Copyright (c) 1998-2011 Glenn Randers-Pehrson
+ * Last changed in libpng 1.6.1 [March 28, 2013]
+ * Copyright (c) 1998-2013 Glenn Randers-Pehrson
  * (Version 0.96 Copyright (c) 1996, 1997 Andreas Dilger)
  * (Version 0.88 Copyright (c) 1995, 1996 Guy Eric Schalnat, Group 42, Inc.)
  *
 
 #if defined(PNG_READ_SUPPORTED) || defined(PNG_WRITE_SUPPORTED)
 
-static PNG_FUNCTION(void, png_default_error,PNGARG((png_structp png_ptr,
+static PNG_FUNCTION(void, png_default_error,PNGARG((png_const_structrp png_ptr,
     png_const_charp error_message)),PNG_NORETURN);
 
 #ifdef PNG_WARNINGS_SUPPORTED
 static void /* PRIVATE */
-png_default_warning PNGARG((png_structp png_ptr,
+png_default_warning PNGARG((png_const_structrp png_ptr,
    png_const_charp warning_message));
 #endif /* PNG_WARNINGS_SUPPORTED */
 
@@ -36,7 +36,8 @@ png_default_warning PNGARG((png_structp png_ptr,
  */
 #ifdef PNG_ERROR_TEXT_SUPPORTED
 PNG_FUNCTION(void,PNGAPI
-png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN)
+png_error,(png_const_structrp png_ptr, png_const_charp error_message),
+   PNG_NORETURN)
 {
 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
    char msg[16];
@@ -79,7 +80,8 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN)
    }
 #endif
    if (png_ptr != NULL && png_ptr->error_fn != NULL)
-      (*(png_ptr->error_fn))(png_ptr, error_message);
+      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr),
+          error_message);
 
    /* If the custom handler doesn't exist, or if it returns,
       use the default handler, which will not return. */
@@ -87,7 +89,7 @@ png_error,(png_structp png_ptr, png_const_charp error_message),PNG_NORETURN)
 }
 #else
 PNG_FUNCTION(void,PNGAPI
-png_err,(png_structp png_ptr),PNG_NORETURN)
+png_err,(png_const_structrp png_ptr),PNG_NORETURN)
 {
    /* Prior to 1.5.2 the error_fn received a NULL pointer, expressed
     * erroneously as '\0', instead of the empty string "".  This was
@@ -95,7 +97,7 @@ png_err,(png_structp png_ptr),PNG_NORETURN)
     * will crash in this case.
     */
    if (png_ptr != NULL && png_ptr->error_fn != NULL)
-      (*(png_ptr->error_fn))(png_ptr, "");
+      (*(png_ptr->error_fn))(png_constcast(png_structrp,png_ptr), "");
 
    /* If the custom handler doesn't exist, or if it returns,
       use the default handler, which will not return. */
@@ -161,7 +163,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
          case PNG_NUMBER_FORMAT_02u:
             /* Expects at least 2 digits. */
             mincount = 2;
-            /* fall through */
+            /* FALL THROUGH */
 
          case PNG_NUMBER_FORMAT_u:
             *--end = digits[number % 10];
@@ -171,7 +173,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
          case PNG_NUMBER_FORMAT_02x:
             /* This format expects at least two digits */
             mincount = 2;
-            /* fall through */
+            /* FALL THROUGH */
 
          case PNG_NUMBER_FORMAT_x:
             *--end = digits[number & 0xf];
@@ -211,7 +213,7 @@ png_format_number(png_const_charp start, png_charp end, int format,
  * png_set_error_fn() to replace the warning function at run-time.
  */
 void PNGAPI
-png_warning(png_structp png_ptr, png_const_charp warning_message)
+png_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 {
    int offset = 0;
    if (png_ptr != NULL)
@@ -230,7 +232,8 @@ png_warning(png_structp png_ptr, png_const_charp warning_message)
       }
    }
    if (png_ptr != NULL && png_ptr->warning_fn != NULL)
-      (*(png_ptr->warning_fn))(png_ptr, warning_message + offset);
+      (*(png_ptr->warning_fn))(png_constcast(png_structrp,png_ptr),
+         warning_message + offset);
    else
       png_default_warning(png_ptr, warning_message + offset);
 }
@@ -278,38 +281,43 @@ png_warning_parameter_signed(png_warning_parameters p, int number, int format,
 }
 
 void
-png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
+png_formatted_warning(png_const_structrp png_ptr, png_warning_parameters p,
    png_const_charp message)
 {
-   /* The internal buffer is just 128 bytes - enough for all our messages,
-    * overflow doesn't happen because this code checks!
+   /* 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.
     */
-   size_t i;
-   char msg[128];
-
-   for (i=0; i<(sizeof msg)-1 && *message != '\0'; ++i)
+   size_t i = 0; /* Index in the msg[] buffer: */
+   char msg[192];
+
+   /* 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')
    {
-      if (*message == '@')
+      /* '@' 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')
       {
-         int parameter = -1;
-         switch (*++message)
-         {
-            case '1':
-               parameter = 0;
-               break;
+         int parameter_char = *++message; /* Consume the '@' */
+         static const char valid_parameters[] = "123456789";
+         int parameter = 0;
 
-            case '2':
-               parameter = 1;
-               break;
-
-            case '\0':
-               continue; /* To break out of the for loop above. */
-
-            default:
-               break;
-         }
+         /* 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;
 
-         if (parameter >= 0 && parameter < PNG_WARNING_PARAMETER_COUNT)
+         /* If the parameter digit is out of range it will just get printed. */
+         if (parameter < PNG_WARNING_PARAMETER_COUNT)
          {
             /* Append this parameter */
             png_const_charp parm = p[parameter];
@@ -319,42 +327,81 @@ png_formatted_warning(png_structp png_ptr, png_warning_parameters p,
              * 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++;
+            while (i<(sizeof msg)-1 && *parm != '\0' && parm < pend)
+               msg[i++] = *parm++;
 
+            /* Consume the parameter digit too: */
             ++message;
             continue;
          }
 
          /* else not a parameter and there is a character after the @ sign; just
-          * copy that.
+          * copy that.  This is known not to be '\0' because of the test above.
           */
       }
 
       /* 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++;
+      msg[i++] = *message++;
    }
 
    /* i is always less than (sizeof msg), so: */
    msg[i] = '\0';
 
-   /* And this is the formatted message: */
+   /* 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.
+    */
    png_warning(png_ptr, msg);
 }
 #endif /* PNG_WARNINGS_SUPPORTED */
 
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 void PNGAPI
-png_benign_error(png_structp png_ptr, png_const_charp error_message)
+png_benign_error(png_const_structrp png_ptr, png_const_charp error_message)
 {
-  if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)
+   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);
+   }
+}
+
+void /* PRIVATE */
+png_app_warning(png_const_structrp png_ptr, png_const_charp error_message)
+{
+  if (png_ptr->flags & PNG_FLAG_APP_WARNINGS_WARN)
      png_warning(png_ptr, error_message);
   else
      png_error(png_ptr, error_message);
 }
-#endif
+
+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);
+}
+#endif /* BENIGN_ERRORS */
 
 /* These utilities are used internally to build an error message that relates
  * to the current chunk.  The chunk name comes from png_ptr->chunk_name,
@@ -368,10 +415,10 @@ static PNG_CONST char png_digit[16] = {
    'A', 'B', 'C', 'D', 'E', 'F'
 };
 
-#define PNG_MAX_ERROR_TEXT 64
+#define PNG_MAX_ERROR_TEXT 196 /* Currently limited be profile_error in png.c */
 #if defined(PNG_WARNINGS_SUPPORTED) || defined(PNG_ERROR_TEXT_SUPPORTED)
 static void /* PRIVATE */
-png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
+png_format_buffer(png_const_structrp png_ptr, png_charp buffer, png_const_charp
     error_message)
 {
    png_uint_32 chunk_name = png_ptr->chunk_name;
@@ -417,7 +464,7 @@ png_format_buffer(png_structp png_ptr, png_charp buffer, png_const_charp
 
 #if defined(PNG_READ_SUPPORTED) && defined(PNG_ERROR_TEXT_SUPPORTED)
 PNG_FUNCTION(void,PNGAPI
-png_chunk_error,(png_structp png_ptr, png_const_charp error_message),
+png_chunk_error,(png_const_structrp png_ptr, png_const_charp error_message),
    PNG_NORETURN)
 {
    char msg[18+PNG_MAX_ERROR_TEXT];
@@ -434,7 +481,7 @@ png_chunk_error,(png_structp png_ptr, png_const_charp error_message),
 
 #ifdef PNG_WARNINGS_SUPPORTED
 void PNGAPI
-png_chunk_warning(png_structp png_ptr, png_const_charp warning_message)
+png_chunk_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 {
    char msg[18+PNG_MAX_ERROR_TEXT];
    if (png_ptr == NULL)
@@ -451,7 +498,8 @@ png_chunk_warning(png_structp png_ptr, png_const_charp warning_message)
 #ifdef PNG_READ_SUPPORTED
 #ifdef PNG_BENIGN_ERRORS_SUPPORTED
 void PNGAPI
-png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message)
+png_chunk_benign_error(png_const_structrp png_ptr, png_const_charp
+    error_message)
 {
    if (png_ptr->flags & PNG_FLAG_BENIGN_ERRORS_WARN)
       png_chunk_warning(png_ptr, error_message);
@@ -462,16 +510,51 @@ png_chunk_benign_error(png_structp png_ptr, png_const_charp error_message)
 #endif
 #endif /* PNG_READ_SUPPORTED */
 
+void /* PRIVATE */
+png_chunk_report(png_const_structrp png_ptr, png_const_charp message, int error)
+{
+   /* 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
+}
+
 #ifdef PNG_ERROR_TEXT_SUPPORTED
 #ifdef PNG_FLOATING_POINT_SUPPORTED
 PNG_FUNCTION(void,
-png_fixed_error,(png_structp png_ptr, png_const_charp name),PNG_NORETURN)
+png_fixed_error,(png_const_structrp png_ptr, png_const_charp name),PNG_NORETURN)
 {
 #  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);
+   memcpy(msg, fixed_message, fixed_message_ln);
    iin = 0;
    if (name != NULL) while (iin < (PNG_MAX_ERROR_TEXT-1) && name[iin] != 0)
    {
@@ -489,14 +572,111 @@ png_fixed_error,(png_structp png_ptr, png_const_charp name),PNG_NORETURN)
  * otherwise it is necessary for png_default_error to be overridden.
  */
 jmp_buf* PNGAPI
-png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn,
+png_set_longjmp_fn(png_structrp png_ptr, png_longjmp_ptr longjmp_fn,
     size_t jmp_buf_size)
 {
-   if (png_ptr == NULL || jmp_buf_size != png_sizeof(jmp_buf))
+   /* 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)
       return NULL;
 
+   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.
+    */
    png_ptr->longjmp_fn = longjmp_fn;
-   return &png_ptr->longjmp_buffer;
+   return png_ptr->jmp_buf_ptr;
+}
+
+void /* PRIVATE */
+png_free_jmpbuf(png_structrp png_ptr)
+{
+   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;
+   }
 }
 #endif
 
@@ -506,7 +686,7 @@ png_set_longjmp_fn(png_structp png_ptr, png_longjmp_ptr longjmp_fn,
  * error function pointer in png_set_error_fn().
  */
 static PNG_FUNCTION(void /* PRIVATE */,
-png_default_error,(png_structp png_ptr, png_const_charp error_message),
+png_default_error,(png_const_structrp png_ptr, png_const_charp error_message),
    PNG_NORETURN)
 {
 #ifdef PNG_CONSOLE_IO_SUPPORTED
@@ -553,23 +733,13 @@ png_default_error,(png_structp png_ptr, png_const_charp error_message),
 }
 
 PNG_FUNCTION(void,PNGAPI
-png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN)
+png_longjmp,(png_const_structrp png_ptr, int val),PNG_NORETURN)
 {
 #ifdef PNG_SETJMP_SUPPORTED
-   if (png_ptr && png_ptr->longjmp_fn)
-   {
-#  ifdef USE_FAR_KEYWORD
-      {
-         jmp_buf tmp_jmpbuf;
-         png_memcpy(tmp_jmpbuf, png_ptr->longjmp_buffer, png_sizeof(jmp_buf));
-         png_ptr->longjmp_fn(tmp_jmpbuf, val);
-      }
-
-#  else
-   png_ptr->longjmp_fn(png_ptr->longjmp_buffer, val);
-#  endif
-   }
+   if (png_ptr && png_ptr->longjmp_fn && png_ptr->jmp_buf_ptr)
+      png_ptr->longjmp_fn(*png_ptr->jmp_buf_ptr, val);
 #endif
+
    /* Here if not setjmp support or if png_ptr is null. */
    PNG_ABORT();
 }
@@ -581,7 +751,7 @@ png_longjmp,(png_structp png_ptr, int val),PNG_NORETURN)
  * not used, but it is passed in case it may be useful.
  */
 static void /* PRIVATE */
-png_default_warning(png_structp png_ptr, png_const_charp warning_message)
+png_default_warning(png_const_structrp png_ptr, png_const_charp warning_message)
 {
 #ifdef PNG_CONSOLE_IO_SUPPORTED
 #  ifdef PNG_ERROR_NUMBERS_SUPPORTED
@@ -628,10 +798,10 @@ png_default_warning(png_structp png_ptr, png_const_charp warning_message)
 /* This function is called when the application wants to use another method
  * of handling errors and warnings.  Note that the error function MUST NOT
  * return to the calling routine or serious problems will occur.  The return
- * method used in the default routine calls longjmp(png_ptr->longjmp_buffer, 1)
+ * method used in the default routine calls longjmp(png_ptr->jmp_buf_ptr, 1)
  */
 void PNGAPI
-png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
+png_set_error_fn(png_structrp png_ptr, png_voidp error_ptr,
     png_error_ptr error_fn, png_error_ptr warning_fn)
 {
    if (png_ptr == NULL)
@@ -652,7 +822,7 @@ png_set_error_fn(png_structp png_ptr, png_voidp error_ptr,
  * pointer before png_write_destroy and png_read_destroy are called.
  */
 png_voidp PNGAPI
-png_get_error_ptr(png_const_structp png_ptr)
+png_get_error_ptr(png_const_structrp png_ptr)
 {
    if (png_ptr == NULL)
       return NULL;
@@ -663,7 +833,7 @@ png_get_error_ptr(png_const_structp png_ptr)
 
 #ifdef PNG_ERROR_NUMBERS_SUPPORTED
 void PNGAPI
-png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode)
+png_set_strip_error_numbers(png_structrp png_ptr, png_uint_32 strip_mode)
 {
    if (png_ptr != NULL)
    {
@@ -673,4 +843,90 @@ png_set_strip_error_numbers(png_structp png_ptr, png_uint_32 strip_mode)
    }
 }
 #endif
+
+#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 */,
+png_safe_error,(png_structp png_nonconst_ptr, png_const_charp error_message),
+   PNG_NORETURN)
+{
+   const png_const_structrp png_ptr = png_nonconst_ptr;
+   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
+
+   /* 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 |= PNG_IMAGE_ERROR;
+
+      /* 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.
+       */
+      if (image->opaque != NULL && image->opaque->error_buf != NULL)
+         longjmp(png_control_jmp_buf(image->opaque), 1);
+
+      /* 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 */
+png_safe_warning(png_structp png_nonconst_ptr, png_const_charp warning_message)
+{
+   const png_const_structrp png_ptr = png_nonconst_ptr;
+   png_imagep image = png_voidcast(png_imagep, png_ptr->error_ptr);
+
+   /* A warning is only logged if there is no prior warning or error. */
+   if (image->warning_or_error == 0)
+   {
+      png_safecat(image->message, (sizeof image->message), 0, warning_message);
+      image->warning_or_error |= PNG_IMAGE_WARNING;
+   }
+}
+#endif
+
+int /* PRIVATE */
+png_safe_execute(png_imagep image_in, int (*function)(png_voidp), png_voidp arg)
+{
+   volatile png_imagep image = image_in;
+   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 */
 #endif /* PNG_READ_SUPPORTED || PNG_WRITE_SUPPORTED */