| @@ -29,7 +29,7 @@ | |||
| #ifndef JUCE_HEAPBLOCK_H_INCLUDED | |||
| #define JUCE_HEAPBLOCK_H_INCLUDED | |||
| #ifndef DOXYGEN | |||
| #if ! (defined (DOXYGEN) || JUCE_EXCEPTIONS_DISABLED) | |||
| namespace HeapBlockHelper | |||
| { | |||
| template <bool shouldThrow> | |||
| @@ -295,7 +295,11 @@ private: | |||
| void throwOnAllocationFailure() const | |||
| { | |||
| #if JUCE_EXCEPTIONS_DISABLED | |||
| jassert (data != nullptr); // without exceptions, you'll need to find a better way to handle this failure case. | |||
| #else | |||
| HeapBlockHelper::ThrowOnFail<throwOnFailure>::check (data); | |||
| #endif | |||
| } | |||
| #if ! (defined (JUCE_DLL) || defined (JUCE_DLL_BUILD)) | |||
| @@ -54,6 +54,12 @@ | |||
| #if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406 && ! defined (JUCE_COMPILER_SUPPORTS_LAMBDAS) | |||
| #define JUCE_COMPILER_SUPPORTS_LAMBDAS 1 | |||
| #endif | |||
| #ifndef JUCE_EXCEPTIONS_DISABLED | |||
| #if ! __EXCEPTIONS | |||
| #define JUCE_EXCEPTIONS_DISABLED 1 | |||
| #endif | |||
| #endif | |||
| #endif | |||
| //============================================================================== | |||
| @@ -95,6 +101,12 @@ | |||
| #define JUCE_COMPILER_SUPPORTS_ARC 1 | |||
| #endif | |||
| #ifndef JUCE_EXCEPTIONS_DISABLED | |||
| #if ! __has_feature (cxx_exceptions) | |||
| #define JUCE_EXCEPTIONS_DISABLED 1 | |||
| #endif | |||
| #endif | |||
| #endif | |||
| //============================================================================== | |||
| @@ -119,6 +131,12 @@ | |||
| #if _MSC_VER >= 1900 | |||
| #define JUCE_COMPILER_SUPPORTS_NOEXCEPT 1 | |||
| #endif | |||
| #ifndef JUCE_EXCEPTIONS_DISABLED | |||
| #if ! _CPPUNWIND | |||
| #define JUCE_EXCEPTIONS_DISABLED 1 | |||
| #endif | |||
| #endif | |||
| #endif | |||
| //============================================================================== | |||
| @@ -143,6 +143,9 @@ void UnitTestRunner::runTests (const Array<UnitTest*>& tests, int64 randomSeed) | |||
| if (shouldAbortTests()) | |||
| break; | |||
| #if JUCE_EXCEPTIONS_DISABLED | |||
| tests.getUnchecked(i)->performTest (this); | |||
| #else | |||
| try | |||
| { | |||
| tests.getUnchecked(i)->performTest (this); | |||
| @@ -151,6 +154,7 @@ void UnitTestRunner::runTests (const Array<UnitTest*>& tests, int64 randomSeed) | |||
| { | |||
| addFail ("An unhandled exception was thrown!"); | |||
| } | |||
| #endif | |||
| } | |||
| endTest(); | |||
| @@ -139,9 +139,7 @@ namespace JPEGHelpers | |||
| using jpeglibNamespace::boolean; | |||
| #endif | |||
| struct JPEGDecodingFailure {}; | |||
| static void fatalErrorHandler (j_common_ptr) { throw JPEGDecodingFailure(); } | |||
| static void fatalErrorHandler (j_common_ptr p) { *((bool*) (p->client_data)) = true; } | |||
| static void silentErrorCallback1 (j_common_ptr) {} | |||
| static void silentErrorCallback2 (j_common_ptr, int) {} | |||
| static void silentErrorCallback3 (j_common_ptr, char*) {} | |||
| @@ -264,6 +262,9 @@ Image JPEGImageFormat::decodeImage (InputStream& in) | |||
| jpegDecompStruct.src = (jpeg_source_mgr*)(jpegDecompStruct.mem->alloc_small) | |||
| ((j_common_ptr)(&jpegDecompStruct), JPOOL_PERMANENT, sizeof (jpeg_source_mgr)); | |||
| bool hasFailed = false; | |||
| jpegDecompStruct.client_data = &hasFailed; | |||
| jpegDecompStruct.src->init_source = dummyCallback1; | |||
| jpegDecompStruct.src->fill_input_buffer = jpegFill; | |||
| jpegDecompStruct.src->skip_input_data = jpegSkip; | |||
| @@ -273,67 +274,72 @@ Image JPEGImageFormat::decodeImage (InputStream& in) | |||
| jpegDecompStruct.src->next_input_byte = static_cast <const unsigned char*> (mb.getData()); | |||
| jpegDecompStruct.src->bytes_in_buffer = mb.getDataSize(); | |||
| try | |||
| { | |||
| jpeg_read_header (&jpegDecompStruct, TRUE); | |||
| jpeg_read_header (&jpegDecompStruct, TRUE); | |||
| if (! hasFailed) | |||
| { | |||
| jpeg_calc_output_dimensions (&jpegDecompStruct); | |||
| const int width = (int) jpegDecompStruct.output_width; | |||
| const int height = (int) jpegDecompStruct.output_height; | |||
| jpegDecompStruct.out_color_space = JCS_RGB; | |||
| JSAMPARRAY buffer | |||
| = (*jpegDecompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegDecompStruct, | |||
| JPOOL_IMAGE, | |||
| (JDIMENSION) width * 3, 1); | |||
| if (jpeg_start_decompress (&jpegDecompStruct)) | |||
| if (! hasFailed) | |||
| { | |||
| image = Image (Image::RGB, width, height, false); | |||
| image.getProperties()->set ("originalImageHadAlpha", false); | |||
| const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) | |||
| const int width = (int) jpegDecompStruct.output_width; | |||
| const int height = (int) jpegDecompStruct.output_height; | |||
| const Image::BitmapData destData (image, Image::BitmapData::writeOnly); | |||
| jpegDecompStruct.out_color_space = JCS_RGB; | |||
| for (int y = 0; y < height; ++y) | |||
| JSAMPARRAY buffer | |||
| = (*jpegDecompStruct.mem->alloc_sarray) ((j_common_ptr) &jpegDecompStruct, | |||
| JPOOL_IMAGE, | |||
| (JDIMENSION) width * 3, 1); | |||
| if (jpeg_start_decompress (&jpegDecompStruct) && ! hasFailed) | |||
| { | |||
| jpeg_read_scanlines (&jpegDecompStruct, buffer, 1); | |||
| image = Image (Image::RGB, width, height, false); | |||
| image.getProperties()->set ("originalImageHadAlpha", false); | |||
| const bool hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) | |||
| const uint8* src = *buffer; | |||
| uint8* dest = destData.getLinePointer (y); | |||
| const Image::BitmapData destData (image, Image::BitmapData::writeOnly); | |||
| if (hasAlphaChan) | |||
| for (int y = 0; y < height; ++y) | |||
| { | |||
| for (int i = width; --i >= 0;) | |||
| jpeg_read_scanlines (&jpegDecompStruct, buffer, 1); | |||
| if (hasFailed) | |||
| break; | |||
| const uint8* src = *buffer; | |||
| uint8* dest = destData.getLinePointer (y); | |||
| if (hasAlphaChan) | |||
| { | |||
| ((PixelARGB*) dest)->setARGB (0xff, src[0], src[1], src[2]); | |||
| ((PixelARGB*) dest)->premultiply(); | |||
| dest += destData.pixelStride; | |||
| src += 3; | |||
| for (int i = width; --i >= 0;) | |||
| { | |||
| ((PixelARGB*) dest)->setARGB (0xff, src[0], src[1], src[2]); | |||
| ((PixelARGB*) dest)->premultiply(); | |||
| dest += destData.pixelStride; | |||
| src += 3; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| for (int i = width; --i >= 0;) | |||
| else | |||
| { | |||
| ((PixelRGB*) dest)->setARGB (0xff, src[0], src[1], src[2]); | |||
| dest += destData.pixelStride; | |||
| src += 3; | |||
| for (int i = width; --i >= 0;) | |||
| { | |||
| ((PixelRGB*) dest)->setARGB (0xff, src[0], src[1], src[2]); | |||
| dest += destData.pixelStride; | |||
| src += 3; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| jpeg_finish_decompress (&jpegDecompStruct); | |||
| if (! hasFailed) | |||
| jpeg_finish_decompress (&jpegDecompStruct); | |||
| in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData()); | |||
| in.setPosition (((char*) jpegDecompStruct.src->next_input_byte) - (char*) mb.getData()); | |||
| } | |||
| } | |||
| jpeg_destroy_decompress (&jpegDecompStruct); | |||
| } | |||
| catch (...) | |||
| {} | |||
| jpeg_destroy_decompress (&jpegDecompStruct); | |||
| } | |||
| return image; | |||
| @@ -313,9 +313,9 @@ namespace PNGHelpers | |||
| struct PNGErrorStruct {}; | |||
| static void JUCE_CDECL errorCallback (png_structp, png_const_charp) | |||
| static void JUCE_CDECL errorCallback (png_structp p, png_const_charp) | |||
| { | |||
| throw PNGErrorStruct(); | |||
| longjmp (*(jmp_buf*) p->error_ptr, 1); | |||
| } | |||
| static void JUCE_CDECL warningCallback (png_structp, png_const_charp) {} | |||
| @@ -354,106 +354,102 @@ Image PNGImageFormat::decodeImage (InputStream& in) | |||
| if (png_structp pngReadStruct = png_create_read_struct (PNG_LIBPNG_VER_STRING, 0, 0, 0)) | |||
| { | |||
| try | |||
| if (png_infop pngInfoStruct = png_create_info_struct (pngReadStruct)) | |||
| { | |||
| png_infop pngInfoStruct = png_create_info_struct (pngReadStruct); | |||
| jmp_buf errorJumpBuf; | |||
| png_set_error_fn (pngReadStruct, &errorJumpBuf, PNGHelpers::errorCallback, PNGHelpers::warningCallback); | |||
| if (pngInfoStruct == nullptr) | |||
| if (setjmp (errorJumpBuf) == 0) | |||
| { | |||
| png_destroy_read_struct (&pngReadStruct, 0, 0); | |||
| return Image::null; | |||
| } | |||
| png_set_error_fn (pngReadStruct, 0, PNGHelpers::errorCallback, PNGHelpers::warningCallback); | |||
| // read the header.. | |||
| png_set_read_fn (pngReadStruct, &in, PNGHelpers::readCallback); | |||
| // read the header.. | |||
| png_set_read_fn (pngReadStruct, &in, PNGHelpers::readCallback); | |||
| png_uint_32 width = 0, height = 0; | |||
| int bitDepth = 0, colorType = 0, interlaceType; | |||
| png_uint_32 width = 0, height = 0; | |||
| int bitDepth = 0, colorType = 0, interlaceType; | |||
| png_read_info (pngReadStruct, pngInfoStruct); | |||
| png_read_info (pngReadStruct, pngInfoStruct); | |||
| png_get_IHDR (pngReadStruct, pngInfoStruct, | |||
| &width, &height, | |||
| &bitDepth, &colorType, | |||
| &interlaceType, 0, 0); | |||
| png_get_IHDR (pngReadStruct, pngInfoStruct, | |||
| &width, &height, | |||
| &bitDepth, &colorType, | |||
| &interlaceType, 0, 0); | |||
| if (bitDepth == 16) | |||
| png_set_strip_16 (pngReadStruct); | |||
| if (bitDepth == 16) | |||
| png_set_strip_16 (pngReadStruct); | |||
| if (colorType == PNG_COLOR_TYPE_PALETTE) | |||
| png_set_expand (pngReadStruct); | |||
| if (colorType == PNG_COLOR_TYPE_PALETTE) | |||
| png_set_expand (pngReadStruct); | |||
| if (bitDepth < 8) | |||
| png_set_expand (pngReadStruct); | |||
| if (bitDepth < 8) | |||
| png_set_expand (pngReadStruct); | |||
| if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) | |||
| png_set_expand (pngReadStruct); | |||
| if (png_get_valid (pngReadStruct, pngInfoStruct, PNG_INFO_tRNS)) | |||
| png_set_expand (pngReadStruct); | |||
| if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) | |||
| png_set_gray_to_rgb (pngReadStruct); | |||
| if (colorType == PNG_COLOR_TYPE_GRAY || colorType == PNG_COLOR_TYPE_GRAY_ALPHA) | |||
| png_set_gray_to_rgb (pngReadStruct); | |||
| png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER); | |||
| png_set_add_alpha (pngReadStruct, 0xff, PNG_FILLER_AFTER); | |||
| bool hasAlphaChan = (colorType & PNG_COLOR_MASK_ALPHA) != 0 | |||
| || pngInfoStruct->num_trans > 0; | |||
| bool hasAlphaChan = (colorType & PNG_COLOR_MASK_ALPHA) != 0 | |||
| || pngInfoStruct->num_trans > 0; | |||
| // Load the image into a temp buffer in the pnglib format.. | |||
| const size_t lineStride = width * 4; | |||
| HeapBlock<uint8> tempBuffer (height * lineStride); | |||
| // Load the image into a temp buffer in the pnglib format.. | |||
| const size_t lineStride = width * 4; | |||
| HeapBlock<uint8> tempBuffer (height * lineStride); | |||
| HeapBlock<png_bytep> rows (height); | |||
| for (size_t y = 0; y < height; ++y) | |||
| rows[y] = (png_bytep) (tempBuffer + lineStride * y); | |||
| HeapBlock<png_bytep> rows (height); | |||
| for (size_t y = 0; y < height; ++y) | |||
| rows[y] = (png_bytep) (tempBuffer + lineStride * y); | |||
| try | |||
| { | |||
| png_read_image (pngReadStruct, rows); | |||
| png_read_end (pngReadStruct, pngInfoStruct); | |||
| } | |||
| catch (PNGHelpers::PNGErrorStruct&) | |||
| {} | |||
| png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); | |||
| png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); | |||
| // now convert the data to a juce image format.. | |||
| image = Image (hasAlphaChan ? Image::ARGB : Image::RGB, | |||
| (int) width, (int) height, hasAlphaChan); | |||
| // now convert the data to a juce image format.. | |||
| image = Image (hasAlphaChan ? Image::ARGB : Image::RGB, | |||
| (int) width, (int) height, hasAlphaChan); | |||
| image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); | |||
| hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) | |||
| image.getProperties()->set ("originalImageHadAlpha", image.hasAlphaChannel()); | |||
| hasAlphaChan = image.hasAlphaChannel(); // (the native image creator may not give back what we expect) | |||
| const Image::BitmapData destData (image, Image::BitmapData::writeOnly); | |||
| for (int y = 0; y < (int) height; ++y) | |||
| { | |||
| const uint8* src = rows[y]; | |||
| uint8* dest = destData.getLinePointer (y); | |||
| const Image::BitmapData destData (image, Image::BitmapData::writeOnly); | |||
| if (hasAlphaChan) | |||
| for (int y = 0; y < (int) height; ++y) | |||
| { | |||
| for (int i = (int) width; --i >= 0;) | |||
| const uint8* src = rows[y]; | |||
| uint8* dest = destData.getLinePointer (y); | |||
| if (hasAlphaChan) | |||
| { | |||
| ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]); | |||
| ((PixelARGB*) dest)->premultiply(); | |||
| dest += destData.pixelStride; | |||
| src += 4; | |||
| for (int i = (int) width; --i >= 0;) | |||
| { | |||
| ((PixelARGB*) dest)->setARGB (src[3], src[0], src[1], src[2]); | |||
| ((PixelARGB*) dest)->premultiply(); | |||
| dest += destData.pixelStride; | |||
| src += 4; | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| for (int i = (int) width; --i >= 0;) | |||
| else | |||
| { | |||
| ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]); | |||
| dest += destData.pixelStride; | |||
| src += 4; | |||
| for (int i = (int) width; --i >= 0;) | |||
| { | |||
| ((PixelRGB*) dest)->setARGB (0, src[0], src[1], src[2]); | |||
| dest += destData.pixelStride; | |||
| src += 4; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| else | |||
| { | |||
| png_destroy_read_struct (&pngReadStruct, &pngInfoStruct, 0); | |||
| } | |||
| } | |||
| else | |||
| { | |||
| png_destroy_read_struct (&pngReadStruct, 0, 0); | |||
| } | |||
| catch (PNGHelpers::PNGErrorStruct&) | |||
| {} | |||
| } | |||
| return image; | |||
| @@ -74,12 +74,10 @@ ImageFileFormat* ImageFileFormat::findImageFormatForFileExtension (const File& f | |||
| //============================================================================== | |||
| Image ImageFileFormat::loadFrom (InputStream& input) | |||
| { | |||
| ImageFileFormat* const format = findImageFormatForStream (input); | |||
| if (format != nullptr) | |||
| if (ImageFileFormat* format = findImageFormatForStream (input)) | |||
| return format->decodeImage (input); | |||
| return Image::null; | |||
| return Image(); | |||
| } | |||
| Image ImageFileFormat::loadFrom (const File& file) | |||
| @@ -92,7 +90,7 @@ Image ImageFileFormat::loadFrom (const File& file) | |||
| return loadFrom (b); | |||
| } | |||
| return Image::null; | |||
| return Image(); | |||
| } | |||
| Image ImageFileFormat::loadFrom (const void* rawData, const size_t numBytes) | |||
| @@ -103,5 +101,5 @@ Image ImageFileFormat::loadFrom (const void* rawData, const size_t numBytes) | |||
| return loadFrom (stream); | |||
| } | |||
| return Image::null; | |||
| return Image(); | |||
| } | |||