summaryrefslogtreecommitdiff
path: root/thirdparty/tinyexr
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/tinyexr')
-rw-r--r--thirdparty/tinyexr/tinyexr.h1481
1 files changed, 955 insertions, 526 deletions
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
index 107c22ffb3..b3a7ee00c2 100644
--- a/thirdparty/tinyexr/tinyexr.h
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2014 - 2017, Syoyo Fujita
+Copyright (c) 2014 - 2018, Syoyo Fujita and many contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
@@ -115,6 +115,9 @@ extern "C" {
#define TINYEXR_ERROR_CANT_OPEN_FILE (-6)
#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-7)
#define TINYEXR_ERROR_INVALID_HEADER (-8)
+#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-9)
+#define TINYEXR_ERROR_CANT_WRITE_FILE (-10)
+#define TINYEXR_ERROR_SERIALZATION_FAILED (-11)
// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
@@ -123,7 +126,8 @@ extern "C" {
#define TINYEXR_PIXELTYPE_HALF (1)
#define TINYEXR_PIXELTYPE_FLOAT (2)
-#define TINYEXR_MAX_ATTRIBUTES (128)
+#define TINYEXR_MAX_HEADER_ATTRIBUTES (1024)
+#define TINYEXR_MAX_CUSTOM_ATTRIBUTES (128)
#define TINYEXR_COMPRESSIONTYPE_NONE (0)
#define TINYEXR_COMPRESSIONTYPE_RLE (1)
@@ -205,7 +209,8 @@ typedef struct _EXRHeader {
// Custom attributes(exludes required attributes(e.g. `channels`,
// `compression`, etc)
int num_custom_attributes;
- EXRAttribute custom_attributes[TINYEXR_MAX_ATTRIBUTES];
+ EXRAttribute *custom_attributes; // array of EXRAttribute. size =
+ // `num_custom_attributes`.
EXRChannelInfo *channels; // [num_channels]
@@ -276,9 +281,12 @@ extern int LoadEXR(float **out_rgba, int *width, int *height,
// Save image as fp16(HALF) format when `save_as_fp16` is positive non-zero
// value.
// Save image as fp32(FLOAT) format when `save_as_fp16` is 0.
+// Use ZIP compression by default.
+// Returns negative value and may set error string in `err` when there's an
+// error
extern int SaveEXR(const float *data, const int width, const int height,
const int components, const int save_as_fp16,
- const char *filename);
+ const char *filename, const char **err);
// Initialize EXRHeader struct
extern void InitEXRHeader(EXRHeader *exr_header);
@@ -292,6 +300,9 @@ extern int FreeEXRHeader(EXRHeader *exr_header);
// Free's internal data of EXRImage struct
extern int FreeEXRImage(EXRImage *exr_image);
+// Free's error message
+extern void FreeEXRErrorMessage(const char *msg);
+
// Parse EXR version header of a file.
extern int ParseEXRVersionFromFile(EXRVersion *version, const char *filename);
@@ -300,10 +311,14 @@ extern int ParseEXRVersionFromMemory(EXRVersion *version,
const unsigned char *memory, size_t size);
// Parse single-part OpenEXR header from a file and initialize `EXRHeader`.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRHeaderFromFile(EXRHeader *header, const EXRVersion *version,
const char *filename, const char **err);
// Parse single-part OpenEXR header from a memory and initialize `EXRHeader`.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRHeaderFromMemory(EXRHeader *header,
const EXRVersion *version,
const unsigned char *memory, size_t size,
@@ -311,6 +326,8 @@ extern int ParseEXRHeaderFromMemory(EXRHeader *header,
// Parse multi-part OpenEXR headers from a file and initialize `EXRHeader*`
// array.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
int *num_headers,
const EXRVersion *version,
@@ -319,6 +336,8 @@ extern int ParseEXRMultipartHeaderFromFile(EXRHeader ***headers,
// Parse multi-part OpenEXR headers from a memory and initialize `EXRHeader*`
// array
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
int *num_headers,
const EXRVersion *version,
@@ -330,6 +349,8 @@ extern int ParseEXRMultipartHeaderFromMemory(EXRHeader ***headers,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
const char *filename, const char **err);
@@ -339,6 +360,8 @@ extern int LoadEXRImageFromFile(EXRImage *image, const EXRHeader *header,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
const unsigned char *memory,
const size_t size, const char **err);
@@ -349,6 +372,8 @@ extern int LoadEXRImageFromMemory(EXRImage *image, const EXRHeader *header,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRMultipartImageFromFile(EXRImage *images,
const EXRHeader **headers,
unsigned int num_parts,
@@ -361,6 +386,8 @@ extern int LoadEXRMultipartImageFromFile(EXRImage *images,
// Application can free EXRImage using `FreeEXRImage`
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
const EXRHeader **headers,
unsigned int num_parts,
@@ -370,15 +397,19 @@ extern int LoadEXRMultipartImageFromMemory(EXRImage *images,
// Saves multi-channel, single-frame OpenEXR image to a file.
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int SaveEXRImageToFile(const EXRImage *image,
const EXRHeader *exr_header, const char *filename,
const char **err);
// Saves multi-channel, single-frame OpenEXR image to a memory.
// Image is compressed using EXRImage.compression value.
-// Return the number of bytes if succes.
-// Returns negative value and may set error string in `err` when there's an
-// error
+// Return the number of bytes if success.
+// Return zero and will set error string in `err` when there's an
+// error.
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern size_t SaveEXRImageToMemory(const EXRImage *image,
const EXRHeader *exr_header,
unsigned char **memory, const char **err);
@@ -387,6 +418,8 @@ extern size_t SaveEXRImageToMemory(const EXRImage *image,
// Application must free memory of variables in DeepImage(image, offset_table)
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
const char **err);
@@ -409,6 +442,8 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
// RGB(A) channels.
// Returns negative value and may set error string in `err` when there's an
// error
+// When there was an error message, Application must free `err` with
+// FreeEXRErrorMessage()
extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
const unsigned char *memory, size_t size,
const char **err);
@@ -428,8 +463,10 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#include <cstdio>
#include <cstdlib>
#include <cstring>
+#include <iostream>
#include <sstream>
+#include <limits>
#include <string>
#include <vector>
@@ -486,15 +523,29 @@ namespace miniz {
#pragma clang diagnostic ignored "-Wc++11-extensions"
#pragma clang diagnostic ignored "-Wconversion"
#pragma clang diagnostic ignored "-Wunused-function"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#pragma clang diagnostic ignored "-Wundef"
+
#if __has_warning("-Wcomma")
#pragma clang diagnostic ignored "-Wcomma"
#endif
+
#if __has_warning("-Wmacro-redefined")
#pragma clang diagnostic ignored "-Wmacro-redefined"
#endif
+
#if __has_warning("-Wcast-qual")
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
+
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#if __has_warning("-Wtautological-constant-compare")
+#pragma clang diagnostic ignored "-Wtautological-constant-compare"
+#endif
+
#endif
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
@@ -2900,9 +2951,8 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
tinfl_status status = tinfl_decompress(
&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
(mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
- &dst_buf_size,
- (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+ &dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
MZ_FREE(pBuf);
*pOut_len = 0;
@@ -3549,10 +3599,9 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) {
mz_uint saved_bit_buf, saved_bits_in;
mz_uint8 *pSaved_output_buf;
mz_bool comp_block_succeeded = MZ_FALSE;
- int n,
- use_raw_block =
- ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
- (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
+ int n, use_raw_block =
+ ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) &&
+ (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
mz_uint8 *pOutput_buf_start =
((d->m_pPut_buf_func == NULL) &&
((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE))
@@ -3582,9 +3631,8 @@ static int tdefl_flush_block(tdefl_compressor *d, int flush) {
if (!use_raw_block)
comp_block_succeeded =
- tdefl_compress_block(d,
- (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
- (d->m_total_lz_bytes < 48));
+ tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) ||
+ (d->m_total_lz_bytes < 48));
// If the block gets expanded, forget the current contents of the output
// buffer and send a raw block instead.
@@ -4388,9 +4436,8 @@ mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits,
// C and C99, so no big deal)
#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
// 'int', possible loss of data
-#pragma warning( \
- disable : 4267) // 'argument': conversion from '__int64' to 'int',
- // possible loss of data
+#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
+ // 'int', possible loss of data
#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
// deprecated. Instead, use the ISO C and C++
// conformant name: _strdup.
@@ -5229,10 +5276,9 @@ mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index,
n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
pStat->m_comment_size = n;
- memcpy(pStat->m_comment,
- p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
- MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
- MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
+ memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE +
+ MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) +
+ MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
n);
pStat->m_comment[n] = '\0';
@@ -6894,7 +6940,7 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
#ifdef _MSC_VER
#pragma warning(pop)
#endif
-}
+} // namespace miniz
#else
// Reuse MINIZ_LITTE_ENDIAN macro
@@ -6919,8 +6965,26 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
// return bint.c[0] == 1;
//}
+static void SetErrorMessage(const std::string &msg, const char **err) {
+ if (err) {
+#ifdef _WIN32
+ (*err) = _strdup(msg.c_str());
+#else
+ (*err) = strdup(msg.c_str());
+#endif
+ }
+}
+
static const int kEXRVersionSize = 8;
+static void cpy2(unsigned short *dst_val, const unsigned short *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+}
+
static void swap2(unsigned short *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -6934,6 +6998,36 @@ static void swap2(unsigned short *val) {
#endif
}
+static void cpy4(int *dst_val, const int *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
+static void cpy4(unsigned int *dst_val, const unsigned int *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
+static void cpy4(float *dst_val, const float *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+}
+
static void swap4(unsigned int *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -6949,6 +7043,22 @@ static void swap4(unsigned int *val) {
#endif
}
+#if 0
+static void cpy8(tinyexr::tinyexr_uint64 *dst_val, const tinyexr::tinyexr_uint64 *src_val) {
+ unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
+ const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
+
+ dst[0] = src[0];
+ dst[1] = src[1];
+ dst[2] = src[2];
+ dst[3] = src[3];
+ dst[4] = src[4];
+ dst[5] = src[5];
+ dst[6] = src[6];
+ dst[7] = src[7];
+}
+#endif
+
static void swap8(tinyexr::tinyexr_uint64 *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -7084,6 +7194,15 @@ static FP16 float_to_half_full(FP32 f) {
// #define IMF_B44_COMPRESSION 6
// #define IMF_B44A_COMPRESSION 7
+#ifdef __clang__
+#pragma clang diagnostic push
+
+#if __has_warning("-Wzero-as-null-pointer-constant")
+#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
+#endif
+
+#endif
+
static const char *ReadString(std::string *s, const char *ptr, size_t len) {
// Read untile NULL(\0).
const char *p = ptr;
@@ -7133,7 +7252,21 @@ static bool ReadAttribute(std::string *name, std::string *type,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
if (data_len == 0) {
- return false;
+ if ((*type).compare("string") == 0) {
+ // Accept empty string attribute.
+
+ marker += sizeof(uint32_t);
+ size -= sizeof(uint32_t);
+
+ *marker_size = name_len + 1 + type_len + 1 + sizeof(uint32_t);
+
+ data->resize(1);
+ (*data)[0] = '\0';
+
+ return true;
+ } else {
+ return false;
+ }
}
marker += sizeof(uint32_t);
@@ -7236,18 +7369,24 @@ static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
}
ChannelInfo info;
- tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) - (p - reinterpret_cast<const char *>(data.data()));
+ tinyexr_int64 data_len = static_cast<tinyexr_int64>(data.size()) -
+ (p - reinterpret_cast<const char *>(data.data()));
if (data_len < 0) {
return false;
}
- p = ReadString(
- &info.name, p, size_t(data_len));
+ p = ReadString(&info.name, p, size_t(data_len));
if ((p == NULL) && (info.name.empty())) {
// Buffer overrun. Issue #51.
return false;
}
+ const unsigned char *data_end =
+ reinterpret_cast<const unsigned char *>(p) + 16;
+ if (data_end >= (data.data() + data.size())) {
+ return false;
+ }
+
memcpy(&info.pixel_type, p, sizeof(int));
p += 4;
info.p_linear = static_cast<unsigned char>(p[0]); // uchar
@@ -7468,9 +7607,8 @@ static bool DecompressZip(unsigned char *dst,
// C and C99, so no big deal)
#pragma warning(disable : 4244) // 'initializing': conversion from '__int64' to
// 'int', possible loss of data
-#pragma warning( \
- disable : 4267) // 'argument': conversion from '__int64' to 'int',
- // possible loss of data
+#pragma warning(disable : 4267) // 'argument': conversion from '__int64' to
+ // 'int', possible loss of data
#pragma warning(disable : 4996) // 'strdup': The POSIX name for this item is
// deprecated. Instead, use the ISO C and C++
// conformant name: _strdup.
@@ -7705,6 +7843,7 @@ static void DecompressRle(unsigned char *dst,
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wc++11-extensions"
#pragma clang diagnostic ignored "-Wconversion"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
#if __has_warning("-Wcast-qual")
#pragma clang diagnostic ignored "-Wcast-qual"
@@ -8187,8 +8326,8 @@ static void hufBuildEncTable(
// for all array entries.
//
- int hlink[HUF_ENCSIZE];
- long long *fHeap[HUF_ENCSIZE];
+ std::vector<int> hlink(HUF_ENCSIZE);
+ std::vector<long long *> fHeap(HUF_ENCSIZE);
*im = 0;
@@ -8247,8 +8386,8 @@ static void hufBuildEncTable(
std::make_heap(&fHeap[0], &fHeap[nf], FHeapCompare());
- long long scode[HUF_ENCSIZE];
- memset(scode, 0, sizeof(long long) * HUF_ENCSIZE);
+ std::vector<long long> scode(HUF_ENCSIZE);
+ memset(scode.data(), 0, sizeof(long long) * HUF_ENCSIZE);
while (nf > 1) {
//
@@ -8320,8 +8459,8 @@ static void hufBuildEncTable(
// code table from scode into frq.
//
- hufCanonicalCodeTable(scode);
- memcpy(frq, scode, sizeof(long long) * HUF_ENCSIZE);
+ hufCanonicalCodeTable(scode.data());
+ memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
}
//
@@ -8657,26 +8796,62 @@ static int hufEncode // return: output size (in bits)
lc += 8; \
}
-#define getCode(po, rlc, c, lc, in, out, oe) \
- { \
- if (po == rlc) { \
- if (lc < 8) getChar(c, lc, in); \
- \
- lc -= 8; \
- \
- unsigned char cs = (c >> lc); \
- \
- if (out + cs > oe) return false; \
- \
- unsigned short s = out[-1]; \
- \
- while (cs-- > 0) *out++ = s; \
- } else if (out < oe) { \
- *out++ = po; \
- } else { \
- return false; \
- } \
+#if 0
+#define getCode(po, rlc, c, lc, in, out, ob, oe) \
+ { \
+ if (po == rlc) { \
+ if (lc < 8) getChar(c, lc, in); \
+ \
+ lc -= 8; \
+ \
+ unsigned char cs = (c >> lc); \
+ \
+ if (out + cs > oe) return false; \
+ \
+ /* TinyEXR issue 78 */ \
+ unsigned short s = out[-1]; \
+ \
+ while (cs-- > 0) *out++ = s; \
+ } else if (out < oe) { \
+ *out++ = po; \
+ } else { \
+ return false; \
+ } \
}
+#else
+static bool getCode(int po, int rlc, long long &c, int &lc, const char *&in,
+ const char *in_end, unsigned short *&out,
+ const unsigned short *ob, const unsigned short *oe) {
+ (void)ob;
+ if (po == rlc) {
+ if (lc < 8) {
+ /* TinyEXR issue 78 */
+ if ((in + 1) >= in_end) {
+ return false;
+ }
+
+ getChar(c, lc, in);
+ }
+
+ lc -= 8;
+
+ unsigned char cs = (c >> lc);
+
+ if (out + cs > oe) return false;
+
+ // Bounds check for safety
+ if ((out - 1) <= ob) return false;
+ unsigned short s = out[-1];
+
+ while (cs-- > 0) *out++ = s;
+ } else if (out < oe) {
+ *out++ = po;
+ } else {
+ return false;
+ }
+ return true;
+}
+#endif
//
// Decode (uncompress) ni bits based on encoding & decoding tables:
@@ -8692,8 +8867,8 @@ static bool hufDecode(const long long *hcode, // i : encoding table
{
long long c = 0;
int lc = 0;
- unsigned short *outb = out;
- unsigned short *oe = out + no;
+ unsigned short *outb = out; // begin
+ unsigned short *oe = out + no; // end
const char *ie = in + (ni + 7) / 8; // input byte size
//
@@ -8716,7 +8891,16 @@ static bool hufDecode(const long long *hcode, // i : encoding table
//
lc -= pl.len;
- getCode(pl.lit, rlc, c, lc, in, out, oe);
+ // std::cout << "lit = " << pl.lit << std::endl;
+ // std::cout << "rlc = " << rlc << std::endl;
+ // std::cout << "c = " << c << std::endl;
+ // std::cout << "lc = " << lc << std::endl;
+ // std::cout << "in = " << in << std::endl;
+ // std::cout << "out = " << out << std::endl;
+ // std::cout << "oe = " << oe << std::endl;
+ if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
} else {
if (!pl.p) {
return false;
@@ -8743,7 +8927,9 @@ static bool hufDecode(const long long *hcode, // i : encoding table
//
lc -= l;
- getCode(pl.p[j], rlc, c, lc, in, out, oe);
+ if (!getCode(pl.p[j], rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
break;
}
}
@@ -8770,7 +8956,9 @@ static bool hufDecode(const long long *hcode, // i : encoding table
if (pl.len) {
lc -= pl.len;
- getCode(pl.lit, rlc, c, lc, in, out, oe);
+ if (!getCode(pl.lit, rlc, c, lc, in, ie, out, outb, oe)) {
+ return false;
+ }
} else {
return false;
// invalidCode(); // wrong (long) code
@@ -8785,7 +8973,7 @@ static bool hufDecode(const long long *hcode, // i : encoding table
return true;
}
-static void countFrequencies(long long freq[HUF_ENCSIZE],
+static void countFrequencies(std::vector<long long> &freq,
const unsigned short data[/*n*/], int n) {
for (int i = 0; i < HUF_ENCSIZE; ++i) freq[i] = 0;
@@ -8816,21 +9004,21 @@ static int hufCompress(const unsigned short raw[], int nRaw,
char compressed[]) {
if (nRaw == 0) return 0;
- long long freq[HUF_ENCSIZE];
+ std::vector<long long> freq(HUF_ENCSIZE);
countFrequencies(freq, raw, nRaw);
int im = 0;
int iM = 0;
- hufBuildEncTable(freq, &im, &iM);
+ hufBuildEncTable(freq.data(), &im, &iM);
char *tableStart = compressed + 20;
char *tableEnd = tableStart;
- hufPackEncTable(freq, im, iM, &tableEnd);
+ hufPackEncTable(freq.data(), im, iM, &tableEnd);
int tableLength = tableEnd - tableStart;
char *dataStart = tableEnd;
- int nBits = hufEncode(freq, raw, nRaw, iM, dataStart);
+ int nBits = hufEncode(freq.data(), raw, nRaw, iM, dataStart);
int data_length = (nBits + 7) / 8;
writeUInt(compressed, im);
@@ -8843,9 +9031,9 @@ static int hufCompress(const unsigned short raw[], int nRaw,
}
static bool hufUncompress(const char compressed[], int nCompressed,
- unsigned short raw[], int nRaw) {
+ std::vector<unsigned short> *raw) {
if (nCompressed == 0) {
- if (nRaw != 0) return false;
+ if (raw->size() != 0) return false;
return false;
}
@@ -8886,7 +9074,8 @@ static bool hufUncompress(const char compressed[], int nCompressed,
}
hufBuildDecTable(&freq.at(0), im, iM, &hdec.at(0));
- hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, nRaw, raw);
+ hufDecode(&freq.at(0), &hdec.at(0), ptr, nBits, iM, raw->size(),
+ raw->data());
}
// catch (...)
//{
@@ -8975,7 +9164,7 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
const unsigned char *inPtr, size_t inSize,
const std::vector<ChannelInfo> &channelInfo,
int data_width, int num_lines) {
- unsigned char bitmap[BITMAP_SIZE];
+ std::vector<unsigned char> bitmap(BITMAP_SIZE);
unsigned short minNonZero;
unsigned short maxNonZero;
@@ -9026,12 +9215,12 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
}
}
- bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()), bitmap,
- minNonZero, maxNonZero);
+ bitmapFromData(&tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()),
+ bitmap.data(), minNonZero, maxNonZero);
- unsigned short lut[USHORT_RANGE];
- unsigned short maxValue = forwardLutFromBitmap(bitmap, lut);
- applyLut(lut, &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
+ std::vector<unsigned short> lut(USHORT_RANGE);
+ unsigned short maxValue = forwardLutFromBitmap(bitmap.data(), lut.data());
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBuffer.size()));
//
// Store range compression info in _outBuffer
@@ -9101,7 +9290,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
return true;
}
- unsigned char bitmap[BITMAP_SIZE];
+ std::vector<unsigned char> bitmap(BITMAP_SIZE);
unsigned short minNonZero;
unsigned short maxNonZero;
@@ -9111,11 +9300,13 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
return false;
#endif
- memset(bitmap, 0, BITMAP_SIZE);
+ memset(bitmap.data(), 0, BITMAP_SIZE);
const unsigned char *ptr = inPtr;
- minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
- maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
+ // minNonZero = *(reinterpret_cast<const unsigned short *>(ptr));
+ tinyexr::cpy2(&minNonZero, reinterpret_cast<const unsigned short *>(ptr));
+ // maxNonZero = *(reinterpret_cast<const unsigned short *>(ptr + 2));
+ tinyexr::cpy2(&maxNonZero, reinterpret_cast<const unsigned short *>(ptr + 2));
ptr += 4;
if (maxNonZero >= BITMAP_SIZE) {
@@ -9128,9 +9319,9 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
ptr += maxNonZero - minNonZero + 1;
}
- unsigned short lut[USHORT_RANGE];
- memset(lut, 0, sizeof(unsigned short) * USHORT_RANGE);
- unsigned short maxValue = reverseLutFromBitmap(bitmap, lut);
+ std::vector<unsigned short> lut(USHORT_RANGE);
+ memset(lut.data(), 0, sizeof(unsigned short) * USHORT_RANGE);
+ unsigned short maxValue = reverseLutFromBitmap(bitmap.data(), lut.data());
//
// Huffman decoding
@@ -9138,12 +9329,12 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
int length;
- length = *(reinterpret_cast<const int *>(ptr));
+ // length = *(reinterpret_cast<const int *>(ptr));
+ tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
ptr += sizeof(int);
std::vector<unsigned short> tmpBuffer(tmpBufSize);
- hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer.at(0),
- static_cast<int>(tmpBufSize));
+ hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
//
// Wavelet decoding
@@ -9184,7 +9375,7 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
// Expand the pixel data to their original range
//
- applyLut(lut, &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
+ applyLut(lut.data(), &tmpBuffer.at(0), static_cast<int>(tmpBufSize));
for (int y = 0; y < num_lines; y++) {
for (size_t i = 0; i < channelData.size(); ++i) {
@@ -9409,6 +9600,7 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
// -----------------------------------------------------------------
//
+// TODO(syoyo): Refactor function arguments.
static bool DecodePixelData(/* out */ unsigned char **out_images,
const int *requested_pixel_types,
const unsigned char *data_ptr, size_t data_len,
@@ -9421,6 +9613,11 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
const std::vector<size_t> &channel_offset_list) {
if (compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) { // PIZ
#if TINYEXR_USE_PIZ
+ if ((width == 0) || (num_lines == 0) || (pixel_data_size == 0)) {
+ // Invalid input #90
+ return false;
+ }
+
// Allocate original data size.
std::vector<unsigned char> outBuf(static_cast<size_t>(
static_cast<size_t>(width * num_lines) * pixel_data_size));
@@ -9452,7 +9649,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ // use `cpy` to avoid unaligned memory access when compiler's
+ // optimization is on.
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
@@ -9495,7 +9695,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(&val);
@@ -9521,7 +9723,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
v * pixel_data_size * static_cast<size_t>(x_stride) +
channel_offset_list[c] * static_cast<size_t>(x_stride)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9557,9 +9761,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
assert(dstLen > 0);
- if (!tinyexr::DecompressZip(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
- &dstLen, data_ptr,
- static_cast<unsigned long>(data_len))) {
+ if (!tinyexr::DecompressZip(
+ reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr,
+ static_cast<unsigned long>(data_len))) {
return false;
}
@@ -9583,7 +9787,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
tinyexr::FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
@@ -9626,7 +9831,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(&val);
@@ -9652,7 +9859,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9707,7 +9916,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
tinyexr::FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
@@ -9750,7 +9960,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(&val);
@@ -9776,7 +9988,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ // val = line_ptr[u];
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9839,7 +10053,8 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
channel_offset_list[c] * static_cast<size_t>(width)));
for (size_t u = 0; u < static_cast<size_t>(width); u++) {
- float val = line_ptr[u];
+ float val;
+ tinyexr::cpy4(&val, line_ptr + u);
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
@@ -9871,88 +10086,120 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
#endif
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
for (size_t c = 0; c < num_channels; c++) {
- if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
- const unsigned short *line_ptr =
- reinterpret_cast<const unsigned short *>(
- data_ptr +
- c * static_cast<size_t>(width) * sizeof(unsigned short));
-
- if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
- unsigned short *outLine =
- reinterpret_cast<unsigned short *>(out_images[c]);
- if (line_order == 0) {
- outLine += y * x_stride;
- } else {
- outLine += (height - 1 - y) * x_stride;
- }
+ for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
+ if (channels[c].pixel_type == TINYEXR_PIXELTYPE_HALF) {
+ const unsigned short *line_ptr =
+ reinterpret_cast<const unsigned short *>(
+ data_ptr + v * pixel_data_size * size_t(width) +
+ channel_offset_list[c] * static_cast<size_t>(width));
+
+ if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
+ unsigned short *outLine =
+ reinterpret_cast<unsigned short *>(out_images[c]);
+ if (line_order == 0) {
+ outLine += (size_t(y) + v) * size_t(x_stride);
+ } else {
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
+ }
- for (int u = 0; u < width; u++) {
- tinyexr::FP16 hf;
+ for (int u = 0; u < width; u++) {
+ tinyexr::FP16 hf;
- hf.u = line_ptr[u];
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
- tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
+ tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
- outLine[u] = hf.u;
+ outLine[u] = hf.u;
+ }
+ } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
+ float *outLine = reinterpret_cast<float *>(out_images[c]);
+ if (line_order == 0) {
+ outLine += (size_t(y) + v) * size_t(x_stride);
+ } else {
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
+ }
+
+ if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
+ (data_ptr + data_len)) {
+ // Insufficient data size
+ return false;
+ }
+
+ for (int u = 0; u < width; u++) {
+ tinyexr::FP16 hf;
+
+ // address may not be aliged. use byte-wise copy for safety.#76
+ // hf.u = line_ptr[u];
+ tinyexr::cpy2(&(hf.u), line_ptr + u);
+
+ tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
+
+ tinyexr::FP32 f32 = half_to_float(hf);
+
+ outLine[u] = f32.f;
+ }
+ } else {
+ assert(0);
+ return false;
}
- } else if (requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
+ const float *line_ptr = reinterpret_cast<const float *>(
+ data_ptr + v * pixel_data_size * size_t(width) +
+ channel_offset_list[c] * static_cast<size_t>(width));
+
float *outLine = reinterpret_cast<float *>(out_images[c]);
if (line_order == 0) {
- outLine += y * x_stride;
+ outLine += (size_t(y) + v) * size_t(x_stride);
} else {
- outLine += (height - 1 - y) * x_stride;
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
}
- for (int u = 0; u < width; u++) {
- tinyexr::FP16 hf;
-
- hf.u = line_ptr[u];
-
- tinyexr::swap2(reinterpret_cast<unsigned short *>(&hf.u));
-
- tinyexr::FP32 f32 = half_to_float(hf);
-
- outLine[u] = f32.f;
+ if (reinterpret_cast<const unsigned char *>(line_ptr + width) >
+ (data_ptr + data_len)) {
+ // Insufficient data size
+ return false;
}
- } else {
- assert(0);
- return false;
- }
- } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
- const float *line_ptr = reinterpret_cast<const float *>(
- data_ptr + c * static_cast<size_t>(width) * sizeof(float));
- float *outLine = reinterpret_cast<float *>(out_images[c]);
- if (line_order == 0) {
- outLine += y * x_stride;
- } else {
- outLine += (height - 1 - y) * x_stride;
- }
+ for (int u = 0; u < width; u++) {
+ float val;
+ tinyexr::cpy4(&val, line_ptr + u);
- for (int u = 0; u < width; u++) {
- float val = line_ptr[u];
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
+ outLine[u] = val;
+ }
+ } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
+ const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
+ data_ptr + v * pixel_data_size * size_t(width) +
+ channel_offset_list[c] * static_cast<size_t>(width));
- outLine[u] = val;
- }
- } else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
- const unsigned int *line_ptr = reinterpret_cast<const unsigned int *>(
- data_ptr + c * static_cast<size_t>(width) * sizeof(unsigned int));
+ unsigned int *outLine =
+ reinterpret_cast<unsigned int *>(out_images[c]);
+ if (line_order == 0) {
+ outLine += (size_t(y) + v) * size_t(x_stride);
+ } else {
+ outLine +=
+ (size_t(height) - 1 - (size_t(y) + v)) * size_t(x_stride);
+ }
- unsigned int *outLine = reinterpret_cast<unsigned int *>(out_images[c]);
- if (line_order == 0) {
- outLine += y * x_stride;
- } else {
- outLine += (height - 1 - y) * x_stride;
- }
+ for (int u = 0; u < width; u++) {
+ if (reinterpret_cast<const unsigned char *>(line_ptr + u) >=
+ (data_ptr + data_len)) {
+ // Corrupsed data?
+ return false;
+ }
- for (int u = 0; u < width; u++) {
- unsigned int val = line_ptr[u];
+ unsigned int val;
+ tinyexr::cpy4(&val, line_ptr + u);
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
- outLine[u] = val;
+ outLine[u] = val;
+ }
}
}
}
@@ -9994,7 +10241,7 @@ static void DecodeTiledPixelData(
num_channels, channels, channel_offset_list);
}
-static void ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
+static bool ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
int *pixel_data_size, size_t *channel_offset,
int num_channels,
const EXRChannelInfo *channels) {
@@ -10015,9 +10262,11 @@ static void ComputeChannelLayout(std::vector<size_t> *channel_offset_list,
(*pixel_data_size) += sizeof(unsigned int);
(*channel_offset) += sizeof(unsigned int);
} else {
- assert(0);
+ // ???
+ return false;
}
}
+ return true;
}
static unsigned char **AllocateImage(int num_channels,
@@ -10125,8 +10374,11 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
// Read attributes
size_t orig_size = size;
- for (;;) {
+ for (size_t nattr = 0; nattr < TINYEXR_MAX_HEADER_ATTRIBUTES; nattr++) {
if (0 == size) {
+ if (err) {
+ (*err) += "Insufficient data size for attributes.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
} else if (marker[0] == '\0') {
size--;
@@ -10139,6 +10391,9 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
size_t marker_size;
if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
marker, size)) {
+ if (err) {
+ (*err) += "Failed to read attribute.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
marker += marker_size;
@@ -10209,14 +10464,14 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
if (!ReadChannelInfo(info->channels, data)) {
if (err) {
- (*err) = "Failed to parse channel info.";
+ (*err) += "Failed to parse channel info.\n";
}
return TINYEXR_ERROR_INVALID_DATA;
}
if (info->channels.size() < 1) {
if (err) {
- (*err) = "# of channels is zero.";
+ (*err) += "# of channels is zero.\n";
}
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10224,9 +10479,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
has_channels = true;
} else if (attr_name.compare("dataWindow") == 0) {
- if (data.size() < 16) {
- // Corrupsed file(Issue #50).
- } else {
+ if (data.size() >= 16) {
memcpy(&info->data_window[0], &data.at(0), sizeof(int));
memcpy(&info->data_window[1], &data.at(4), sizeof(int));
memcpy(&info->data_window[2], &data.at(8), sizeof(int));
@@ -10238,48 +10491,60 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
has_data_window = true;
}
} else if (attr_name.compare("displayWindow") == 0) {
- memcpy(&info->display_window[0], &data.at(0), sizeof(int));
- memcpy(&info->display_window[1], &data.at(4), sizeof(int));
- memcpy(&info->display_window[2], &data.at(8), sizeof(int));
- memcpy(&info->display_window[3], &data.at(12), sizeof(int));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[0]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[1]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[2]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->display_window[3]));
-
- has_display_window = true;
+ if (data.size() >= 16) {
+ memcpy(&info->display_window[0], &data.at(0), sizeof(int));
+ memcpy(&info->display_window[1], &data.at(4), sizeof(int));
+ memcpy(&info->display_window[2], &data.at(8), sizeof(int));
+ memcpy(&info->display_window[3], &data.at(12), sizeof(int));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[0]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[1]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[2]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->display_window[3]));
+
+ has_display_window = true;
+ }
} else if (attr_name.compare("lineOrder") == 0) {
- info->line_order = static_cast<int>(data[0]);
- has_line_order = true;
+ if (data.size() >= 1) {
+ info->line_order = static_cast<int>(data[0]);
+ has_line_order = true;
+ }
} else if (attr_name.compare("pixelAspectRatio") == 0) {
- memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
- has_pixel_aspect_ratio = true;
+ if (data.size() >= sizeof(float)) {
+ memcpy(&info->pixel_aspect_ratio, &data.at(0), sizeof(float));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->pixel_aspect_ratio));
+ has_pixel_aspect_ratio = true;
+ }
} else if (attr_name.compare("screenWindowCenter") == 0) {
- memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
- memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
- has_screen_window_center = true;
+ if (data.size() >= 8) {
+ memcpy(&info->screen_window_center[0], &data.at(0), sizeof(float));
+ memcpy(&info->screen_window_center[1], &data.at(4), sizeof(float));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->screen_window_center[0]));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->screen_window_center[1]));
+ has_screen_window_center = true;
+ }
} else if (attr_name.compare("screenWindowWidth") == 0) {
- memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
- tinyexr::swap4(
- reinterpret_cast<unsigned int *>(&info->screen_window_width));
+ if (data.size() >= sizeof(float)) {
+ memcpy(&info->screen_window_width, &data.at(0), sizeof(float));
+ tinyexr::swap4(
+ reinterpret_cast<unsigned int *>(&info->screen_window_width));
- has_screen_window_width = true;
+ has_screen_window_width = true;
+ }
} else if (attr_name.compare("chunkCount") == 0) {
- memcpy(&info->chunk_count, &data.at(0), sizeof(int));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
+ if (data.size() >= sizeof(int)) {
+ memcpy(&info->chunk_count, &data.at(0), sizeof(int));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->chunk_count));
+ }
} else {
- // Custom attribute(up to TINYEXR_MAX_ATTRIBUTES)
- if (info->attributes.size() < TINYEXR_MAX_ATTRIBUTES) {
+ // Custom attribute(up to TINYEXR_MAX_CUSTOM_ATTRIBUTES)
+ if (info->attributes.size() < TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
EXRAttribute attrib;
#ifdef _MSC_VER
strncpy_s(attrib.name, attr_name.c_str(), 255);
@@ -10409,15 +10674,30 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
exr_header->requested_pixel_types[c] = info.channels[c].pixel_type;
}
- assert(info.attributes.size() < TINYEXR_MAX_ATTRIBUTES);
exr_header->num_custom_attributes = static_cast<int>(info.attributes.size());
- for (size_t i = 0; i < info.attributes.size(); i++) {
- memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name, 256);
- memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type, 256);
- exr_header->custom_attributes[i].size = info.attributes[i].size;
- // Just copy poiner
- exr_header->custom_attributes[i].value = info.attributes[i].value;
+ if (exr_header->num_custom_attributes > 0) {
+ // TODO(syoyo): Report warning when # of attributes exceeds
+ // `TINYEXR_MAX_CUSTOM_ATTRIBUTES`
+ if (exr_header->num_custom_attributes > TINYEXR_MAX_CUSTOM_ATTRIBUTES) {
+ exr_header->num_custom_attributes = TINYEXR_MAX_CUSTOM_ATTRIBUTES;
+ }
+
+ exr_header->custom_attributes = static_cast<EXRAttribute *>(malloc(
+ sizeof(EXRAttribute) * size_t(exr_header->num_custom_attributes)));
+
+ for (size_t i = 0; i < info.attributes.size(); i++) {
+ memcpy(exr_header->custom_attributes[i].name, info.attributes[i].name,
+ 256);
+ memcpy(exr_header->custom_attributes[i].type, info.attributes[i].type,
+ 256);
+ exr_header->custom_attributes[i].size = info.attributes[i].size;
+ // Just copy poiner
+ exr_header->custom_attributes[i].value = info.attributes[i].value;
+ }
+
+ } else {
+ exr_header->custom_attributes = NULL;
}
exr_header->header_len = info.header_len;
@@ -10425,7 +10705,8 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
const std::vector<tinyexr::tinyexr_uint64> &offsets,
- const unsigned char *head, const size_t size) {
+ const unsigned char *head, const size_t size,
+ std::string *err) {
int num_channels = exr_header->num_channels;
int num_scanline_blocks = 1;
@@ -10445,32 +10726,40 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
std::vector<size_t> channel_offset_list;
int pixel_data_size = 0;
size_t channel_offset = 0;
- tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
- &channel_offset, num_channels,
- exr_header->channels);
+ if (!tinyexr::ComputeChannelLayout(&channel_offset_list, &pixel_data_size,
+ &channel_offset, num_channels,
+ exr_header->channels)) {
+ if (err) {
+ (*err) += "Failed to compute channel layout.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
- bool invalid_data = false;
+ bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
if (exr_header->tiled) {
size_t num_tiles = offsets.size(); // = # of blocks
exr_image->tiles = static_cast<EXRTile *>(
- malloc(sizeof(EXRTile) * static_cast<size_t>(num_tiles)));
+ calloc(sizeof(EXRTile), static_cast<size_t>(num_tiles)));
for (size_t tile_idx = 0; tile_idx < num_tiles; tile_idx++) {
// Allocate memory for each tile.
exr_image->tiles[tile_idx].images = tinyexr::AllocateImage(
num_channels, exr_header->channels, exr_header->requested_pixel_types,
- data_width, data_height);
+ exr_header->tile_size_x, exr_header->tile_size_y);
// 16 byte: tile coordinates
// 4 byte : data size
// ~ : data(uncompressed or compressed)
if (offsets[tile_idx] + sizeof(int) * 5 > size) {
+ if (err) {
+ (*err) += "Insufficient data size.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
- size_t data_size = size - (offsets[tile_idx] + sizeof(int) * 5);
+ size_t data_size = size_t(size - (offsets[tile_idx] + sizeof(int) * 5));
const unsigned char *data_ptr =
reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
@@ -10482,8 +10771,12 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&tile_coordinates[3]));
// @todo{ LoD }
- assert(tile_coordinates[2] == 0);
- assert(tile_coordinates[3] == 0);
+ if (tile_coordinates[2] != 0) {
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
+ }
+ if (tile_coordinates[3] != 0) {
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
+ }
int data_len;
memcpy(&data_len, data_ptr + 16,
@@ -10491,6 +10784,9 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
if (data_len < 4 || size_t(data_len) > data_size) {
+ if (err) {
+ (*err) += "Insufficient data length.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10531,56 +10827,56 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
size_t y_idx = static_cast<size_t>(y);
if (offsets[y_idx] + sizeof(int) * 2 > size) {
- return TINYEXR_ERROR_INVALID_DATA;
- }
-
- // 4 byte: scan line
- // 4 byte: data size
- // ~ : pixel data(uncompressed or compressed)
- size_t data_size = size - (offsets[y_idx] + sizeof(int) * 2);
- const unsigned char *data_ptr =
- reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
-
- int line_no;
- memcpy(&line_no, data_ptr, sizeof(int));
- int data_len;
- memcpy(&data_len, data_ptr + 4, sizeof(int));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
-
- if (size_t(data_len) > data_size) {
- return TINYEXR_ERROR_INVALID_DATA;
- }
-
- int end_line_no = (std::min)(line_no + num_scanline_blocks,
- (exr_header->data_window[3] + 1));
-
- int num_lines = end_line_no - line_no;
- //assert(num_lines > 0);
-
- if (num_lines <= 0) {
invalid_data = true;
} else {
-
- // Move to data addr: 8 = 4 + 4;
- data_ptr += 8;
-
- // Adjust line_no with data_window.bmin.y
- line_no -= exr_header->data_window[1];
-
- if (line_no < 0) {
+ // 4 byte: scan line
+ // 4 byte: data size
+ // ~ : pixel data(uncompressed or compressed)
+ size_t data_size = size_t(size - (offsets[y_idx] + sizeof(int) * 2));
+ const unsigned char *data_ptr =
+ reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
+
+ int line_no;
+ memcpy(&line_no, data_ptr, sizeof(int));
+ int data_len;
+ memcpy(&data_len, data_ptr + 4, sizeof(int));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&line_no));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
+
+ if (size_t(data_len) > data_size) {
invalid_data = true;
} else {
- if (!tinyexr::DecodePixelData(
- exr_image->images, exr_header->requested_pixel_types, data_ptr,
- static_cast<size_t>(data_len), exr_header->compression_type,
- exr_header->line_order, data_width, data_height, data_width, y,
- line_no, num_lines, static_cast<size_t>(pixel_data_size),
- static_cast<size_t>(exr_header->num_custom_attributes),
- exr_header->custom_attributes,
- static_cast<size_t>(exr_header->num_channels), exr_header->channels,
- channel_offset_list)) {
+ int end_line_no = (std::min)(line_no + num_scanline_blocks,
+ (exr_header->data_window[3] + 1));
+
+ int num_lines = end_line_no - line_no;
+ // assert(num_lines > 0);
+
+ if (num_lines <= 0) {
invalid_data = true;
+ } else {
+ // Move to data addr: 8 = 4 + 4;
+ data_ptr += 8;
+
+ // Adjust line_no with data_window.bmin.y
+ line_no -= exr_header->data_window[1];
+
+ if (line_no < 0) {
+ invalid_data = true;
+ } else {
+ if (!tinyexr::DecodePixelData(
+ exr_image->images, exr_header->requested_pixel_types,
+ data_ptr, static_cast<size_t>(data_len),
+ exr_header->compression_type, exr_header->line_order,
+ data_width, data_height, data_width, y, line_no,
+ num_lines, static_cast<size_t>(pixel_data_size),
+ static_cast<size_t>(exr_header->num_custom_attributes),
+ exr_header->custom_attributes,
+ static_cast<size_t>(exr_header->num_channels),
+ exr_header->channels, channel_offset_list)) {
+ invalid_data = true;
+ }
+ }
}
}
}
@@ -10648,9 +10944,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
const char **err) {
if (exr_image == NULL || exr_header == NULL || head == NULL ||
marker == NULL || (size <= tinyexr::kEXRVersionSize)) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for DecodeEXRImage().", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -10663,13 +10957,23 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
num_scanline_blocks = 16;
}
- int data_width = exr_header->data_window[2] - exr_header->data_window[0] + 1;
- int data_height = exr_header->data_window[3] - exr_header->data_window[1] + 1;
+ int data_width = exr_header->data_window[2] - exr_header->data_window[0];
+ if (data_width >= std::numeric_limits<int>::max()) {
+ // Issue 63
+ tinyexr::SetErrorMessage("Invalid data window value", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ data_width++;
+
+ int data_height = exr_header->data_window[3] - exr_header->data_window[1];
+ if (data_height >= std::numeric_limits<int>::max()) {
+ tinyexr::SetErrorMessage("Invalid data height value", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ data_height++;
if ((data_width < 0) || (data_height < 0)) {
- if (err) {
- (*err) = "Invalid data window value.";
- }
+ tinyexr::SetErrorMessage("data window or data height is negative.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10708,12 +11012,16 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
for (size_t y = 0; y < num_blocks; y++) {
tinyexr::tinyexr_uint64 offset;
+ // Issue #81
+ if ((marker + sizeof(tinyexr_uint64)) >= (head + size)) {
+ tinyexr::SetErrorMessage("Insufficient data size in offset table.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
memcpy(&offset, marker, sizeof(tinyexr::tinyexr_uint64));
tinyexr::swap8(&offset);
if (offset >= size) {
- if (err) {
- (*err) = "Invalid offset value.";
- }
+ tinyexr::SetErrorMessage("Invalid offset value in DecodeEXRImage.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
marker += sizeof(tinyexr::tinyexr_uint64); // = 8
@@ -10736,15 +11044,37 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
// OK
break;
} else {
- if (err) {
- (*err) = "Cannot reconstruct lineOffset table.";
- }
+ tinyexr::SetErrorMessage(
+ "Cannot reconstruct lineOffset table in DecodeEXRImage.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
}
}
- return DecodeChunk(exr_image, exr_header, offsets, head, size);
+ {
+ std::string e;
+ int ret = DecodeChunk(exr_image, exr_header, offsets, head, size, &e);
+
+ if (ret != TINYEXR_SUCCESS) {
+ if (!e.empty()) {
+ tinyexr::SetErrorMessage(e, err);
+ }
+
+ // release memory(if exists)
+ if ((exr_header->num_channels > 0) && exr_image && exr_image->images) {
+ for (size_t c = 0; c < size_t(exr_header->num_channels); c++) {
+ if (exr_image->images[c]) {
+ free(exr_image->images[c]);
+ exr_image->images[c] = NULL;
+ }
+ }
+ free(exr_image->images);
+ exr_image->images = NULL;
+ }
+ }
+
+ return ret;
+ }
}
} // namespace tinyexr
@@ -10752,9 +11082,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
const char **err) {
if (out_rgba == NULL) {
- if (err) {
- (*err) = "Invalid argument.\n";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXR()", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -10767,13 +11095,14 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
{
int ret = ParseEXRVersionFromFile(&exr_version, filename);
if (ret != TINYEXR_SUCCESS) {
+ tinyexr::SetErrorMessage("Invalid EXR header.", err);
return ret;
}
if (exr_version.multipart || exr_version.non_image) {
- if (err) {
- (*err) = "Loading multipart or DeepImage is not supported yet.\n";
- }
+ tinyexr::SetErrorMessage(
+ "Loading multipart or DeepImage is not supported in LoadEXR() API",
+ err);
return TINYEXR_ERROR_INVALID_DATA; // @fixme.
}
}
@@ -10781,6 +11110,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
{
int ret = ParseEXRHeaderFromFile(&exr_header, &exr_version, filename, err);
if (ret != TINYEXR_SUCCESS) {
+ FreeEXRHeader(&exr_header);
return ret;
}
}
@@ -10795,6 +11125,7 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
{
int ret = LoadEXRImageFromFile(&exr_image, &exr_header, filename, err);
if (ret != TINYEXR_SUCCESS) {
+ FreeEXRHeader(&exr_header);
return ret;
}
}
@@ -10816,62 +11147,130 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
}
}
- if ((idxA == 0) && (idxR == -1) && (idxG == -1) && (idxB == -1)) {
- // Alpha channel only.
+ if (exr_header.num_channels == 1) {
+ // Grayscale channel only.
(*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
- (*out_rgba)[4 * i + 0] = val;
- (*out_rgba)[4 * i + 1] = val;
- (*out_rgba)[4 * i + 2] = val;
- (*out_rgba)[4 * i + 3] = val;
+
+ if (exr_header.tiled) {
+ // todo.implement this
+
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++) {
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[0][srcIdx];
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ const float val = reinterpret_cast<float **>(exr_image.images)[0][i];
+ (*out_rgba)[4 * i + 0] = val;
+ (*out_rgba)[4 * i + 1] = val;
+ (*out_rgba)[4 * i + 2] = val;
+ (*out_rgba)[4 * i + 3] = val;
+ }
}
} else {
// Assume RGB(A)
if (idxR == -1) {
- if (err) {
- (*err) = "R channel not found\n";
- }
+ tinyexr::SetErrorMessage("R channel not found", err);
// @todo { free exr_image }
+ FreeEXRHeader(&exr_header);
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxG == -1) {
- if (err) {
- (*err) = "G channel not found\n";
- }
+ tinyexr::SetErrorMessage("G channel not found", err);
// @todo { free exr_image }
+ FreeEXRHeader(&exr_header);
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxB == -1) {
- if (err) {
- (*err) = "B channel not found\n";
- }
+ tinyexr::SetErrorMessage("B channel not found", err);
// @todo { free exr_image }
+ FreeEXRHeader(&exr_header);
return TINYEXR_ERROR_INVALID_DATA;
}
(*out_rgba) = reinterpret_cast<float *>(
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- (*out_rgba)[4 * i + 0] =
- reinterpret_cast<float **>(exr_image.images)[idxR][i];
- (*out_rgba)[4 * i + 1] =
- reinterpret_cast<float **>(exr_image.images)[idxG][i];
- (*out_rgba)[4 * i + 2] =
- reinterpret_cast<float **>(exr_image.images)[idxB][i];
- if (idxA != -1) {
- (*out_rgba)[4 * i + 3] =
- reinterpret_cast<float **>(exr_image.images)[idxA][i];
- } else {
- (*out_rgba)[4 * i + 3] = 1.0;
+ if (exr_header.tiled) {
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++) {
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[idxR][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[idxG][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[idxB][srcIdx];
+ if (idxA != -1) {
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[idxA][srcIdx];
+ } else {
+ (*out_rgba)[4 * idx + 3] = 1.0;
+ }
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ (*out_rgba)[4 * i + 0] =
+ reinterpret_cast<float **>(exr_image.images)[idxR][i];
+ (*out_rgba)[4 * i + 1] =
+ reinterpret_cast<float **>(exr_image.images)[idxG][i];
+ (*out_rgba)[4 * i + 2] =
+ reinterpret_cast<float **>(exr_image.images)[idxB][i];
+ if (idxA != -1) {
+ (*out_rgba)[4 * i + 3] =
+ reinterpret_cast<float **>(exr_image.images)[idxA][i];
+ } else {
+ (*out_rgba)[4 * i + 3] = 1.0;
+ }
}
}
}
@@ -10889,15 +11288,17 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
const unsigned char *memory, size_t size,
const char **err) {
if (memory == NULL || exr_header == NULL) {
- if (err) {
- (*err) = "Invalid argument.\n";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument. `memory` or `exr_header` argument is null in "
+ "ParseEXRHeaderFromMemory()",
+ err);
// Invalid argument
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
if (size < tinyexr::kEXRVersionSize) {
+ tinyexr::SetErrorMessage("Insufficient header/data size.\n", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -10912,11 +11313,7 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
if (ret != TINYEXR_SUCCESS) {
if (err && !err_str.empty()) {
-#ifdef _WIN32
- (*err) = _strdup(err_str.c_str()); // May leak
-#else
- (*err) = strdup(err_str.c_str()); // May leak
-#endif
+ tinyexr::SetErrorMessage(err_str, err);
}
}
@@ -10932,9 +11329,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
const unsigned char *memory, size_t size,
const char **err) {
if (out_rgba == NULL || memory == NULL) {
- if (err) {
- (*err) = "Invalid argument.\n";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXRFromMemory", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -10946,6 +11341,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
int ret = ParseEXRVersionFromMemory(&exr_version, memory, size);
if (ret != TINYEXR_SUCCESS) {
+ tinyexr::SetErrorMessage("Failed to parse EXR version", err);
return ret;
}
@@ -10985,26 +11381,20 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
}
if (idxR == -1) {
- if (err) {
- (*err) = "R channel not found\n";
- }
+ tinyexr::SetErrorMessage("R channel not found", err);
// @todo { free exr_image }
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxG == -1) {
- if (err) {
- (*err) = "G channel not found\n";
- }
+ tinyexr::SetErrorMessage("G channel not found", err);
// @todo { free exr_image }
return TINYEXR_ERROR_INVALID_DATA;
}
if (idxB == -1) {
- if (err) {
- (*err) = "B channel not found\n";
- }
+ tinyexr::SetErrorMessage("B channel not found", err);
// @todo { free exr_image }
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -11013,18 +11403,53 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
static_cast<size_t>(exr_image.height)));
- for (int i = 0; i < exr_image.width * exr_image.height; i++) {
- (*out_rgba)[4 * i + 0] =
- reinterpret_cast<float **>(exr_image.images)[idxR][i];
- (*out_rgba)[4 * i + 1] =
- reinterpret_cast<float **>(exr_image.images)[idxG][i];
- (*out_rgba)[4 * i + 2] =
- reinterpret_cast<float **>(exr_image.images)[idxB][i];
- if (idxA != -1) {
- (*out_rgba)[4 * i + 3] =
- reinterpret_cast<float **>(exr_image.images)[idxA][i];
- } else {
- (*out_rgba)[4 * i + 3] = 1.0;
+ if (exr_header.tiled) {
+ for (int it = 0; it < exr_image.num_tiles; it++) {
+ for (int j = 0; j < exr_header.tile_size_y; j++)
+ for (int i = 0; i < exr_header.tile_size_x; i++) {
+ const int ii =
+ exr_image.tiles[it].offset_x * exr_header.tile_size_x + i;
+ const int jj =
+ exr_image.tiles[it].offset_y * exr_header.tile_size_y + j;
+ const int idx = ii + jj * exr_image.width;
+
+ // out of region check.
+ if (ii >= exr_image.width) {
+ continue;
+ }
+ if (jj >= exr_image.height) {
+ continue;
+ }
+ const int srcIdx = i + j * exr_header.tile_size_x;
+ unsigned char **src = exr_image.tiles[it].images;
+ (*out_rgba)[4 * idx + 0] =
+ reinterpret_cast<float **>(src)[idxR][srcIdx];
+ (*out_rgba)[4 * idx + 1] =
+ reinterpret_cast<float **>(src)[idxG][srcIdx];
+ (*out_rgba)[4 * idx + 2] =
+ reinterpret_cast<float **>(src)[idxB][srcIdx];
+ if (idxA != -1) {
+ (*out_rgba)[4 * idx + 3] =
+ reinterpret_cast<float **>(src)[idxA][srcIdx];
+ } else {
+ (*out_rgba)[4 * idx + 3] = 1.0;
+ }
+ }
+ }
+ } else {
+ for (int i = 0; i < exr_image.width * exr_image.height; i++) {
+ (*out_rgba)[4 * i + 0] =
+ reinterpret_cast<float **>(exr_image.images)[idxR][i];
+ (*out_rgba)[4 * i + 1] =
+ reinterpret_cast<float **>(exr_image.images)[idxG][i];
+ (*out_rgba)[4 * i + 2] =
+ reinterpret_cast<float **>(exr_image.images)[idxB][i];
+ if (idxA != -1) {
+ (*out_rgba)[4 * i + 3] =
+ reinterpret_cast<float **>(exr_image.images)[idxA][i];
+ } else {
+ (*out_rgba)[4 * i + 3] = 1.0;
+ }
}
}
@@ -11040,9 +11465,7 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
const char *filename, const char **err) {
if (exr_image == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromFile", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -11053,9 +11476,7 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -11065,6 +11486,12 @@ int LoadEXRImageFromFile(EXRImage *exr_image, const EXRHeader *exr_header,
filesize = static_cast<size_t>(ftell(fp));
fseek(fp, 0, SEEK_SET);
+ if (filesize < 16) {
+ tinyexr::SetErrorMessage("File size too short " + std::string(filename),
+ err);
+ return TINYEXR_ERROR_INVALID_FILE;
+ }
+
std::vector<unsigned char> buf(filesize); // @todo { use mmap }
{
size_t ret;
@@ -11083,16 +11510,13 @@ int LoadEXRImageFromMemory(EXRImage *exr_image, const EXRHeader *exr_header,
const char **err) {
if (exr_image == NULL || memory == NULL ||
(size < tinyexr::kEXRVersionSize)) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadEXRImageFromMemory",
+ err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
if (exr_header->header_len == 0) {
- if (err) {
- (*err) = "EXRHeader is not initialized.";
- }
+ tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -11109,26 +11533,22 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
unsigned char **memory_out, const char **err) {
if (exr_image == NULL || memory_out == NULL ||
exr_header->compression_type < 0) {
- if (err) {
- (*err) = "Invalid argument.";
- }
- return 0; // @fixme
+ tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToMemory", err);
+ return 0;
}
#if !TINYEXR_USE_PIZ
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
- if (err) {
- (*err) = "PIZ compression is not supported in this build.";
- }
+ tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
+ err);
return 0;
}
#endif
#if !TINYEXR_USE_ZFP
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
- if (err) {
- (*err) = "ZFP compression is not supported in this build.";
- }
+ tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
+ err);
return 0;
}
#endif
@@ -11136,9 +11556,8 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
#if TINYEXR_USE_ZFP
for (size_t i = 0; i < static_cast<size_t>(exr_header->num_channels); i++) {
if (exr_header->requested_pixel_types[i] != TINYEXR_PIXELTYPE_FLOAT) {
- if (err) {
- (*err) = "Pixel type must be FLOAT for ZFP compression.";
- }
+ tinyexr::SetErrorMessage("Pixel type must be FLOAT for ZFP compression",
+ err);
return 0;
}
}
@@ -11286,8 +11705,6 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(
tinyexr::tinyexr_int64); // sizeof(header) + sizeof(offsetTable)
- std::vector<unsigned char> data;
-
std::vector<std::vector<unsigned char> > data_list(
static_cast<size_t>(num_blocks));
std::vector<size_t> channel_offset_list(
@@ -11348,6 +11765,11 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ float *line_ptr = reinterpret_cast<float *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
tinyexr::FP16 h16;
h16.u = reinterpret_cast<unsigned short **>(
@@ -11357,30 +11779,27 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
tinyexr::swap4(reinterpret_cast<unsigned int *>(&f32.f));
- // Assume increasing Y
- float *line_ptr = reinterpret_cast<float *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = f32.f;
+ // line_ptr[x] = f32.f;
+ tinyexr::cpy4(line_ptr + x, &(f32.f));
}
}
} else if (exr_header->requested_pixel_types[c] ==
TINYEXR_PIXELTYPE_HALF) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
+ &buf.at(static_cast<size_t>(pixel_data_size * y *
+ exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
unsigned short val = reinterpret_cast<unsigned short **>(
exr_image->images)[c][(y + start_y) * exr_image->width + x];
tinyexr::swap2(&val);
- // Assume increasing Y
- unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
- &buf.at(static_cast<size_t>(pixel_data_size * y *
- exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = val;
+ // line_ptr[x] = val;
+ tinyexr::cpy2(line_ptr + x, &val);
}
}
} else {
@@ -11390,6 +11809,12 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT) {
if (exr_header->requested_pixel_types[c] == TINYEXR_PIXELTYPE_HALF) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
+ &buf.at(static_cast<size_t>(pixel_data_size * y *
+ exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
tinyexr::FP32 f32;
f32.f = reinterpret_cast<float **>(
@@ -11400,30 +11825,26 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
tinyexr::swap2(reinterpret_cast<unsigned short *>(&h16.u));
- // Assume increasing Y
- unsigned short *line_ptr = reinterpret_cast<unsigned short *>(
- &buf.at(static_cast<size_t>(pixel_data_size * y *
- exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = h16.u;
+ // line_ptr[x] = h16.u;
+ tinyexr::cpy2(line_ptr + x, &(h16.u));
}
}
} else if (exr_header->requested_pixel_types[c] ==
TINYEXR_PIXELTYPE_FLOAT) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ float *line_ptr = reinterpret_cast<float *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * exr_image->width) +
+ channel_offset_list[c] *
+ static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
float val = reinterpret_cast<float **>(
exr_image->images)[c][(y + start_y) * exr_image->width + x];
tinyexr::swap4(reinterpret_cast<unsigned int *>(&val));
- // Assume increasing Y
- float *line_ptr = reinterpret_cast<float *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = val;
+ // line_ptr[x] = val;
+ tinyexr::cpy4(line_ptr + x, &val);
}
}
} else {
@@ -11431,18 +11852,18 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
}
} else if (exr_header->pixel_types[c] == TINYEXR_PIXELTYPE_UINT) {
for (int y = 0; y < h; y++) {
+ // Assume increasing Y
+ unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
+ static_cast<size_t>(pixel_data_size * y * exr_image->width) +
+ channel_offset_list[c] * static_cast<size_t>(exr_image->width)));
for (int x = 0; x < exr_image->width; x++) {
unsigned int val = reinterpret_cast<unsigned int **>(
exr_image->images)[c][(y + start_y) * exr_image->width + x];
tinyexr::swap4(&val);
- // Assume increasing Y
- unsigned int *line_ptr = reinterpret_cast<unsigned int *>(&buf.at(
- static_cast<size_t>(pixel_data_size * y * exr_image->width) +
- channel_offset_list[c] *
- static_cast<size_t>(exr_image->width)));
- line_ptr[x] = val;
+ // line_ptr[x] = val;
+ tinyexr::cpy4(line_ptr + x, &val);
}
}
}
@@ -11522,9 +11943,9 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} else if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
#if TINYEXR_USE_PIZ
unsigned int bufLen =
- 1024 + static_cast<unsigned int>(
- 1.2 * static_cast<unsigned int>(
- buf.size())); // @fixme { compute good bound. }
+ 8192 + static_cast<unsigned int>(
+ 2 * static_cast<unsigned int>(
+ buf.size())); // @fixme { compute good bound. }
std::vector<unsigned char> block(bufLen);
unsigned int outSize = static_cast<unsigned int>(block.size());
@@ -11583,13 +12004,12 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
} // omp parallel
for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
- data.insert(data.end(), data_list[i].begin(), data_list[i].end());
-
offsets[i] = offset;
tinyexr::swap8(reinterpret_cast<tinyexr::tinyexr_uint64 *>(&offsets[i]));
offset += data_list[i].size();
}
+ size_t totalSize = static_cast<size_t>(offset);
{
memory.insert(
memory.end(), reinterpret_cast<unsigned char *>(&offsets.at(0)),
@@ -11597,41 +12017,44 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
}
- { memory.insert(memory.end(), data.begin(), data.end()); }
-
- assert(memory.size() > 0);
+ if ( memory.size() == 0 ) {
+ tinyexr::SetErrorMessage("Output memory size is zero", err);
+ return 0;
+ }
- (*memory_out) = static_cast<unsigned char *>(malloc(memory.size()));
+ (*memory_out) = static_cast<unsigned char *>(malloc(totalSize));
memcpy((*memory_out), &memory.at(0), memory.size());
+ unsigned char *memory_ptr = *memory_out + memory.size();
+
+ for (size_t i = 0; i < static_cast<size_t>(num_blocks); i++) {
+ memcpy(memory_ptr, &data_list[i].at(0), data_list[i].size());
+ memory_ptr += data_list[i].size();
+ }
- return memory.size(); // OK
+ return totalSize; // OK
}
int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
const char *filename, const char **err) {
if (exr_image == NULL || filename == NULL ||
exr_header->compression_type < 0) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for SaveEXRImageToFile", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
#if !TINYEXR_USE_PIZ
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_PIZ) {
- if (err) {
- (*err) = "PIZ compression is not supported in this build.";
- }
- return 0;
+ tinyexr::SetErrorMessage("PIZ compression is not supported in this build",
+ err);
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
}
#endif
#if !TINYEXR_USE_ZFP
if (exr_header->compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
- if (err) {
- (*err) = "ZFP compression is not supported in this build.";
- }
- return 0;
+ tinyexr::SetErrorMessage("ZFP compression is not supported in this build",
+ err);
+ return TINYEXR_ERROR_UNSUPPORTED_FEATURE;
}
#endif
@@ -11642,48 +12065,51 @@ int SaveEXRImageToFile(const EXRImage *exr_image, const EXRHeader *exr_header,
FILE *fp = fopen(filename, "wb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot write a file.";
- }
- return TINYEXR_ERROR_CANT_OPEN_FILE;
+ tinyexr::SetErrorMessage("Cannot write a file", err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
}
unsigned char *mem = NULL;
size_t mem_size = SaveEXRImageToMemory(exr_image, exr_header, &mem, err);
+ if (mem_size == 0) {
+ return TINYEXR_ERROR_SERIALZATION_FAILED;
+ }
+ size_t written_size = 0;
if ((mem_size > 0) && mem) {
- fwrite(mem, 1, mem_size, fp);
+ written_size = fwrite(mem, 1, mem_size, fp);
}
free(mem);
fclose(fp);
+ if (written_size != mem_size) {
+ tinyexr::SetErrorMessage("Cannot write a file", err);
+ return TINYEXR_ERROR_CANT_WRITE_FILE;
+ }
+
return TINYEXR_SUCCESS;
}
int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (deep_image == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for LoadDeepEXR", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
#ifdef _MSC_VER
FILE *fp = NULL;
errno_t errcode = fopen_s(&fp, filename, "rb");
- if ((!errcode) || (!fp)) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ if ((0 != errcode) || (!fp)) {
+ tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
+ err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#else
FILE *fp = fopen(filename, "rb");
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read a file " + std::string(filename),
+ err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
#endif
@@ -11696,9 +12122,8 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (filesize == 0) {
fclose(fp);
- if (err) {
- (*err) = "File size is zero.";
- }
+ tinyexr::SetErrorMessage("File size is zero : " + std::string(filename),
+ err);
return TINYEXR_ERROR_INVALID_FILE;
}
@@ -11719,9 +12144,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
const char header[] = {0x76, 0x2f, 0x31, 0x01};
if (memcmp(marker, header, 4) != 0) {
- if (err) {
- (*err) = "Invalid magic number.";
- }
+ tinyexr::SetErrorMessage("Invalid magic number", err);
return TINYEXR_ERROR_INVALID_MAGIC_NUMBER;
}
marker += 4;
@@ -11732,9 +12155,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
// ver 2.0, scanline, deep bit on(0x800)
// must be [2, 0, 0, 0]
if (marker[0] != 2 || marker[1] != 8 || marker[2] != 0 || marker[3] != 0) {
- if (err) {
- (*err) = "Unsupported version or scanline.";
- }
+ tinyexr::SetErrorMessage("Unsupported version or scanline", err);
return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
}
@@ -11775,9 +12196,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (attr_name.compare("compression") == 0) {
compression_type = data[0];
if (compression_type > TINYEXR_COMPRESSIONTYPE_PIZ) {
- if (err) {
- (*err) = "Unsupported compression type.";
- }
+ std::stringstream ss;
+ ss << "Unsupported compression type : " << compression_type;
+ tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
}
@@ -11794,18 +12215,14 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
// ySampling: int
if (!tinyexr::ReadChannelInfo(channels, data)) {
- if (err) {
- (*err) = "Failed to parse channel info.";
- }
+ tinyexr::SetErrorMessage("Failed to parse channel info", err);
return TINYEXR_ERROR_INVALID_DATA;
}
num_channels = static_cast<int>(channels.size());
if (num_channels < 1) {
- if (err) {
- (*err) = "Invalid channels format.";
- }
+ tinyexr::SetErrorMessage("Invalid channels format", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -11877,9 +12294,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
#endif
// OK
} else {
- if (err) {
- (*err) = "Unsupported format.";
- }
+ tinyexr::SetErrorMessage("Unsupported compression format", err);
return TINYEXR_ERROR_UNSUPPORTED_FORMAT;
}
@@ -11936,8 +12351,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
unsigned long dstLen =
static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int));
if (!tinyexr::DecompressZip(
- reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)), &dstLen,
- data_ptr + 28, static_cast<unsigned long>(packedOffsetTableSize))) {
+ reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)),
+ &dstLen, data_ptr + 28,
+ static_cast<unsigned long>(packedOffsetTableSize))) {
return false;
}
@@ -11955,9 +12371,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
if (dstLen) {
if (!tinyexr::DecompressZip(
- reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
- data_ptr + 28 + packedOffsetTableSize,
- static_cast<unsigned long>(packedSampleDataSize))) {
+ reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
+ data_ptr + 28 + packedOffsetTableSize,
+ static_cast<unsigned long>(packedSampleDataSize))) {
return false;
}
assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
@@ -12006,8 +12422,10 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
if (channels[c].pixel_type == 0) { // UINT
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
- unsigned int ui = *reinterpret_cast<unsigned int *>(
+ unsigned int ui;
+ unsigned int *src_ptr = reinterpret_cast<unsigned int *>(
&sample_data.at(size_t(data_offset) + x * sizeof(int)));
+ tinyexr::cpy4(&ui, src_ptr);
deep_image->image[c][y][x] = static_cast<float>(ui); // @fixme
}
data_offset +=
@@ -12015,16 +12433,19 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
} else if (channels[c].pixel_type == 1) { // half
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
tinyexr::FP16 f16;
- f16.u = *reinterpret_cast<unsigned short *>(
+ const unsigned short *src_ptr = reinterpret_cast<unsigned short *>(
&sample_data.at(size_t(data_offset) + x * sizeof(short)));
+ tinyexr::cpy2(&(f16.u), src_ptr);
tinyexr::FP32 f32 = half_to_float(f16);
deep_image->image[c][y][x] = f32.f;
}
data_offset += sizeof(short) * static_cast<size_t>(samples_per_line);
} else { // float
for (size_t x = 0; x < static_cast<size_t>(samples_per_line); x++) {
- float f = *reinterpret_cast<float *>(
+ float f;
+ const float *src_ptr = reinterpret_cast<float *>(
&sample_data.at(size_t(data_offset) + x * sizeof(float)));
+ tinyexr::cpy4(&f, src_ptr);
deep_image->image[c][y][x] = f;
}
data_offset += sizeof(float) * static_cast<size_t>(samples_per_line);
@@ -12065,6 +12486,13 @@ void InitEXRImage(EXRImage *exr_image) {
exr_image->num_tiles = 0;
}
+void FreeEXRErrorMessage(const char *msg) {
+ if (msg) {
+ free(reinterpret_cast<void *>(const_cast<char *>(msg)));
+ }
+ return;
+}
+
void InitEXRHeader(EXRHeader *exr_header) {
if (exr_header == NULL) {
return;
@@ -12096,6 +12524,10 @@ int FreeEXRHeader(EXRHeader *exr_header) {
}
}
+ if (exr_header->custom_attributes) {
+ free(exr_header->custom_attributes);
+ }
+
return TINYEXR_SUCCESS;
}
@@ -12125,6 +12557,7 @@ int FreeEXRImage(EXRImage *exr_image) {
free(exr_image->tiles[tid].images);
}
}
+ free(exr_image->tiles);
}
return TINYEXR_SUCCESS;
@@ -12133,9 +12566,8 @@ int FreeEXRImage(EXRImage *exr_image) {
int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
const char *filename, const char **err) {
if (exr_header == NULL || exr_version == NULL || filename == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage("Invalid argument for ParseEXRHeaderFromFile",
+ err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12146,9 +12578,7 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -12166,9 +12596,8 @@ int ParseEXRHeaderFromFile(EXRHeader *exr_header, const EXRVersion *exr_version,
fclose(fp);
if (ret != filesize) {
- if (err) {
- (*err) = "fread error.";
- }
+ tinyexr::SetErrorMessage("fread() error on " + std::string(filename),
+ err);
return TINYEXR_ERROR_INVALID_FILE;
}
}
@@ -12185,10 +12614,13 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
if (memory == NULL || exr_headers == NULL || num_headers == NULL ||
exr_version == NULL) {
// Invalid argument
+ tinyexr::SetErrorMessage(
+ "Invalid argument for ParseEXRMultipartHeaderFromMemory", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
if (size < tinyexr::kEXRVersionSize) {
+ tinyexr::SetErrorMessage("Data size too short", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -12207,13 +12639,7 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
marker, marker_size);
if (ret != TINYEXR_SUCCESS) {
- if (err) {
-#ifdef _WIN32
- (*err) = _strdup(err_str.c_str()); // may leak
-#else
- (*err) = strdup(err_str.c_str()); // may leak
-#endif
- }
+ tinyexr::SetErrorMessage(err_str, err);
return ret;
}
@@ -12224,9 +12650,8 @@ int ParseEXRMultipartHeaderFromMemory(EXRHeader ***exr_headers,
// `chunkCount` must exist in the header.
if (info.chunk_count == 0) {
- if (err) {
- (*err) = "`chunkCount' attribute is not found in the header.";
- }
+ tinyexr::SetErrorMessage(
+ "`chunkCount' attribute is not found in the header.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -12261,9 +12686,8 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
const char *filename, const char **err) {
if (exr_headers == NULL || num_headers == NULL || exr_version == NULL ||
filename == NULL) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument for ParseEXRMultipartHeaderFromFile()", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12274,9 +12698,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -12294,9 +12716,7 @@ int ParseEXRMultipartHeaderFromFile(EXRHeader ***exr_headers, int *num_headers,
fclose(fp);
if (ret != filesize) {
- if (err) {
- (*err) = "fread error.";
- }
+ tinyexr::SetErrorMessage("`fread' error. file may be corrupted.", err);
return TINYEXR_ERROR_INVALID_FILE;
}
}
@@ -12405,9 +12825,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
const size_t size, const char **err) {
if (exr_images == NULL || exr_headers == NULL || num_parts == 0 ||
memory == NULL || (size <= tinyexr::kEXRVersionSize)) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument for LoadEXRMultipartImageFromMemory()", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12415,9 +12834,7 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
size_t total_header_size = 0;
for (unsigned int i = 0; i < num_parts; i++) {
if (exr_headers[i]->header_len == 0) {
- if (err) {
- (*err) = "EXRHeader is not initialized.";
- }
+ tinyexr::SetErrorMessage("EXRHeader variable is not initialized.", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12452,9 +12869,8 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
tinyexr::swap8(&offset);
if (offset >= size) {
- if (err) {
- (*err) = "Invalid offset size.";
- }
+ tinyexr::SetErrorMessage("Invalid offset size in EXR header chunks.",
+ err);
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -12479,14 +12895,19 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
tinyexr::swap4(&part_no);
if (part_no != i) {
- assert(0);
+ tinyexr::SetErrorMessage("Invalid `part number' in EXR header chunks.",
+ err);
return TINYEXR_ERROR_INVALID_DATA;
}
}
+ std::string e;
int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
- memory, size);
+ memory, size, &e);
if (ret != TINYEXR_SUCCESS) {
+ if (!e.empty()) {
+ tinyexr::SetErrorMessage(e, err);
+ }
return ret;
}
}
@@ -12499,9 +12920,8 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
unsigned int num_parts, const char *filename,
const char **err) {
if (exr_images == NULL || exr_headers == NULL || num_parts == 0) {
- if (err) {
- (*err) = "Invalid argument.";
- }
+ tinyexr::SetErrorMessage(
+ "Invalid argument for LoadEXRMultipartImageFromFile", err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
@@ -12512,9 +12932,7 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
FILE *fp = fopen(filename, "rb");
#endif
if (!fp) {
- if (err) {
- (*err) = "Cannot read file.";
- }
+ tinyexr::SetErrorMessage("Cannot read file " + std::string(filename), err);
return TINYEXR_ERROR_CANT_OPEN_FILE;
}
@@ -12538,20 +12956,27 @@ int LoadEXRMultipartImageFromFile(EXRImage *exr_images,
}
int SaveEXR(const float *data, int width, int height, int components,
- const int save_as_fp16, const char *outfilename) {
+ const int save_as_fp16, const char *outfilename, const char **err) {
if ((components == 1) || components == 3 || components == 4) {
// OK
} else {
+ std::stringstream ss;
+ ss << "Unsupported component value : " << components << std::endl;
+
+ tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_INVALID_ARGUMENT;
}
- // Assume at least 16x16 pixels.
- if (width < 16) return TINYEXR_ERROR_INVALID_ARGUMENT;
- if (height < 16) return TINYEXR_ERROR_INVALID_ARGUMENT;
-
EXRHeader header;
InitEXRHeader(&header);
+ if ((width < 16) && (height < 16)) {
+ // No compression for small image.
+ header.compression_type = TINYEXR_COMPRESSIONTYPE_NONE;
+ } else {
+ header.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
+ }
+
EXRImage image;
InitEXRImage(&image);
@@ -12657,8 +13082,7 @@ int SaveEXR(const float *data, int width, int height, int components,
}
}
- const char *err;
- int ret = SaveEXRImageToFile(&image, &header, outfilename, &err);
+ int ret = SaveEXRImageToFile(&image, &header, outfilename, err);
if (ret != TINYEXR_SUCCESS) {
return ret;
}
@@ -12670,5 +13094,10 @@ int SaveEXR(const float *data, int width, int height, int components,
return ret;
}
+#ifdef __clang__
+// zero-as-null-ppinter-constant
+#pragma clang diagnostic pop
+#endif
+
#endif // TINYEXR_IMPLEMENTATION_DEIFNED
#endif // TINYEXR_IMPLEMENTATION