summaryrefslogtreecommitdiff
path: root/indra/llkdu/llimagej2ckdu.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llkdu/llimagej2ckdu.cpp')
-rw-r--r--indra/llkdu/llimagej2ckdu.cpp117
1 files changed, 103 insertions, 14 deletions
diff --git a/indra/llkdu/llimagej2ckdu.cpp b/indra/llkdu/llimagej2ckdu.cpp
index 9347e51b85..9e1dfc7213 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
*
@@ -34,6 +34,53 @@
#include "kdu_block_coding.h"
+#include "llexception.h"
+#include <boost/exception/diagnostic_information.hpp>
+#include <sstream>
+#include <iomanip>
+
+namespace {
+// Failure to load an image shouldn't crash the whole viewer.
+struct KDUError: public LLContinueError
+{
+ 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
+
class kdc_flow_control {
public:
@@ -167,7 +214,7 @@ struct LLKDUMessageError : public LLKDUMessage
// exception if we want to recover from a KDU error.
if (end_of_message)
{
- throw "KDU throwing an exception";
+ LLTHROW(KDUError("LLKDUMessageError::flush()"));
}
}
};
@@ -384,14 +431,24 @@ bool LLImageJ2CKDU::initDecode(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
mTPosp->x = 0;
}
}
- catch (const char* msg)
+ catch (const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ return false;
+ }
+ catch (kdu_exception kdu_value)
{
- base.setLastError(ll_safe_string(msg));
+ // 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;
}
@@ -480,16 +537,28 @@ bool LLImageJ2CKDU::decodeImpl(LLImageJ2C &base, LLImageRaw &raw_image, F32 deco
return false;
}
}
- catch (const char* msg)
+ catch (const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ base.decodeFailed();
+ cleanupCodeStream();
+ return true; // done
+ }
+ catch (kdu_exception kdu_value)
{
- base.setLastError(ll_safe_string(msg));
+ // 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
@@ -673,14 +742,24 @@ bool LLImageJ2CKDU::encodeImpl(LLImageJ2C &base, const LLImageRaw &raw_image, co
base.updateData(); // set width, height
delete[] output_buffer;
}
- catch(const char* msg)
+ catch(const KDUError& msg)
{
- base.setLastError(ll_safe_string(msg));
+ 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;
}
@@ -697,14 +776,24 @@ bool LLImageJ2CKDU::getMetadata(LLImageJ2C &base)
setupCodeStream(base, false, MODE_FAST);
return true;
}
- catch (const char* msg)
+ catch (const KDUError& msg)
+ {
+ base.setLastError(msg.what());
+ return false;
+ }
+ catch (kdu_exception kdu_value)
{
- base.setLastError(ll_safe_string(msg));
+ // 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;
}
}