From 470fcacc8118cb469c4a6af845cbe5df9b19059a Mon Sep 17 00:00:00 2001 From: wenbin1989 Date: Thu, 1 Nov 2012 21:42:24 +0800 Subject: [PATCH] Add error handler when read image data using libjpeg. Fix errors when read image using libjpeg. Fix errors when read image with broken data using libjpeg. --- cocos2dx/platform/CCImageCommon_cpp.h | 84 ++++++++++++++++++++++++--- 1 file changed, 76 insertions(+), 8 deletions(-) diff --git a/cocos2dx/platform/CCImageCommon_cpp.h b/cocos2dx/platform/CCImageCommon_cpp.h index 5b0a60e93d..7339754a0c 100644 --- a/cocos2dx/platform/CCImageCommon_cpp.h +++ b/cocos2dx/platform/CCImageCommon_cpp.h @@ -197,11 +197,64 @@ bool CCImage::initWithImageData(void * pData, return bRet; } +/* + * ERROR HANDLING: + * + * The JPEG library's standard error handler (jerror.c) is divided into + * several "methods" which you can override individually. This lets you + * adjust the behavior without duplicating a lot of code, which you might + * have to update with each future release. + * + * We override the "error_exit" method so that control is returned to the + * library's caller when a fatal error occurs, rather than calling exit() + * as the standard error_exit method does. + * + * We use C's setjmp/longjmp facility to return control. This means that the + * routine which calls the JPEG library must first execute a setjmp() call to + * establish the return point. We want the replacement error_exit to do a + * longjmp(). But we need to make the setjmp buffer accessible to the + * error_exit routine. To do this, we make a private extension of the + * standard JPEG error handler object. (If we were using C++, we'd say we + * were making a subclass of the regular error handler.) + * + * Here's the extended error handler struct: + */ + +struct my_error_mgr { + struct jpeg_error_mgr pub; /* "public" fields */ + + jmp_buf setjmp_buffer; /* for return to caller */ +}; + +typedef struct my_error_mgr * my_error_ptr; + +/* + * Here's the routine that will replace the standard error_exit method: + */ + +METHODDEF(void) +my_error_exit (j_common_ptr cinfo) +{ + /* cinfo->err really points to a my_error_mgr struct, so coerce pointer */ + my_error_ptr myerr = (my_error_ptr) cinfo->err; + + /* Always display the message. */ + /* We could postpone this until after returning, if we chose. */ + (*cinfo->err->output_message) (cinfo); + + /* Return control to the setjmp point */ + longjmp(myerr->setjmp_buffer, 1); +} + bool CCImage::_initWithJpgData(void * data, int nSize) { /* these are standard libjpeg structures for reading(decompression) */ struct jpeg_decompress_struct cinfo; - struct jpeg_error_mgr jerr; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + struct my_error_mgr jerr; /* libjpeg data structure for storing one row, that is, scanline of an image */ JSAMPROW row_pointer[1] = {0}; unsigned long location = 0; @@ -210,8 +263,18 @@ bool CCImage::_initWithJpgData(void * data, int nSize) bool bRet = false; do { - /* here we set up the standard libjpeg error handler */ - cinfo.err = jpeg_std_error( &jerr ); + /* We set up the normal JPEG error routines, then override error_exit. */ + cinfo.err = jpeg_std_error(&jerr.pub); + jerr.pub.error_exit = my_error_exit; + /* Establish the setjmp return context for my_error_exit to use. */ + if (setjmp(jerr.setjmp_buffer)) { + /* If we get here, the JPEG code has signaled an error. + * We need to clean up the JPEG object, close the input file, and return. + */ + CCLog("%d", bRet); + jpeg_destroy_decompress(&cinfo); + break; + } /* setup decompression process and source, then read JPEG header */ jpeg_create_decompress( &cinfo ); @@ -238,8 +301,8 @@ bool CCImage::_initWithJpgData(void * data, int nSize) jpeg_start_decompress( &cinfo ); /* init image info */ - m_nWidth = (short)(cinfo.image_width); - m_nHeight = (short)(cinfo.image_height); + m_nWidth = (short)(cinfo.output_width); + m_nHeight = (short)(cinfo.output_height); m_bHasAlpha = false; m_bPreMulti = false; m_nBitsPerComponent = 8; @@ -251,16 +314,21 @@ bool CCImage::_initWithJpgData(void * data, int nSize) /* now actually read the jpeg into the raw buffer */ /* read one scan line at a time */ - while( cinfo.output_scanline < cinfo.image_height ) + while( cinfo.output_scanline < cinfo.output_height ) { jpeg_read_scanlines( &cinfo, row_pointer, 1 ); - for( i=0; i