summaryrefslogtreecommitdiff
path: root/thirdparty/tinyexr/tinyexr.h
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/tinyexr/tinyexr.h')
-rw-r--r--thirdparty/tinyexr/tinyexr.h261
1 files changed, 178 insertions, 83 deletions
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
index 606c19756a..107c22ffb3 100644
--- a/thirdparty/tinyexr/tinyexr.h
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -410,8 +410,8 @@ extern int LoadDeepEXR(DeepImage *out_image, const char *filename,
// Returns negative value and may set error string in `err` when there's an
// error
extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
- const unsigned char *memory, size_t size,
- const char **err);
+ const unsigned char *memory, size_t size,
+ const char **err);
#ifdef __cplusplus
}
@@ -444,7 +444,8 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#if TINYEXR_USE_MINIZ
#else
-// Issue #46. Please include your own zlib-compatible API header before including `tinyexr.h`
+// Issue #46. Please include your own zlib-compatible API header before
+// including `tinyexr.h`
//#include "zlib.h"
#endif
@@ -488,6 +489,12 @@ namespace miniz {
#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
#endif
/* miniz.c v1.15 - public domain deflate/inflate, zlib-subset, ZIP
@@ -6887,8 +6894,6 @@ void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename,
#ifdef _MSC_VER
#pragma warning(pop)
#endif
-
-
}
#else
@@ -7079,11 +7084,18 @@ static FP16 float_to_half_full(FP32 f) {
// #define IMF_B44_COMPRESSION 6
// #define IMF_B44A_COMPRESSION 7
-static const char *ReadString(std::string *s, const char *ptr) {
+static const char *ReadString(std::string *s, const char *ptr, size_t len) {
// Read untile NULL(\0).
const char *p = ptr;
const char *q = ptr;
- while ((*q) != 0) q++;
+ while ((size_t(q - ptr) < len) && (*q) != 0) {
+ q++;
+ }
+
+ if (size_t(q - ptr) >= len) {
+ (*s) = std::string();
+ return NULL;
+ }
(*s) = std::string(p, q);
@@ -7120,6 +7132,10 @@ static bool ReadAttribute(std::string *name, std::string *type,
memcpy(&data_len, marker, sizeof(uint32_t));
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
+ if (data_len == 0) {
+ return false;
+ }
+
marker += sizeof(uint32_t);
size -= sizeof(uint32_t);
@@ -7210,7 +7226,7 @@ typedef struct {
}
} HeaderInfo;
-static void ReadChannelInfo(std::vector<ChannelInfo> &channels,
+static bool ReadChannelInfo(std::vector<ChannelInfo> &channels,
const std::vector<unsigned char> &data) {
const char *p = reinterpret_cast<const char *>(&data.at(0));
@@ -7219,7 +7235,18 @@ static void ReadChannelInfo(std::vector<ChannelInfo> &channels,
break;
}
ChannelInfo info;
- p = ReadString(&info.name, p);
+
+ 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));
+ if ((p == NULL) && (info.name.empty())) {
+ // Buffer overrun. Issue #51.
+ return false;
+ }
memcpy(&info.pixel_type, p, sizeof(int));
p += 4;
@@ -7236,6 +7263,8 @@ static void ReadChannelInfo(std::vector<ChannelInfo> &channels,
channels.push_back(info);
}
+
+ return true;
}
static void WriteChannelInfo(std::vector<unsigned char> &data,
@@ -7361,25 +7390,27 @@ static void CompressZip(unsigned char *dst,
}
}
-static void DecompressZip(unsigned char *dst,
+static bool DecompressZip(unsigned char *dst,
unsigned long *uncompressed_size /* inout */,
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;
}
std::vector<unsigned char> tmpBuf(*uncompressed_size);
#if TINYEXR_USE_MINIZ
int ret =
miniz::mz_uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
- assert(ret == miniz::MZ_OK);
- (void)ret;
+ if (miniz::MZ_OK != ret) {
+ return false;
+ }
#else
int ret = uncompress(&tmpBuf.at(0), uncompressed_size, src, src_size);
- assert(ret == Z_OK);
- (void)ret;
+ if (Z_OK != ret) {
+ return false;
+ }
#endif
//
@@ -7419,6 +7450,8 @@ static void DecompressZip(unsigned char *dst,
break;
}
}
+
+ return true;
}
// RLE code from OpenEXR --------------------------------------
@@ -7443,7 +7476,6 @@ static void DecompressZip(unsigned char *dst,
// conformant name: _strdup.
#endif
-
const int MIN_RUN_LENGTH = 3;
const int MAX_RUN_LENGTH = 127;
@@ -7673,6 +7705,11 @@ static void DecompressRle(unsigned char *dst,
#pragma clang diagnostic ignored "-Wsign-conversion"
#pragma clang diagnostic ignored "-Wc++11-extensions"
#pragma clang diagnostic ignored "-Wconversion"
+
+#if __has_warning("-Wcast-qual")
+#pragma clang diagnostic ignored "-Wcast-qual"
+#endif
+
#endif
//
@@ -8934,7 +8971,6 @@ static void applyLut(const unsigned short lut[USHORT_RANGE],
#pragma warning(pop)
#endif
-
static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
const unsigned char *inPtr, size_t inSize,
const std::vector<ChannelInfo> &channelInfo,
@@ -9373,7 +9409,7 @@ bool CompressZfp(std::vector<unsigned char> *outBuf, unsigned int *outSize,
// -----------------------------------------------------------------
//
-static void DecodePixelData(/* out */ unsigned char **out_images,
+static bool DecodePixelData(/* out */ unsigned char **out_images,
const int *requested_pixel_types,
const unsigned char *data_ptr, size_t data_len,
int compression_type, int line_order, int width,
@@ -9509,6 +9545,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
}
#else
assert(0 && "PIZ is enabled in this build");
+ return false;
#endif
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZIPS ||
@@ -9520,9 +9557,11 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
assert(dstLen > 0);
- tinyexr::DecompressZip(reinterpret_cast<unsigned char *>(&outBuf.at(0)),
+ if (!tinyexr::DecompressZip(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 ZIP_COMPRESSION:
// pixel sample data for channel 0 for scanline 0
@@ -9633,6 +9672,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
}
} else {
assert(0);
+ return false;
}
}
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_RLE) {
@@ -9756,6 +9796,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
}
} else {
assert(0);
+ return false;
}
}
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_ZFP) {
@@ -9764,7 +9805,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
if (!FindZFPCompressionParam(&zfp_compression_param, attributes,
num_attributes)) {
assert(0);
- return;
+ return false;
}
// Allocate original data size.
@@ -9818,6 +9859,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
}
} else {
assert(0);
+ return false;
}
}
#else
@@ -9825,6 +9867,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
(void)num_attributes;
(void)num_channels;
assert(0);
+ return false;
#endif
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
for (size_t c = 0; c < num_channels; c++) {
@@ -9873,6 +9916,7 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
}
} else {
assert(0);
+ return false;
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
const float *line_ptr = reinterpret_cast<const float *>(
@@ -9913,6 +9957,8 @@ static void DecodePixelData(/* out */ unsigned char **out_images,
}
}
}
+
+ return true;
}
static void DecodeTiledPixelData(
@@ -10161,7 +10207,12 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
// xSampling: int
// ySampling: int
- ReadChannelInfo(info->channels, data);
+ if (!ReadChannelInfo(info->channels, data)) {
+ if (err) {
+ (*err) = "Failed to parse channel info.";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
if (info->channels.size() < 1) {
if (err) {
@@ -10173,16 +10224,19 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
has_channels = true;
} else if (attr_name.compare("dataWindow") == 0) {
- 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));
- memcpy(&info->data_window[3], &data.at(12), sizeof(int));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[0]));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[1]));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[2]));
- tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[3]));
-
- has_data_window = true;
+ if (data.size() < 16) {
+ // Corrupsed file(Issue #50).
+ } else {
+ 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));
+ memcpy(&info->data_window[3], &data.at(12), sizeof(int));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[0]));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[1]));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[2]));
+ tinyexr::swap4(reinterpret_cast<unsigned int *>(&info->data_window[3]));
+ 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));
@@ -10268,7 +10322,7 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
}
if (!has_data_window) {
- ss_err << "\"dataWindow\" attribute not found in the header."
+ ss_err << "\"dataWindow\" attribute not found in the header or invalid."
<< std::endl;
}
@@ -10333,7 +10387,7 @@ static void ConvertHeader(EXRHeader *exr_header, const HeaderInfo &info) {
#else
strncpy(exr_header->channels[c].name, info.channels[c].name.c_str(), 255);
#endif
- // manually add '\0' for safety.
+ // manually add '\0' for safety.
exr_header->channels[c].name[255] = '\0';
exr_header->channels[c].pixel_type = info.channels[c].pixel_type;
@@ -10371,7 +10425,7 @@ 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 unsigned char *head, const size_t size) {
int num_channels = exr_header->num_channels;
int num_scanline_blocks = 1;
@@ -10412,6 +10466,11 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
// 16 byte: tile coordinates
// 4 byte : data size
// ~ : data(uncompressed or compressed)
+ if (offsets[tile_idx] + sizeof(int) * 5 > size) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
+ size_t data_size = size - (offsets[tile_idx] + sizeof(int) * 5);
const unsigned char *data_ptr =
reinterpret_cast<const unsigned char *>(head + offsets[tile_idx]);
@@ -10430,7 +10489,10 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
memcpy(&data_len, data_ptr + 16,
sizeof(int)); // 16 = sizeof(tile_coordinates)
tinyexr::swap4(reinterpret_cast<unsigned int *>(&data_len));
- assert(data_len >= 4);
+
+ if (data_len < 4 || size_t(data_len) > data_size) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
// Move to data addr: 20 = 16 + 4;
data_ptr += 20;
@@ -10467,11 +10529,18 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
#endif
for (int y = 0; y < static_cast<int>(num_blocks); y++) {
size_t y_idx = static_cast<size_t>(y);
- const unsigned char *data_ptr =
- reinterpret_cast<const unsigned char *>(head + offsets[y_idx]);
+
+ 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;
@@ -10479,30 +10548,41 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
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);
-
- // 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];
+ //assert(num_lines > 0);
- if (line_no < 0) {
+ if (num_lines <= 0) {
invalid_data = true;
} else {
- 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);
+
+ // 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;
+ }
+ }
}
} // omp parallel
}
@@ -10537,7 +10617,7 @@ static bool ReconstructLineOffsets(
for (size_t i = 0; i < n; i++) {
size_t offset = static_cast<size_t>(marker - head);
// Offset should not exceed whole EXR file/data size.
- if (offset >= size) {
+ if ((offset + sizeof(tinyexr::tinyexr_uint64)) >= size) {
return false;
}
@@ -10586,8 +10666,15 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
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;
+ if ((data_width < 0) || (data_height < 0)) {
+ if (err) {
+ (*err) = "Invalid data window value.";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
// Read offset tables.
- size_t num_blocks;
+ size_t num_blocks = 0;
if (exr_header->chunk_count > 0) {
// Use `chunkCount` attribute.
@@ -10657,7 +10744,7 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
}
}
- return DecodeChunk(exr_image, exr_header, offsets, head);
+ return DecodeChunk(exr_image, exr_header, offsets, head, size);
}
} // namespace tinyexr
@@ -10842,8 +10929,8 @@ int ParseEXRHeaderFromMemory(EXRHeader *exr_header, const EXRVersion *version,
}
int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
- const unsigned char *memory, size_t size,
- const char **err) {
+ const unsigned char *memory, size_t size,
+ const char **err) {
if (out_rgba == NULL || memory == NULL) {
if (err) {
(*err) = "Invalid argument.\n";
@@ -10866,13 +10953,13 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
if (ret != TINYEXR_SUCCESS) {
return ret;
}
-
+
// Read HALF channel as FLOAT.
for (int i = 0; i < exr_header.num_channels; i++) {
if (exr_header.pixel_types[i] == TINYEXR_PIXELTYPE_HALF) {
exr_header.requested_pixel_types[i] = TINYEXR_PIXELTYPE_FLOAT;
}
- }
+ }
InitEXRImage(&exr_image);
ret = LoadEXRImageFromMemory(&exr_image, &exr_header, memory, size, err);
@@ -10923,23 +11010,22 @@ int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
}
(*out_rgba) = reinterpret_cast<float *>(
- malloc(4 * sizeof(float) * static_cast<size_t>(exr_image.width) *
- static_cast<size_t>(exr_image.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;
- }
+ (*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;
+ }
}
(*width) = exr_image.width;
@@ -11707,7 +11793,12 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
// xSampling: int
// ySampling: int
- tinyexr::ReadChannelInfo(channels, data);
+ if (!tinyexr::ReadChannelInfo(channels, data)) {
+ if (err) {
+ (*err) = "Failed to parse channel info.";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
num_channels = static_cast<int>(channels.size());
@@ -11844,9 +11935,11 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
{
unsigned long dstLen =
static_cast<unsigned long>(pixelOffsetTable.size() * sizeof(int));
- tinyexr::DecompressZip(
+ if (!tinyexr::DecompressZip(
reinterpret_cast<unsigned char *>(&pixelOffsetTable.at(0)), &dstLen,
- data_ptr + 28, static_cast<unsigned long>(packedOffsetTableSize));
+ data_ptr + 28, static_cast<unsigned long>(packedOffsetTableSize))) {
+ return false;
+ }
assert(dstLen == pixelOffsetTable.size() * sizeof(int));
for (size_t i = 0; i < static_cast<size_t>(data_width); i++) {
@@ -11861,10 +11954,12 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
{
unsigned long dstLen = static_cast<unsigned long>(unpackedSampleDataSize);
if (dstLen) {
- tinyexr::DecompressZip(
+ if (!tinyexr::DecompressZip(
reinterpret_cast<unsigned char *>(&sample_data.at(0)), &dstLen,
data_ptr + 28 + packedOffsetTableSize,
- static_cast<unsigned long>(packedSampleDataSize));
+ static_cast<unsigned long>(packedSampleDataSize))) {
+ return false;
+ }
assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
}
}
@@ -12390,7 +12485,7 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
}
int ret = tinyexr::DecodeChunk(&exr_images[i], exr_headers[i], offset_table,
- memory);
+ memory, size);
if (ret != TINYEXR_SUCCESS) {
return ret;
}