tinyexr: Sync with upstream a685e33
This commit is contained in:
parent
49ce6bacc3
commit
b5b3aa920b
|
@ -351,7 +351,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
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue