tinyexr: Sync with upstream a685e33

(cherry picked from commit b5b3aa920b)
This commit is contained in:
Rémi Verschelde 2019-07-11 10:34:40 +02:00
parent 8067207257
commit 2e98ecd95f
2 changed files with 161 additions and 47 deletions

View File

@ -371,7 +371,7 @@ License: Expat
Files: ./thirdparty/tinyexr/ Files: ./thirdparty/tinyexr/
Comment: TinyEXR Comment: TinyEXR
Copyright: 2014-2018, Syoyo Fujita Copyright: 2014-2019, Syoyo Fujita
2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC 2002, Industrial Light & Magic, a division of Lucas Digital Ltd. LLC
License: BSD-3-clause License: BSD-3-clause

View File

@ -1,5 +1,5 @@
/* /*
Copyright (c) 2014 - 2018, Syoyo Fujita and many contributors. Copyright (c) 2014 - 2019, Syoyo Fujita and many contributors.
All rights reserved. All rights reserved.
Redistribution and use in source and binary forms, with or without Redistribution and use in source and binary forms, with or without
@ -276,7 +276,8 @@ extern int LoadEXR(float **out_rgba, int *width, int *height,
// @deprecated { to be removed. } // @deprecated { to be removed. }
// Simple wrapper API for ParseEXRHeaderFromFile. // Simple wrapper API for ParseEXRHeaderFromFile.
// checking given file is a EXR file(by just look up header) // checking given file is a EXR file(by just look up header)
// @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for others // @return TINYEXR_SUCCEES for EXR image, TINYEXR_ERROR_INVALID_HEADER for
// others
extern int IsEXR(const char *filename); extern int IsEXR(const char *filename);
// @deprecated { to be removed. } // @deprecated { to be removed. }
@ -469,9 +470,10 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <iostream>
#include <sstream> #include <sstream>
//#include <iostream> // debug
#include <limits> #include <limits>
#include <string> #include <string>
#include <vector> #include <vector>
@ -2537,10 +2539,10 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r,
tinfl_status status = TINFL_STATUS_FAILED; tinfl_status status = TINFL_STATUS_FAILED;
mz_uint32 num_bits, dist, counter, num_extra; mz_uint32 num_bits, dist, counter, num_extra;
tinfl_bit_buf_t bit_buf; tinfl_bit_buf_t bit_buf;
const mz_uint8 *pIn_buf_cur = pIn_buf_next, const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
*const pIn_buf_end = pIn_buf_next + *pIn_buf_size; pIn_buf_next + *pIn_buf_size;
mz_uint8 *pOut_buf_cur = pOut_buf_next, mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
*const pOut_buf_end = pOut_buf_next + *pOut_buf_size; pOut_buf_next + *pOut_buf_size;
size_t out_buf_size_mask = size_t out_buf_size_mask =
(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
? (size_t)-1 ? (size_t)-1
@ -2957,7 +2959,8 @@ void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len,
tinfl_status status = tinfl_decompress( tinfl_status status = tinfl_decompress(
&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, &decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size,
(mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL,
&dst_buf_size, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | &dst_buf_size,
(flags & ~TINFL_FLAG_HAS_MORE_INPUT) |
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF); TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) { if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT)) {
MZ_FREE(pBuf); MZ_FREE(pBuf);
@ -3011,8 +3014,7 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
tinfl_status status = tinfl_status status =
tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
&in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
(flags & (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
~(TINFL_FLAG_HAS_MORE_INPUT |
TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))); TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
in_buf_ofs += in_buf_size; in_buf_ofs += in_buf_size;
if ((dst_buf_size) && if ((dst_buf_size) &&
@ -3138,7 +3140,9 @@ static const mz_uint8 s_tdefl_large_dist_extra[128] = {
// Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted // Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted
// values. // values.
typedef struct { mz_uint16 m_key, m_sym_index; } tdefl_sym_freq; typedef struct {
mz_uint16 m_key, m_sym_index;
} tdefl_sym_freq;
static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms,
tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms0,
tdefl_sym_freq *pSyms1) { tdefl_sym_freq *pSyms1) {
@ -5282,7 +5286,8 @@ 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_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1); n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
pStat->m_comment_size = n; pStat->m_comment_size = n;
memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + 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_FILENAME_LEN_OFS) +
MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS),
n); n);
@ -7008,6 +7013,11 @@ static void swap2(unsigned short *val) {
#pragma clang diagnostic push #pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function" #pragma clang diagnostic ignored "-Wunused-function"
#endif #endif
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-function"
#endif
static void cpy4(int *dst_val, const int *src_val) { static void cpy4(int *dst_val, const int *src_val) {
unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val); unsigned char *dst = reinterpret_cast<unsigned char *>(dst_val);
const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val); const unsigned char *src = reinterpret_cast<const unsigned char *>(src_val);
@ -7037,11 +7047,14 @@ static void cpy4(float *dst_val, const float *src_val) {
dst[2] = src[2]; dst[2] = src[2];
dst[3] = src[3]; dst[3] = src[3];
} }
#ifdef __clang__ #ifdef __clang__
#pragma clang diagnostic pop #pragma clang diagnostic pop
#endif #endif
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
static void swap4(unsigned int *val) { static void swap4(unsigned int *val) {
#ifdef MINIZ_LITTLE_ENDIAN #ifdef MINIZ_LITTLE_ENDIAN
(void)val; (void)val;
@ -7696,7 +7709,8 @@ static int rleUncompress(int inLength, int maxLength, const signed char in[],
int count = -(static_cast<int>(*in++)); int count = -(static_cast<int>(*in++));
inLength -= count + 1; inLength -= count + 1;
if (0 > (maxLength -= count)) return 0; // Fixes #116: Add bounds check to in buffer.
if ((0 > (maxLength -= count)) || (inLength < 0)) return 0;
memcpy(out, in, count); memcpy(out, in, count);
out += count; out += count;
@ -7790,13 +7804,19 @@ static void CompressRle(unsigned char *dst,
} }
} }
static void DecompressRle(unsigned char *dst, static bool DecompressRle(unsigned char *dst,
const unsigned long uncompressed_size, const unsigned long uncompressed_size,
const unsigned char *src, unsigned long src_size) { const unsigned char *src, unsigned long src_size) {
if (uncompressed_size == src_size) { if (uncompressed_size == src_size) {
// Data is not compressed(Issue 40). // Data is not compressed(Issue 40).
memcpy(dst, src, src_size); memcpy(dst, src, src_size);
return; return true;
}
// Workaround for issue #112.
// TODO(syoyo): Add more robust out-of-bounds check in `rleUncompress`.
if (src_size <= 2) {
return false;
} }
std::vector<unsigned char> tmpBuf(uncompressed_size); std::vector<unsigned char> tmpBuf(uncompressed_size);
@ -7805,8 +7825,9 @@ static void DecompressRle(unsigned char *dst,
static_cast<int>(uncompressed_size), static_cast<int>(uncompressed_size),
reinterpret_cast<const signed char *>(src), reinterpret_cast<const signed char *>(src),
reinterpret_cast<char *>(&tmpBuf.at(0))); reinterpret_cast<char *>(&tmpBuf.at(0)));
assert(ret == static_cast<int>(uncompressed_size)); if (ret != static_cast<int>(uncompressed_size)) {
(void)ret; return false;
}
// //
// Apply EXR-specific? postprocess. Grabbed from OpenEXR's // Apply EXR-specific? postprocess. Grabbed from OpenEXR's
@ -7845,6 +7866,8 @@ static void DecompressRle(unsigned char *dst,
break; break;
} }
} }
return true;
} }
#if TINYEXR_USE_PIZ #if TINYEXR_USE_PIZ
@ -8556,7 +8579,7 @@ static bool hufUnpackEncTable(
int lc = 0; int lc = 0;
for (; im <= iM; im++) { for (; im <= iM; im++) {
if (p - *pcode > ni) { if (p - *pcode >= ni) {
return false; return false;
} }
@ -9348,6 +9371,10 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr)); tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
ptr += sizeof(int); ptr += sizeof(int);
if (size_t((ptr - inPtr) + length) > inLen) {
return false;
}
std::vector<unsigned short> tmpBuffer(tmpBufSize); std::vector<unsigned short> tmpBuffer(tmpBufSize);
hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer); hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
@ -9642,8 +9669,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen, reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen,
data_len, static_cast<int>(num_channels), channels, width, num_lines); data_len, static_cast<int>(num_channels), channels, width, num_lines);
assert(ret); if (!ret) {
(void)ret; return false;
}
// For PIZ_COMPRESSION: // For PIZ_COMPRESSION:
// pixel sample data for channel 0 for scanline 0 // pixel sample data for channel 0 for scanline 0
@ -9688,16 +9716,18 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
} else { // HALF -> FLOAT } else { // HALF -> FLOAT
FP32 f32 = half_to_float(hf); FP32 f32 = half_to_float(hf);
float *image = reinterpret_cast<float **>(out_images)[c]; float *image = reinterpret_cast<float **>(out_images)[c];
size_t offset = 0;
if (line_order == 0) { if (line_order == 0) {
image += (static_cast<size_t>(line_no) + v) * offset = (static_cast<size_t>(line_no) + v) *
static_cast<size_t>(x_stride) + static_cast<size_t>(x_stride) +
u; u;
} else { } else {
image += static_cast<size_t>( offset = static_cast<size_t>(
(height - 1 - (line_no + static_cast<int>(v)))) * (height - 1 - (line_no + static_cast<int>(v)))) *
static_cast<size_t>(x_stride) + static_cast<size_t>(x_stride) +
u; u;
} }
image += offset;
*image = f32.f; *image = f32.f;
} }
} }
@ -9824,16 +9854,19 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
} else { // HALF -> FLOAT } else { // HALF -> FLOAT
tinyexr::FP32 f32 = half_to_float(hf); tinyexr::FP32 f32 = half_to_float(hf);
float *image = reinterpret_cast<float **>(out_images)[c]; float *image = reinterpret_cast<float **>(out_images)[c];
size_t offset = 0;
if (line_order == 0) { if (line_order == 0) {
image += (static_cast<size_t>(line_no) + v) * offset = (static_cast<size_t>(line_no) + v) *
static_cast<size_t>(x_stride) + static_cast<size_t>(x_stride) +
u; u;
} else { } else {
image += (static_cast<size_t>(height) - 1U - offset = (static_cast<size_t>(height) - 1U -
(static_cast<size_t>(line_no) + v)) * (static_cast<size_t>(line_no) + v)) *
static_cast<size_t>(x_stride) + static_cast<size_t>(x_stride) +
u; u;
} }
image += offset;
*image = f32.f; *image = f32.f;
} }
} }
@ -9906,10 +9939,15 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
pixel_data_size); pixel_data_size);
unsigned long dstLen = static_cast<unsigned long>(outBuf.size()); unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
assert(dstLen > 0); if (dstLen == 0) {
tinyexr::DecompressRle(reinterpret_cast<unsigned char *>(&outBuf.at(0)), return false;
}
if (!tinyexr::DecompressRle(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
dstLen, data_ptr, dstLen, data_ptr,
static_cast<unsigned long>(data_len)); static_cast<unsigned long>(data_len))) {
return false;
}
// For RLE_COMPRESSION: // For RLE_COMPRESSION:
// pixel sample data for channel 0 for scanline 0 // pixel sample data for channel 0 for scanline 0
@ -10739,12 +10777,28 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
if ((data_width < 0) || (data_height < 0)) { if ((data_width < 0) || (data_height < 0)) {
if (err) { if (err) {
std::stringstream ss; std::stringstream ss;
ss << "Invalid data width or data height: " << data_width << ", " << data_height << std::endl; ss << "Invalid data width or data height: " << data_width << ", "
<< data_height << std::endl;
(*err) += ss.str(); (*err) += ss.str();
} }
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} }
// Do not allow too large data_width and data_height. header invalid?
{
const int threshold = 1024 * 8192; // heuristics
if ((data_width > threshold) || (data_height > threshold)) {
if (err) {
std::stringstream ss;
ss << "data_with or data_height too large. data_width: " << data_width
<< ", "
<< "data_height = " << data_height << std::endl;
(*err) += ss.str();
}
return TINYEXR_ERROR_INVALID_DATA;
}
}
size_t num_blocks = offsets.size(); size_t num_blocks = offsets.size();
std::vector<size_t> channel_offset_list; std::vector<size_t> channel_offset_list;
@ -10762,6 +10816,25 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety. bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
if (exr_header->tiled) { if (exr_header->tiled) {
// value check
if (exr_header->tile_size_x < 0) {
if (err) {
std::stringstream ss;
ss << "Invalid tile size x : " << exr_header->tile_size_x << "\n";
(*err) += ss.str();
}
return TINYEXR_ERROR_INVALID_HEADER;
}
if (exr_header->tile_size_y < 0) {
if (err) {
std::stringstream ss;
ss << "Invalid tile size y : " << exr_header->tile_size_y << "\n";
(*err) += ss.str();
}
return TINYEXR_ERROR_INVALID_HEADER;
}
size_t num_tiles = offsets.size(); // = # of blocks size_t num_tiles = offsets.size(); // = # of blocks
exr_image->tiles = static_cast<EXRTile *>( exr_image->tiles = static_cast<EXRTile *>(
@ -10840,12 +10913,17 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
} }
} else { // scanline format } else { // scanline format
// Don't allow too large image(256GB * pixel_data_size or more). Workaround for #104. // Don't allow too large image(256GB * pixel_data_size or more). Workaround
size_t data_len = size_t(data_width) * size_t(data_height) * size_t(num_channels); // for #104.
if ((data_len == 0) || (data_len >= 0x4000000000)) { size_t total_data_len =
size_t(data_width) * size_t(data_height) * size_t(num_channels);
const bool total_data_len_overflown = sizeof(void*) == 8 ? (total_data_len >= 0x4000000000) : false;
if ((total_data_len == 0) || total_data_len_overflown ) {
if (err) { if (err) {
std::stringstream ss; std::stringstream ss;
ss << "Image data size is zero or too large: width = " << data_width << ", height = " << data_height << ", channels = " << num_channels << std::endl; ss << "Image data size is zero or too large: width = " << data_width
<< ", height = " << data_height << ", channels = " << num_channels
<< std::endl;
(*err) += ss.str(); (*err) += ss.str();
} }
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
@ -10880,12 +10958,21 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
if (size_t(data_len) > data_size) { if (size_t(data_len) > data_size) {
invalid_data = true; invalid_data = true;
} else if ((line_no > (2 << 20)) || (line_no < -(2 << 20))) {
// Too large value. Assume this is invalid
// 2**20 = 1048576 = heuristic value.
invalid_data = true;
} else if (data_len == 0) {
// TODO(syoyo): May be ok to raise the threshold for example `data_len
// < 4`
invalid_data = true;
} else { } else {
// line_no may be negative.
int end_line_no = (std::min)(line_no + num_scanline_blocks, int end_line_no = (std::min)(line_no + num_scanline_blocks,
(exr_header->data_window[3] + 1)); (exr_header->data_window[3] + 1));
int num_lines = end_line_no - line_no; int num_lines = end_line_no - line_no;
// assert(num_lines > 0);
if (num_lines <= 0) { if (num_lines <= 0) {
invalid_data = true; invalid_data = true;
@ -10894,7 +10981,16 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
data_ptr += 8; data_ptr += 8;
// Adjust line_no with data_window.bmin.y // Adjust line_no with data_window.bmin.y
// overflow check
tinyexr_int64 lno = static_cast<tinyexr_int64>(line_no) - static_cast<tinyexr_int64>(exr_header->data_window[1]);
if (lno > std::numeric_limits<int>::max()) {
line_no = -1; // invalid
} else if (lno < -std::numeric_limits<int>::max()) {
line_no = -1; // invalid
} else {
line_no -= exr_header->data_window[1]; line_no -= exr_header->data_window[1];
}
if (line_no < 0) { if (line_no < 0) {
invalid_data = true; invalid_data = true;
@ -10919,6 +11015,10 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
} }
if (invalid_data) { if (invalid_data) {
if (err) {
std::stringstream ss;
(*err) += "Invalid data found when decoding pixels.\n";
}
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} }
@ -10995,7 +11095,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
int data_width = exr_header->data_window[2] - exr_header->data_window[0]; int data_width = exr_header->data_window[2] - exr_header->data_window[0];
if (data_width >= std::numeric_limits<int>::max()) { if (data_width >= std::numeric_limits<int>::max()) {
// Issue 63 // Issue 63
tinyexr::SetErrorMessage("Invalid data window value", err); tinyexr::SetErrorMessage("Invalid data width value", err);
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} }
data_width++; data_width++;
@ -11008,10 +11108,23 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
data_height++; data_height++;
if ((data_width < 0) || (data_height < 0)) { if ((data_width < 0) || (data_height < 0)) {
tinyexr::SetErrorMessage("data window or data height is negative.", err); tinyexr::SetErrorMessage("data width or data height is negative.", err);
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} }
// Do not allow too large data_width and data_height. header invalid?
{
const int threshold = 1024 * 8192; // heuristics
if (data_width > threshold) {
tinyexr::SetErrorMessage("data width too large.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
if (data_height > threshold) {
tinyexr::SetErrorMessage("data height too large.", err);
return TINYEXR_ERROR_INVALID_DATA;
}
}
// Read offset tables. // Read offset tables.
size_t num_blocks = 0; size_t num_blocks = 0;
@ -11190,7 +11303,6 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
static_cast<size_t>(exr_image.height))); static_cast<size_t>(exr_image.height)));
if (exr_header.tiled) { if (exr_header.tiled) {
for (int it = 0; it < exr_image.num_tiles; it++) { for (int it = 0; it < exr_image.num_tiles; it++) {
for (int j = 0; j < exr_header.tile_size_y; j++) { for (int j = 0; j < exr_header.tile_size_y; j++) {
for (int i = 0; i < exr_header.tile_size_x; i++) { for (int i = 0; i < exr_header.tile_size_x; i++) {
@ -11434,7 +11546,6 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
static_cast<size_t>(exr_image.height))); static_cast<size_t>(exr_image.height)));
if (exr_header.tiled) { if (exr_header.tiled) {
for (int it = 0; it < exr_image.num_tiles; it++) { for (int it = 0; it < exr_image.num_tiles; it++) {
for (int j = 0; j < exr_header.tile_size_y; j++) { for (int j = 0; j < exr_header.tile_size_y; j++) {
for (int i = 0; i < exr_header.tile_size_x; i++) { for (int i = 0; i < exr_header.tile_size_x; i++) {
@ -12286,6 +12397,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
size_t marker_size; size_t marker_size;
if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size, if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
marker, size)) { marker, size)) {
std::stringstream ss;
ss << "Failed to parse attribute\n";
tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_INVALID_DATA; return TINYEXR_ERROR_INVALID_DATA;
} }
marker += marker_size; marker += marker_size;