[devel] Reverted changes to call png_longjmp in contrib/gregbook

where it is not appropriate.  If mainprog->jmpbuf is used by setjmp,
then png_longjmp cannot be used.
Reversed patch to remove error handler when the jmp_buf is stored in the
main program structure, not the png_struct.
The error handler is needed because the default handler in libpng will
always use the jmp_buf in the library control structure; this is never
set.  The gregbook code is a useful example because, even though it
uses setjmp/longjmp, it shows how error handling can be implemented
using control mechanisms not directly supported by libpng.  The
technique will work correctly with mechanisms such as Microsoft
Structure Exceptions or C++ exceptions (compiler willing - note that gcc
does not by default support interworking of C and C++ error handling.)
This commit is contained in:
Glenn Randers-Pehrson
2010-06-28 20:17:48 -05:00
parent 6cac43c974
commit 73e28ef13d
9 changed files with 122 additions and 21 deletions

View File

@@ -60,6 +60,10 @@
#include "writepng.h" /* typedefs, common macros, public prototypes */
/* local prototype */
static void writepng_error_handler(png_structp png_ptr, png_const_charp msg);
void writepng_version_info(void)
@@ -86,7 +90,7 @@ int writepng_init(mainprog_info *mainprog_ptr)
/* could also replace libpng warning-handler (final NULL), but no need: */
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, mainprog_ptr,
NULL, NULL);
writepng_error_handler, NULL);
if (!png_ptr)
return 4; /* out of memory */
@@ -100,7 +104,8 @@ int writepng_init(mainprog_info *mainprog_ptr)
/* setjmp() must be called in every function that calls a PNG-writing
* libpng function, unless an alternate error handler was installed--
* but compatible error handlers must either use longjmp() themselves
* (as in this program) or exit immediately, so here we go: */
* (as in this program) or some other method to return control to
* application code, so here we go: */
if (setjmp(mainprog_ptr->jmpbuf)) {
png_destroy_write_struct(&png_ptr, &info_ptr);
@@ -355,3 +360,41 @@ void writepng_cleanup(mainprog_info *mainprog_ptr)
if (png_ptr && info_ptr)
png_destroy_write_struct(&png_ptr, &info_ptr);
}
static void writepng_error_handler(png_structp png_ptr, png_const_charp msg)
{
mainprog_info *mainprog_ptr;
/* This function, aside from the extra step of retrieving the "error
* pointer" (below) and the fact that it exists within the application
* rather than within libpng, is essentially identical to libpng's
* default error handler. The second point is critical: since both
* setjmp() and longjmp() are called from the same code, they are
* guaranteed to have compatible notions of how big a jmp_buf is,
* regardless of whether _BSD_SOURCE or anything else has (or has not)
* been defined. */
fprintf(stderr, "writepng libpng error: %s\n", msg);
fflush(stderr);
mainprog_ptr = png_get_error_ptr(png_ptr);
if (mainprog_ptr == NULL) { /* we are completely hosed now */
fprintf(stderr,
"writepng severe error: jmpbuf not recoverable; terminating.\n");
fflush(stderr);
exit(99);
}
/* Now we have our data structure we can use the information in it
* to return control to our own higher level code (all the points
* where 'setjmp' is called in this file.) This will work with other
* error handling mechanisms as well - libpng always calls png_error
* when it can proceed no further, thus, so long as the error handler
* is intercepted, application code can do its own error recovery.
*/
longjmp(mainprog_ptr->jmpbuf, 1);
}