summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/bimg/3rdparty/tinyexr/tinyexr.h
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/bimg/3rdparty/tinyexr/tinyexr.h')
-rw-r--r--3rdparty/bimg/3rdparty/tinyexr/tinyexr.h227
1 files changed, 176 insertions, 51 deletions
diff --git a/3rdparty/bimg/3rdparty/tinyexr/tinyexr.h b/3rdparty/bimg/3rdparty/tinyexr/tinyexr.h
index cda32f456c9..a02b913e694 100644
--- a/3rdparty/bimg/3rdparty/tinyexr/tinyexr.h
+++ b/3rdparty/bimg/3rdparty/tinyexr/tinyexr.h
@@ -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.
Redistribution and use in source and binary forms, with or without
@@ -111,13 +111,13 @@ extern "C" {
#define TINYEXR_ERROR_INVALID_ARGUMENT (-3)
#define TINYEXR_ERROR_INVALID_DATA (-4)
#define TINYEXR_ERROR_INVALID_FILE (-5)
-#define TINYEXR_ERROR_INVALID_PARAMETER (-5)
-#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)
+#define TINYEXR_ERROR_INVALID_PARAMETER (-6)
+#define TINYEXR_ERROR_CANT_OPEN_FILE (-7)
+#define TINYEXR_ERROR_UNSUPPORTED_FORMAT (-8)
+#define TINYEXR_ERROR_INVALID_HEADER (-9)
+#define TINYEXR_ERROR_UNSUPPORTED_FEATURE (-10)
+#define TINYEXR_ERROR_CANT_WRITE_FILE (-11)
+#define TINYEXR_ERROR_SERIALZATION_FAILED (-12)
// @note { OpenEXR file format: http://www.openexr.com/openexrfilelayout.pdf }
@@ -276,7 +276,8 @@ extern int LoadEXR(float **out_rgba, int *width, int *height,
// @deprecated { to be removed. }
// Simple wrapper API for ParseEXRHeaderFromFile.
// 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);
// @deprecated { to be removed. }
@@ -469,9 +470,10 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#include <cstdio>
#include <cstdlib>
#include <cstring>
-#include <iostream>
#include <sstream>
+//#include <iostream> // debug
+
#include <limits>
#include <string>
#include <vector>
@@ -557,6 +559,10 @@ namespace miniz {
#pragma clang diagnostic ignored "-Wtautological-constant-compare"
#endif
+#if __has_warning("-Wextra-semi-stmt")
+#pragma clang diagnostic ignored "-Wextra-semi-stmt"
+#endif
+
#endif
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
@@ -2551,10 +2557,10 @@ tinfl_status tinfl_decompress(tinfl_decompressor *r,
tinfl_status status = TINFL_STATUS_FAILED;
mz_uint32 num_bits, dist, counter, num_extra;
tinfl_bit_buf_t bit_buf;
- const mz_uint8 *pIn_buf_cur = pIn_buf_next,
- *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
- mz_uint8 *pOut_buf_cur = pOut_buf_next,
- *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
+ const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end =
+ pIn_buf_next + *pIn_buf_size;
+ mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end =
+ pOut_buf_next + *pOut_buf_size;
size_t out_buf_size_mask =
(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)
? (size_t)-1
@@ -2971,8 +2977,9 @@ 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;
@@ -3025,9 +3032,8 @@ int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size,
tinfl_status status =
tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs,
&in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
- (flags &
- ~(TINFL_FLAG_HAS_MORE_INPUT |
- TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
+ (flags & ~(TINFL_FLAG_HAS_MORE_INPUT |
+ TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
in_buf_ofs += in_buf_size;
if ((dst_buf_size) &&
(!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
@@ -3152,7 +3158,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
// 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,
tdefl_sym_freq *pSyms0,
tdefl_sym_freq *pSyms1) {
@@ -5296,9 +5304,10 @@ 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';
@@ -7022,6 +7031,11 @@ static void swap2(unsigned short *val) {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif
+
+#ifdef __GNUC__
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-function"
+#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);
@@ -7051,11 +7065,14 @@ static void cpy4(float *dst_val, const float *src_val) {
dst[2] = src[2];
dst[3] = src[3];
}
-
#ifdef __clang__
#pragma clang diagnostic pop
#endif
+#ifdef __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
static void swap4(unsigned int *val) {
#ifdef MINIZ_LITTLE_ENDIAN
(void)val;
@@ -7626,6 +7643,9 @@ static bool DecompressZip(unsigned char *dst,
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wsign-conversion"
+#if __has_warning("-Wextra-semi-stmt")
+#pragma clang diagnostic ignored "-Wextra-semi-stmt"
+#endif
#endif
#ifdef _MSC_VER
@@ -7710,7 +7730,8 @@ static int rleUncompress(int inLength, int maxLength, const signed char in[],
int count = -(static_cast<int>(*in++));
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);
out += count;
@@ -7804,13 +7825,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 char *src, unsigned long src_size) {
if (uncompressed_size == src_size) {
// Data is not compressed(Issue 40).
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);
@@ -7819,8 +7846,9 @@ static void DecompressRle(unsigned char *dst,
static_cast<int>(uncompressed_size),
reinterpret_cast<const signed char *>(src),
reinterpret_cast<char *>(&tmpBuf.at(0)));
- assert(ret == static_cast<int>(uncompressed_size));
- (void)ret;
+ if (ret != static_cast<int>(uncompressed_size)) {
+ return false;
+ }
//
// Apply EXR-specific? postprocess. Grabbed from OpenEXR's
@@ -7859,6 +7887,8 @@ static void DecompressRle(unsigned char *dst,
break;
}
}
+
+ return true;
}
#if TINYEXR_USE_PIZ
@@ -7877,6 +7907,10 @@ static void DecompressRle(unsigned char *dst,
#pragma clang diagnostic ignored "-Wcast-qual"
#endif
+#if __has_warning("-Wextra-semi-stmt")
+#pragma clang diagnostic ignored "-Wextra-semi-stmt"
+#endif
+
#endif
//
@@ -8570,7 +8604,7 @@ static bool hufUnpackEncTable(
int lc = 0;
for (; im <= iM; im++) {
- if (p - *pcode > ni) {
+ if (p - *pcode >= ni) {
return false;
}
@@ -9362,6 +9396,10 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
ptr += sizeof(int);
+ if (size_t((ptr - inPtr) + length) > inLen) {
+ return false;
+ }
+
std::vector<unsigned short> tmpBuffer(tmpBufSize);
hufUncompress(reinterpret_cast<const char *>(ptr), length, &tmpBuffer);
@@ -9656,8 +9694,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
reinterpret_cast<unsigned char *>(&outBuf.at(0)), data_ptr, tmpBufLen,
data_len, static_cast<int>(num_channels), channels, width, num_lines);
- assert(ret);
- (void)ret;
+ if (!ret) {
+ return false;
+ }
// For PIZ_COMPRESSION:
// pixel sample data for channel 0 for scanline 0
@@ -9702,16 +9741,18 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
} else { // HALF -> FLOAT
FP32 f32 = half_to_float(hf);
float *image = reinterpret_cast<float **>(out_images)[c];
+ size_t offset = 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) +
u;
} else {
- image += static_cast<size_t>(
+ offset = static_cast<size_t>(
(height - 1 - (line_no + static_cast<int>(v)))) *
static_cast<size_t>(x_stride) +
u;
}
+ image += offset;
*image = f32.f;
}
}
@@ -9838,16 +9879,19 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
} else { // HALF -> FLOAT
tinyexr::FP32 f32 = half_to_float(hf);
float *image = reinterpret_cast<float **>(out_images)[c];
+ size_t offset = 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) +
u;
} 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>(x_stride) +
u;
}
+ image += offset;
+
*image = f32.f;
}
}
@@ -9920,10 +9964,15 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
pixel_data_size);
unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
- assert(dstLen > 0);
- tinyexr::DecompressRle(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
+ if (dstLen == 0) {
+ return false;
+ }
+
+ if (!tinyexr::DecompressRle(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
dstLen, data_ptr,
- static_cast<unsigned long>(data_len));
+ static_cast<unsigned long>(data_len))) {
+ return false;
+ }
// For RLE_COMPRESSION:
// pixel sample data for channel 0 for scanline 0
@@ -10753,12 +10802,28 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
if ((data_width < 0) || (data_height < 0)) {
if (err) {
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();
}
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();
std::vector<size_t> channel_offset_list;
@@ -10776,6 +10841,25 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
bool invalid_data = false; // TODO(LTE): Use atomic lock for MT safety.
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
exr_image->tiles = static_cast<EXRTile *>(
@@ -10854,12 +10938,17 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
}
} else { // scanline format
- // Don't allow too large image(256GB * pixel_data_size or more). Workaround for #104.
- size_t data_len0 = size_t(data_width) * size_t(data_height) * size_t(num_channels);
- if ((data_len0 == 0) || (data_len0 >= 0x4000000000)) {
+ // Don't allow too large image(256GB * pixel_data_size or more). Workaround
+ // for #104.
+ 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) {
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();
}
return TINYEXR_ERROR_INVALID_DATA;
@@ -10894,12 +10983,21 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
if (size_t(data_len) > data_size) {
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 {
+ // line_no may be negative.
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;
@@ -10908,7 +11006,16 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
data_ptr += 8;
// Adjust line_no with data_window.bmin.y
- line_no -= exr_header->data_window[1];
+
+ // 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];
+ }
if (line_no < 0) {
invalid_data = true;
@@ -10933,6 +11040,10 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
}
if (invalid_data) {
+ if (err) {
+ std::stringstream ss;
+ (*err) += "Invalid data found when decoding pixels.\n";
+ }
return TINYEXR_ERROR_INVALID_DATA;
}
@@ -11009,7 +11120,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
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);
+ tinyexr::SetErrorMessage("Invalid data width value", err);
return TINYEXR_ERROR_INVALID_DATA;
}
data_width++;
@@ -11022,10 +11133,23 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
data_height++;
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;
}
+ // 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.
size_t num_blocks = 0;
@@ -11204,7 +11328,6 @@ int LoadEXR(float **out_rgba, int *width, int *height, const char *filename,
static_cast<size_t>(exr_image.height)));
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++) {
@@ -11448,7 +11571,6 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
static_cast<size_t>(exr_image.height)));
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++) {
@@ -12129,7 +12251,7 @@ size_t SaveEXRImageToMemory(const EXRImage *exr_image,
sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(num_blocks));
}
- if ( memory.size() == 0 ) {
+ if (memory.size() == 0) {
tinyexr::SetErrorMessage("Output memory size is zero", err);
return 0;
}
@@ -12300,6 +12422,9 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
size_t marker_size;
if (!tinyexr::ReadAttribute(&attr_name, &attr_type, &data, &marker_size,
marker, size)) {
+ std::stringstream ss;
+ ss << "Failed to parse attribute\n";
+ tinyexr::SetErrorMessage(ss.str(), err);
return TINYEXR_ERROR_INVALID_DATA;
}
marker += marker_size;