diff options
Diffstat (limited to 'indra/llkdu/llimagej2ckdu.cpp')
-rw-r--r-- | indra/llkdu/llimagej2ckdu.cpp | 105 |
1 files changed, 91 insertions, 14 deletions
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp index 025c77b85e..aa405362e8 100644 --- a/indra/llkdu/llimagej2ckdu.cpp +++ b/indra/llkdu/llimagej2ckdu.cpp @@ -1,4 +1,4 @@ - /** +/** * @file llimagej2ckdu.cpp * @brief This is an implementation of JPEG2000 encode/decode using Kakadu * @@ -35,16 +35,51 @@ #include "kdu_block_coding.h" -#include <stdexcept> -#include <iostream> +#include "llexception.h" +#include <boost/exception/diagnostic_information.hpp> +#include <sstream> +#include <iomanip> namespace { -// exception used to keep KDU from terminating entire program -- see comments -// in LLKDUMessageError::flush() -struct KDUError: public std::runtime_error +// Failure to load an image shouldn't crash the whole viewer. +struct KDUError: public LLContinueError { - KDUError(const std::string& msg): std::runtime_error(msg) {} + KDUError(const std::string& msg): LLContinueError(msg) {} }; + +// KDU defines int error codes as hex values, so we should log them in hex +// so we can grep KDU headers for the hex. However those hex values +// generally "happen" to encode big-endian multibyte character sequences, +// e.g. KDU_ERROR_EXCEPTION is 0x6b647545: 'kduE' +// But beware because KDU_NULL_EXCEPTION is simply 0 -- which doesn't +// preclude somebody from throwing it. +std::string report_kdu_exception(kdu_exception mb) +{ + std::ostringstream out; + // always report mb in hex + out << "kdu_exception " << std::hex << mb; + + // Also display as many chars as are encoded in the kdu_exception + // value. Make a char array; reserve 1 extra byte for nul terminator. + char bytes[sizeof(kdu_exception) + 1]; + // Back up through 'bytes' + char *bptr = bytes + sizeof(bytes); + *(--bptr) = '\0'; + while (mb) + { + // store low-order byte of mb in next-left char + *(--bptr) = char(mb & 0xFF); + // then shift mb right by one byte + mb >>= 8; + } + // did that produce any characters? + if (*bptr) + { + out << " (" << bptr << ')'; + } + + return out.str(); +} } // anonymous namespace // stream kdu_dims to std::ostream @@ -195,7 +230,7 @@ struct LLKDUMessageError : public LLKDUMessage // shutdown will NOT engage the behavior described above. if (end_of_message) { - throw KDUError("LLKDUMessageError::flush()"); + LLTHROW(KDUError("LLKDUMessageError::flush()")); } } }; @@ -309,10 +344,10 @@ void LLImageJ2CKDU::setupCodeStream(LLImageJ2C &base, bool keep_codestream, ECod { // This method is only called from methods that catch KDUError. // We want to fail the image load, not crash the viewer. - throw KDUError(STRINGIZE("Component " << idx << " dimensions " + LLTHROW(KDUError(STRINGIZE("Component " << idx << " dimensions " << other_dims << " do not match component 0 dimensions " - << dims << "!")); + << dims << "!"))); } } @@ -439,9 +474,19 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch (...) { - base.setLastError("Unknown J2C error"); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); return false; } @@ -537,9 +582,21 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco cleanupCodeStream(); return true; // done } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + base.decodeFailed(); + cleanupCodeStream(); + return true; // done + } catch (...) { - base.setLastError( "Unknown J2C error" ); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); base.decodeFailed(); cleanupCodeStream(); return true; // done @@ -728,9 +785,19 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch( ... ) { - base.setLastError( "Unknown J2C error" ); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); return false; } @@ -752,9 +819,19 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base) base.setLastError(msg.what()); return false; } + catch (kdu_exception kdu_value) + { + // KDU internally throws kdu_exception. It's possible that such an + // exception might leak out into our code. Catch kdu_exception + // specially because boost::current_exception_diagnostic_information() + // could do nothing with it. + base.setLastError(report_kdu_exception(kdu_value)); + return false; + } catch (...) { - base.setLastError( "Unknown J2C error" ); + base.setLastError("Unknown J2C error: " + + boost::current_exception_diagnostic_information()); return false; } } |