summaryrefslogtreecommitdiffstats
path: root/thirdparty/tinyexr/tinyexr.h
diff options
context:
space:
mode:
Diffstat (limited to 'thirdparty/tinyexr/tinyexr.h')
-rw-r--r--thirdparty/tinyexr/tinyexr.h406
1 files changed, 297 insertions, 109 deletions
diff --git a/thirdparty/tinyexr/tinyexr.h b/thirdparty/tinyexr/tinyexr.h
index 7482853bcb..3613aaa874 100644
--- a/thirdparty/tinyexr/tinyexr.h
+++ b/thirdparty/tinyexr/tinyexr.h
@@ -619,7 +619,6 @@ extern int LoadEXRFromMemory(float **out_rgba, int *width, int *height,
#endif
#include <algorithm>
-#include <cassert>
#include <cstdio>
#include <cstdlib>
#include <cstring>
@@ -684,6 +683,27 @@ extern "C" unsigned char *stbi_zlib_compress(unsigned char *data, int data_len,
#endif
+// cond: conditional expression
+// msg: std::string
+// err: std::string*
+#define TINYEXR_CHECK_AND_RETURN_MSG(cond, msg, err) do { \
+ if (!(cond)) { \
+ if (!err) { \
+ std::ostringstream ss_e; \
+ ss_e << __func__ << "():" << __LINE__ << msg << "\n"; \
+ (*err) += ss_e.str(); \
+ } \
+ return false;\
+ } \
+ } while(0)
+
+// no error message.
+#define TINYEXR_CHECK_AND_RETURN_C(cond, retcode) do { \
+ if (!(cond)) { \
+ return retcode; \
+ } \
+ } while(0)
+
namespace tinyexr {
#if __cplusplus > 199711L
@@ -1558,7 +1578,7 @@ static int rleUncompress(int inLength, int maxLength, const signed char in[],
// End of RLE code from OpenEXR -----------------------------------
-static void CompressRle(unsigned char *dst,
+static bool CompressRle(unsigned char *dst,
tinyexr::tinyexr_uint64 &compressedSize,
const unsigned char *src, unsigned long src_size) {
std::vector<unsigned char> tmpBuf(src_size);
@@ -1613,7 +1633,7 @@ static void CompressRle(unsigned char *dst,
int outSize = rleCompress(static_cast<int>(src_size),
reinterpret_cast<const char *>(&tmpBuf.at(0)),
reinterpret_cast<signed char *>(dst));
- assert(outSize > 0);
+ TINYEXR_CHECK_AND_RETURN_C(outSize > 0, false);
compressedSize = static_cast<tinyexr::tinyexr_uint64>(outSize);
@@ -1623,6 +1643,8 @@ static void CompressRle(unsigned char *dst,
compressedSize = src_size;
memcpy(dst, src, src_size);
}
+
+ return true;
}
static bool DecompressRle(unsigned char *dst,
@@ -2162,7 +2184,7 @@ struct FHeapCompare {
bool operator()(long long *a, long long *b) { return *a > *b; }
};
-static void hufBuildEncTable(
+static bool hufBuildEncTable(
long long *frq, // io: input frequencies [HUF_ENCSIZE], output table
int *im, // o: min frq index
int *iM) // o: max frq index
@@ -2290,7 +2312,7 @@ static void hufBuildEncTable(
for (int j = m;; j = hlink[j]) {
scode[j]++;
- assert(scode[j] <= 58);
+ TINYEXR_CHECK_AND_RETURN_C(scode[j] <= 58, false);
if (hlink[j] == j) {
//
@@ -2309,7 +2331,7 @@ static void hufBuildEncTable(
for (int j = mm;; j = hlink[j]) {
scode[j]++;
- assert(scode[j] <= 58);
+ TINYEXR_CHECK_AND_RETURN_C(scode[j] <= 58, false);
if (hlink[j] == j) break;
}
@@ -2323,6 +2345,8 @@ static void hufBuildEncTable(
hufCanonicalCodeTable(scode.data());
memcpy(frq, scode.data(), sizeof(long long) * HUF_ENCSIZE);
+
+ return true;
}
//
@@ -3034,7 +3058,6 @@ static bool CompressPiz(unsigned char *outPtr, unsigned int *outSize,
#if !TINYEXR_LITTLE_ENDIAN
// @todo { PIZ compression on BigEndian architecture. }
- assert(0);
return false;
#endif
@@ -3160,7 +3183,6 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
#if !TINYEXR_LITTLE_ENDIAN
// @todo { PIZ compression on BigEndian architecture. }
- assert(0);
return false;
#endif
@@ -3200,7 +3222,13 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
ptr += maxNonZero - minNonZero + 1;
readLen += maxNonZero - minNonZero + 1;
} else {
- return false;
+ // Issue 194
+ if ((minNonZero == (BITMAP_SIZE - 1)) && (maxNonZero == 0)) {
+ // OK. all pixels are zero. And no need to read `bitmap` data.
+ } else {
+ // invalid minNonZero/maxNonZero combination.
+ return false;
+ }
}
std::vector<unsigned short> lut(USHORT_RANGE);
@@ -3211,12 +3239,12 @@ static bool DecompressPiz(unsigned char *outPtr, const unsigned char *inPtr,
// Huffman decoding
//
- int length;
-
if ((readLen + 4) > inLen) {
return false;
}
+ int length=0;
+
// length = *(reinterpret_cast<const int *>(ptr));
tinyexr::cpy4(&length, reinterpret_cast<const int *>(ptr));
ptr += sizeof(int);
@@ -3396,8 +3424,8 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
zfp_stream *zfp = NULL;
zfp_field *field = NULL;
- assert((dst_width % 4) == 0);
- assert((dst_num_lines % 4) == 0);
+ TINYEXR_CHECK_AND_RETURN_C((dst_width % 4) == 0, false);
+ TINYEXR_CHECK_AND_RETURN_C((dst_num_lines % 4) == 0, false);
if ((size_t(dst_width) & 3U) || (size_t(dst_num_lines) & 3U)) {
return false;
@@ -3418,7 +3446,7 @@ static bool DecompressZfp(float *dst, int dst_width, int dst_num_lines,
} else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
zfp_stream_set_accuracy(zfp, param.tolerance);
} else {
- assert(0);
+ return false;
}
size_t buf_size = zfp_stream_maximum_size(zfp, field);
@@ -3462,8 +3490,8 @@ static bool CompressZfp(std::vector<unsigned char> *outBuf,
zfp_stream *zfp = NULL;
zfp_field *field = NULL;
- assert((width % 4) == 0);
- assert((num_lines % 4) == 0);
+ TINYEXR_CHECK_AND_RETURN_C((width % 4) == 0, false);
+ TINYEXR_CHECK_AND_RETURN_C((num_lines % 4) == 0, false);
if ((size_t(width) & 3U) || (size_t(num_lines) & 3U)) {
return false;
@@ -3483,7 +3511,7 @@ static bool CompressZfp(std::vector<unsigned char> *outBuf,
} else if (param.type == TINYEXR_ZFP_COMPRESSIONTYPE_ACCURACY) {
zfp_stream_set_accuracy(zfp, param.tolerance);
} else {
- assert(0);
+ return false;
}
size_t buf_size = zfp_stream_maximum_size(zfp, field);
@@ -3620,7 +3648,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
@@ -3649,7 +3677,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const float *line_ptr = reinterpret_cast<float *>(&outBuf.at(
v * pixel_data_size * static_cast<size_t>(width) +
@@ -3676,11 +3704,10 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else {
- assert(0);
+ return false;
}
}
#else
- assert(0 && "PIZ is disabled in this build");
return false;
#endif
@@ -3692,7 +3719,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
pixel_data_size);
unsigned long dstLen = static_cast<unsigned long>(outBuf.size());
- assert(dstLen > 0);
+ TINYEXR_CHECK_AND_RETURN_C(dstLen > 0, false);
if (!tinyexr::DecompressZip(
reinterpret_cast<unsigned char *>(&outBuf.at(0)), &dstLen, data_ptr,
static_cast<unsigned long>(data_len))) {
@@ -3759,7 +3786,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
@@ -3788,7 +3815,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const float *line_ptr = reinterpret_cast<float *>(
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
@@ -3815,7 +3842,6 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else {
- assert(0);
return false;
}
}
@@ -3893,7 +3919,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_UINT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_UINT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const unsigned int *line_ptr = reinterpret_cast<unsigned int *>(
@@ -3922,7 +3948,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const float *line_ptr = reinterpret_cast<float *>(
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
@@ -3949,7 +3975,6 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else {
- assert(0);
return false;
}
}
@@ -3960,7 +3985,6 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
if (!tinyexr::FindZFPCompressionParam(&zfp_compression_param, attributes,
int(num_attributes), &e)) {
// This code path should not be reachable.
- assert(0);
return false;
}
@@ -3970,7 +3994,7 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
pixel_data_size);
unsigned long dstLen = outBuf.size();
- assert(dstLen > 0);
+ TINYEXR_CHECK_AND_RETURN_C(dstLen > 0, false);
tinyexr::DecompressZfp(reinterpret_cast<float *>(&outBuf.at(0)), width,
num_lines, num_channels, data_ptr,
static_cast<unsigned long>(data_len),
@@ -3987,9 +4011,9 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
// pixel sample data for channel n for scanline 1
// ...
for (size_t c = 0; c < static_cast<size_t>(num_channels); c++) {
- assert(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT);
+ TINYEXR_CHECK_AND_RETURN_C(channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT, false);
if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
- assert(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT);
+ TINYEXR_CHECK_AND_RETURN_C(requested_pixel_types[c] == TINYEXR_PIXELTYPE_FLOAT, false);
for (size_t v = 0; v < static_cast<size_t>(num_lines); v++) {
const float *line_ptr = reinterpret_cast<float *>(
&outBuf.at(v * pixel_data_size * static_cast<size_t>(width) +
@@ -4015,7 +4039,6 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
}
}
} else {
- assert(0);
return false;
}
}
@@ -4023,7 +4046,6 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
(void)attributes;
(void)num_attributes;
(void)num_channels;
- assert(0);
return false;
#endif
} else if (compression_type == TINYEXR_COMPRESSIONTYPE_NONE) {
@@ -4084,7 +4106,6 @@ static bool DecodePixelData(/* out */ unsigned char **out_images,
outLine[u] = f32.f;
}
} else {
- assert(0);
return false;
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
@@ -4245,7 +4266,9 @@ static unsigned char **AllocateImage(int num_channels,
images[c] = reinterpret_cast<unsigned char *>(
static_cast<float *>(malloc(sizeof(float) * data_len)));
} else {
- assert(0);
+ images[c] = NULL; // just in case.
+ valid = false;
+ break;
}
} else if (channels[c].pixel_type == TINYEXR_PIXELTYPE_FLOAT) {
// pixel_data_size += sizeof(float);
@@ -4400,7 +4423,6 @@ static int ParseEXRHeader(HeaderInfo *info, bool *empty_header,
return TINYEXR_ERROR_INVALID_DATA;
}
- assert(data.size() == 9);
memcpy(&x_size, &data.at(0), sizeof(int));
memcpy(&y_size, &data.at(4), sizeof(int));
tile_mode = data[8];
@@ -4787,6 +4809,7 @@ struct OffsetData {
int num_y_levels;
};
+// -1 = error
static int LevelIndex(int lx, int ly, int tile_level_mode, int num_x_levels) {
switch (tile_level_mode) {
case TINYEXR_TILE_ONE_LEVEL:
@@ -4799,13 +4822,15 @@ static int LevelIndex(int lx, int ly, int tile_level_mode, int num_x_levels) {
return lx + ly * num_x_levels;
default:
- assert(false);
+ return -1;
}
return 0;
}
static int LevelSize(int toplevel_size, int level, int tile_rounding_mode) {
- assert(level >= 0);
+ if (level < 0) {
+ return -1;
+ }
int b = static_cast<int>(1u << static_cast<unsigned int>(level));
int level_size = toplevel_size / b;
@@ -4826,9 +4851,13 @@ static int DecodeTiledLevel(EXRImage* exr_image, const EXRHeader* exr_header,
int level_index = LevelIndex(exr_image->level_x, exr_image->level_y, exr_header->tile_level_mode, offset_data.num_x_levels);
int num_y_tiles = int(offset_data.offsets[size_t(level_index)].size());
- assert(num_y_tiles);
+ if (num_y_tiles < 1) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
int num_x_tiles = int(offset_data.offsets[size_t(level_index)][0].size());
- assert(num_x_tiles);
+ if (num_x_tiles < 1) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
int num_tiles = num_x_tiles * num_y_tiles;
int err_code = TINYEXR_SUCCESS;
@@ -5026,10 +5055,24 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
return TINYEXR_ERROR_INVALID_DATA;
}
- int data_width =
- exr_header->data_window.max_x - exr_header->data_window.min_x + 1;
- int data_height =
- exr_header->data_window.max_y - exr_header->data_window.min_y + 1;
+ tinyexr_int64 data_width =
+ static_cast<tinyexr_int64>(exr_header->data_window.max_x) - static_cast<tinyexr_int64>(exr_header->data_window.min_x) + static_cast<tinyexr_int64>(1);
+ tinyexr_int64 data_height =
+ static_cast<tinyexr_int64>(exr_header->data_window.max_y) - static_cast<tinyexr_int64>(exr_header->data_window.min_y) + static_cast<tinyexr_int64>(1);
+
+ if (data_width <= 0) {
+ if (err) {
+ (*err) += "Invalid data window width.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
+ if (data_height <= 0) {
+ if (err) {
+ (*err) += "Invalid data window height.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
// Do not allow too large data_width and data_height. header invalid?
{
@@ -5109,8 +5152,17 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
}
level_image->width =
LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level, exr_header->tile_rounding_mode);
+ if (level_image->width < 1) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
level_image->height =
LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level, exr_header->tile_rounding_mode);
+
+ if (level_image->height < 1) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
level_image->level_x = level;
level_image->level_y = level;
@@ -5136,8 +5188,16 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
level_image->width =
LevelSize(exr_header->data_window.max_x - exr_header->data_window.min_x + 1, level_x, exr_header->tile_rounding_mode);
+ if (level_image->width < 1) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
level_image->height =
LevelSize(exr_header->data_window.max_y - exr_header->data_window.min_y + 1, level_y, exr_header->tile_rounding_mode);
+ if (level_image->height < 1) {
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
level_image->level_x = level_x;
level_image->level_y = level_y;
@@ -5171,7 +5231,7 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
bool alloc_success = false;
exr_image->images = tinyexr::AllocateImage(
num_channels, exr_header->channels, exr_header->requested_pixel_types,
- data_width, data_height, &alloc_success);
+ int(data_width), int(data_height), &alloc_success);
if (!alloc_success) {
if (err) {
@@ -5271,7 +5331,7 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
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,
+ int(data_width), int(data_height), int(data_width), y, line_no,
num_lines, static_cast<size_t>(pixel_data_size),
static_cast<size_t>(
exr_header->num_custom_attributes),
@@ -5323,8 +5383,8 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
{
exr_image->num_channels = num_channels;
- exr_image->width = data_width;
- exr_image->height = data_height;
+ exr_image->width = int(data_width);
+ exr_image->height = int(data_height);
}
return TINYEXR_SUCCESS;
@@ -5333,8 +5393,12 @@ static int DecodeChunk(EXRImage *exr_image, const EXRHeader *exr_header,
static bool ReconstructLineOffsets(
std::vector<tinyexr::tinyexr_uint64> *offsets, size_t n,
const unsigned char *head, const unsigned char *marker, const size_t size) {
- assert(head < marker);
- assert(offsets->size() == n);
+ if (head >= marker) {
+ return false;
+ }
+ if (offsets->size() != n) {
+ return false;
+ }
for (size_t i = 0; i < n; i++) {
size_t offset = static_cast<size_t>(marker - head);
@@ -5430,7 +5494,7 @@ static int CalculateNumXLevels(const EXRHeader* exr_header) {
default:
- assert(false);
+ return -1;
}
return num;
@@ -5468,25 +5532,29 @@ static int CalculateNumYLevels(const EXRHeader* exr_header) {
default:
- assert(false);
+ return -1;
}
return num;
}
-static void CalculateNumTiles(std::vector<int>& numTiles,
+static bool CalculateNumTiles(std::vector<int>& numTiles,
int toplevel_size,
int size,
int tile_rounding_mode) {
for (unsigned i = 0; i < numTiles.size(); i++) {
int l = LevelSize(toplevel_size, int(i), tile_rounding_mode);
- assert(l <= std::numeric_limits<int>::max() - size + 1);
+ if (l < 0) {
+ return false;
+ }
+ TINYEXR_CHECK_AND_RETURN_C(l <= std::numeric_limits<int>::max() - size + 1, false);
numTiles[i] = (l + size - 1) / size;
}
+ return true;
}
-static void PrecalculateTileInfo(std::vector<int>& num_x_tiles,
+static bool PrecalculateTileInfo(std::vector<int>& num_x_tiles,
std::vector<int>& num_y_tiles,
const EXRHeader* exr_header) {
int min_x = exr_header->data_window.min_x;
@@ -5495,20 +5563,35 @@ static void PrecalculateTileInfo(std::vector<int>& num_x_tiles,
int max_y = exr_header->data_window.max_y;
int num_x_levels = CalculateNumXLevels(exr_header);
+
+ if (num_x_levels < 0) {
+ return false;
+ }
+
int num_y_levels = CalculateNumYLevels(exr_header);
+ if (num_y_levels < 0) {
+ return false;
+ }
+
num_x_tiles.resize(size_t(num_x_levels));
num_y_tiles.resize(size_t(num_y_levels));
- CalculateNumTiles(num_x_tiles,
+ if (!CalculateNumTiles(num_x_tiles,
max_x - min_x + 1,
exr_header->tile_size_x,
- exr_header->tile_rounding_mode);
+ exr_header->tile_rounding_mode)) {
+ return false;
+ }
- CalculateNumTiles(num_y_tiles,
+ if (!CalculateNumTiles(num_y_tiles,
max_y - min_y + 1,
exr_header->tile_size_y,
- exr_header->tile_rounding_mode);
+ exr_header->tile_rounding_mode)) {
+ return false;
+ }
+
+ return true;
}
static void InitSingleResolutionOffsets(OffsetData& offset_data, size_t num_blocks) {
@@ -5520,6 +5603,7 @@ static void InitSingleResolutionOffsets(OffsetData& offset_data, size_t num_bloc
}
// Return sum of tile blocks.
+// 0 = error
static int InitTileOffsets(OffsetData& offset_data,
const EXRHeader* exr_header,
const std::vector<int>& num_x_tiles,
@@ -5530,7 +5614,7 @@ static int InitTileOffsets(OffsetData& offset_data,
switch (exr_header->tile_level_mode) {
case TINYEXR_TILE_ONE_LEVEL:
case TINYEXR_TILE_MIPMAP_LEVELS:
- assert(offset_data.num_x_levels == offset_data.num_y_levels);
+ TINYEXR_CHECK_AND_RETURN_C(offset_data.num_x_levels == offset_data.num_y_levels, 0);
offset_data.offsets.resize(size_t(offset_data.num_x_levels));
for (unsigned int l = 0; l < offset_data.offsets.size(); ++l) {
@@ -5561,7 +5645,7 @@ static int InitTileOffsets(OffsetData& offset_data,
break;
default:
- assert(false);
+ return 0;
}
return num_tile_blocks;
}
@@ -5629,7 +5713,7 @@ static bool isValidTile(const EXRHeader* exr_header,
return false;
}
-static void ReconstructTileOffsets(OffsetData& offset_data,
+static bool ReconstructTileOffsets(OffsetData& offset_data,
const EXRHeader* exr_header,
const unsigned char* head, const unsigned char* marker, const size_t /*size*/,
bool isMultiPartFile,
@@ -5689,14 +5773,19 @@ static void ReconstructTileOffsets(OffsetData& offset_data,
}
if (!isValidTile(exr_header, offset_data,
- tileX, tileY, levelX, levelY))
- return;
+ tileX, tileY, levelX, levelY)) {
+ return false;
+ }
int level_idx = LevelIndex(levelX, levelY, exr_header->tile_level_mode, numXLevels);
+ if (level_idx < 0) {
+ return false;
+ }
offset_data.offsets[size_t(level_idx)][size_t(tileY)][size_t(tileX)] = tileOffset;
}
}
}
+ return true;
}
// marker output is also
@@ -5754,8 +5843,12 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
tinyexr::SetErrorMessage("Invalid data width value", err);
return TINYEXR_ERROR_INVALID_DATA;
}
- int data_width =
- exr_header->data_window.max_x - exr_header->data_window.min_x + 1;
+ tinyexr_int64 data_width =
+ static_cast<tinyexr_int64>(exr_header->data_window.max_x) - static_cast<tinyexr_int64>(exr_header->data_window.min_x) + static_cast<tinyexr_int64>(1);
+ if (data_width <= 0) {
+ tinyexr::SetErrorMessage("Invalid data window width value", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
if (exr_header->data_window.max_y < exr_header->data_window.min_y ||
exr_header->data_window.max_y - exr_header->data_window.min_y ==
@@ -5763,8 +5856,13 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
tinyexr::SetErrorMessage("Invalid data height value", err);
return TINYEXR_ERROR_INVALID_DATA;
}
- int data_height =
- exr_header->data_window.max_y - exr_header->data_window.min_y + 1;
+ tinyexr_int64 data_height =
+ static_cast<tinyexr_int64>(exr_header->data_window.max_y) - static_cast<tinyexr_int64>(exr_header->data_window.min_y) + static_cast<tinyexr_int64>(1);
+
+ if (data_height <= 0) {
+ tinyexr::SetErrorMessage("Invalid data window height value", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
// Do not allow too large data_width and data_height. header invalid?
{
@@ -5797,7 +5895,10 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
if (exr_header->tiled) {
{
std::vector<int> num_x_tiles, num_y_tiles;
- PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_header);
+ if (!PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_header)) {
+ tinyexr::SetErrorMessage("Failed to precalculate tile info.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
num_blocks = size_t(InitTileOffsets(offset_data, exr_header, num_x_tiles, num_y_tiles));
if (exr_header->chunk_count > 0) {
if (exr_header->chunk_count != static_cast<int>(num_blocks)) {
@@ -5810,9 +5911,13 @@ static int DecodeEXRImage(EXRImage *exr_image, const EXRHeader *exr_header,
int ret = ReadOffsets(offset_data, head, marker, size, err);
if (ret != TINYEXR_SUCCESS) return ret;
if (IsAnyOffsetsAreInvalid(offset_data)) {
- ReconstructTileOffsets(offset_data, exr_header,
+ if (!ReconstructTileOffsets(offset_data, exr_header,
head, marker, size,
- exr_header->multipart, exr_header->non_image);
+ exr_header->multipart, exr_header->non_image)) {
+
+ tinyexr::SetErrorMessage("Invalid Tile Offsets data.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
}
} else if (exr_header->chunk_count > 0) {
// Use `chunkCount` attribute.
@@ -6638,6 +6743,7 @@ struct MemoryMappedFile {
data = reinterpret_cast<unsigned char *>(
mmap(0, size, PROT_READ, MAP_SHARED, posix_descriptor, 0));
if (data == MAP_FAILED) {
+ data = nullptr;
return;
}
#else
@@ -6662,20 +6768,26 @@ struct MemoryMappedFile {
size = static_cast<size_t>(ftell_result);
if (fseek(fp, 0, SEEK_SET) != 0) {
fclose(fp);
+ size = 0;
return;
}
data = reinterpret_cast<unsigned char *>(malloc(size));
if (!data) {
+ size = 0;
fclose(fp);
return;
}
size_t read_bytes = fread(data, 1, size, fp);
- assert(read_bytes == size);
+ if (read_bytes != size) {
+ // TODO: Try to read data until reading `size` bytes.
+ fclose(fp);
+ size = 0;
+ data = nullptr;
+ return;
+ }
fclose(fp);
- (void)read_bytes;
#endif
- assert(valid());
}
// MemoryMappedFile's destructor closes all its handles.
@@ -6966,9 +7078,14 @@ static bool EncodePixelData(/* out */ std::vector<unsigned char>& out_data,
tinyexr::tinyexr_uint64 outSize = block.size();
- tinyexr::CompressRle(&block.at(0), outSize,
+ if (!tinyexr::CompressRle(&block.at(0), outSize,
reinterpret_cast<const unsigned char *>(&buf.at(0)),
- static_cast<unsigned long>(buf.size()));
+ static_cast<unsigned long>(buf.size()))) {
+ if (err) {
+ (*err) += "RLE compresssion failed.\n";
+ }
+ return false;
+ }
// 4 byte: scan line
// 4 byte: data size
@@ -6985,9 +7102,14 @@ static bool EncodePixelData(/* out */ std::vector<unsigned char>& out_data,
std::vector<unsigned char> block(bufLen);
unsigned int outSize = static_cast<unsigned int>(block.size());
- CompressPiz(&block.at(0), &outSize,
+ if (!CompressPiz(&block.at(0), &outSize,
reinterpret_cast<const unsigned char *>(&buf.at(0)),
- buf.size(), channels, width, num_lines);
+ buf.size(), channels, width, num_lines)) {
+ if (err) {
+ (*err) += "PIZ compresssion failed.\n";
+ }
+ return false;
+ }
// 4 byte: scan line
// 4 byte: data size
@@ -7041,14 +7163,19 @@ static int EncodeTiledLevel(const EXRImage* level_image, const EXRHeader* exr_he
const void* compression_param, // must be set if zfp compression is enabled
std::string* err) {
int num_tiles = num_x_tiles * num_y_tiles;
- assert(num_tiles == level_image->num_tiles);
+ if (num_tiles != level_image->num_tiles) {
+ if (err) {
+ (*err) += "Invalid number of tiles in argument.\n";
+ }
+ return TINYEXR_ERROR_INVALID_ARGUMENT;
+ }
if ((exr_header->tile_size_x > level_image->width || exr_header->tile_size_y > level_image->height) &&
level_image->level_x == 0 && level_image->level_y == 0) {
if (err) {
(*err) += "Failed to encode tile data.\n";
- }
- return TINYEXR_ERROR_INVALID_DATA;
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
}
@@ -7111,7 +7238,11 @@ static int EncodeTiledLevel(const EXRImage* level_image, const EXRHeader* exr_he
invalid_data = true;
continue;
}
- assert(data_list[data_idx].size() > data_header_size);
+ if (data_list[data_idx].size() <= data_header_size) {
+ invalid_data = true;
+ continue;
+ }
+
int data_len = static_cast<int>(data_list[data_idx].size() - data_header_size);
//tileX, tileY, levelX, levelY // pixel_data_size(int)
memcpy(&data_list[data_idx][0], &x_tile, sizeof(int));
@@ -7191,7 +7322,10 @@ static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header,
pixel_data_size += sizeof(unsigned int);
channel_offset += sizeof(unsigned int);
} else {
- assert(0);
+ if (err) {
+ (*err) += "Invalid requested_pixel_type.\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
}
}
}
@@ -7236,6 +7370,13 @@ static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header,
int level_index_from_image = LevelIndex(level_image->level_x, level_image->level_y,
exr_header->tile_level_mode, offset_data.num_x_levels);
+ if (level_index_from_image < 0) {
+ if (err) {
+ (*err) += "Invalid tile level mode\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
if (level_index_from_image != level_index) {
if (err) {
(*err) += "Incorrect level ordering in tiled image\n";
@@ -7243,9 +7384,20 @@ static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header,
return TINYEXR_ERROR_INVALID_DATA;
}
int num_y_tiles = int(offset_data.offsets[level_index].size());
- assert(num_y_tiles);
+ if (num_y_tiles <= 0) {
+ if (err) {
+ (*err) += "Invalid Y tile size\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
int num_x_tiles = int(offset_data.offsets[level_index][0].size());
- assert(num_x_tiles);
+ if (num_x_tiles <= 0) {
+ if (err) {
+ (*err) += "Invalid X tile size\n";
+ }
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
std::string e;
int ret = EncodeTiledLevel(level_image,
@@ -7276,7 +7428,7 @@ static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header,
}
level_image = level_image->next_level;
}
- assert(static_cast<int>(block_idx) == num_blocks);
+ TINYEXR_CHECK_AND_RETURN_C(static_cast<int>(block_idx) == num_blocks, TINYEXR_ERROR_INVALID_DATA);
total_size = offset;
} else { // scanlines
std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data.offsets[0][0];
@@ -7329,7 +7481,10 @@ static int EncodeChunk(const EXRImage* exr_image, const EXRHeader* exr_header,
invalid_data = true;
continue; // "break" cannot be used with OpenMP
}
- assert(data_list[i].size() > data_header_size);
+ if (data_list[i].size() <= data_header_size) {
+ invalid_data = true;
+ continue; // "break" cannot be used with OpenMP
+ }
int data_len = static_cast<int>(data_list[i].size() - data_header_size);
memcpy(&data_list[i][0], &start_y, sizeof(int));
memcpy(&data_list[i][4], &data_len, sizeof(int));
@@ -7455,9 +7610,20 @@ static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images,
} else {
{
std::vector<int> num_x_tiles, num_y_tiles;
- PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]);
- chunk_count[i] =
- InitTileOffsets(offset_data[i], exr_headers[i], num_x_tiles, num_y_tiles);
+ if (!PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i])) {
+ SetErrorMessage("Failed to precalculate Tile info",
+ err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+ int ntiles = InitTileOffsets(offset_data[i], exr_headers[i], num_x_tiles, num_y_tiles);
+ if (ntiles > 0) {
+ chunk_count[i] = ntiles;
+ } else {
+ SetErrorMessage("Failed to compute Tile offsets",
+ err);
+ return TINYEXR_ERROR_INVALID_DATA;
+
+ }
total_chunk_count += chunk_count[i];
}
}
@@ -7657,7 +7823,7 @@ static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images,
// Allocating required memory
if (total_size == 0) { // something went wrong
tinyexr::SetErrorMessage("Output memory size is zero", err);
- return 0;
+ return TINYEXR_ERROR_INVALID_DATA;
}
(*memory_out) = static_cast<unsigned char*>(malloc(size_t(total_size)));
@@ -7676,7 +7842,11 @@ static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images,
for (size_t j = 0; j < offset_data[i].offsets[level_index].size(); ++j) {
size_t num_bytes = sizeof(tinyexr_uint64) * offset_data[i].offsets[level_index][j].size();
sum += num_bytes;
- assert(sum <= total_size);
+ if (sum > total_size) {
+ tinyexr::SetErrorMessage("Invalid offset bytes in Tiled Part image.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
memcpy(memory_ptr,
reinterpret_cast<unsigned char*>(&offset_data[i].offsets[level_index][j][0]),
num_bytes);
@@ -7687,7 +7857,10 @@ static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images,
} else {
size_t num_bytes = sizeof(tinyexr::tinyexr_uint64) * static_cast<size_t>(chunk_count[i]);
sum += num_bytes;
- assert(sum <= total_size);
+ if (sum > total_size) {
+ tinyexr::SetErrorMessage("Invalid offset bytes in Part image.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
std::vector<tinyexr::tinyexr_uint64>& offsets = offset_data[i].offsets[0][0];
memcpy(memory_ptr, reinterpret_cast<unsigned char*>(&offsets[0]), num_bytes);
memory_ptr += num_bytes;
@@ -7699,19 +7872,30 @@ static size_t SaveEXRNPartImageToMemory(const EXRImage* exr_images,
for (size_t j = 0; j < static_cast<size_t>(chunk_count[i]); ++j) {
if (num_parts > 1) {
sum += 4;
- assert(sum <= total_size);
+ if (sum > total_size) {
+ tinyexr::SetErrorMessage("Buffer overrun in reading Part image chunk data.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
unsigned int part_number = i;
swap4(&part_number);
memcpy(memory_ptr, &part_number, 4);
memory_ptr += 4;
}
sum += data_lists[i][j].size();
- assert(sum <= total_size);
+ if (sum > total_size) {
+ tinyexr::SetErrorMessage("Buffer overrun in reading Part image chunk data.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
memcpy(memory_ptr, &data_lists[i][j][0], data_lists[i][j].size());
memory_ptr += data_lists[i][j].size();
}
}
- assert(sum == total_size);
+
+ if (sum != total_size) {
+ tinyexr::SetErrorMessage("Corrupted Part image chunk data.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
+
return size_t(total_size); // OK
}
@@ -8004,11 +8188,11 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
}
}
- assert(dx >= 0);
- assert(dy >= 0);
- assert(dw >= 0);
- assert(dh >= 0);
- assert(num_channels >= 1);
+ TINYEXR_CHECK_AND_RETURN_C(dx >= 0, TINYEXR_ERROR_INVALID_DATA);
+ TINYEXR_CHECK_AND_RETURN_C(dy >= 0, TINYEXR_ERROR_INVALID_DATA);
+ TINYEXR_CHECK_AND_RETURN_C(dw >= 0, TINYEXR_ERROR_INVALID_DATA);
+ TINYEXR_CHECK_AND_RETURN_C(dh >= 0, TINYEXR_ERROR_INVALID_DATA);
+ TINYEXR_CHECK_AND_RETURN_C(num_channels >= 1, TINYEXR_ERROR_INVALID_DATA);
int data_width = dw - dx + 1;
int data_height = dh - dy + 1;
@@ -8106,7 +8290,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
return false;
}
- assert(dstLen == pixelOffsetTable.size() * sizeof(int));
+ TINYEXR_CHECK_AND_RETURN_C(dstLen == pixelOffsetTable.size() * sizeof(int), TINYEXR_ERROR_INVALID_DATA);
for (size_t i = 0; i < static_cast<size_t>(data_width); i++) {
deep_image->offset_table[y][i] = pixelOffsetTable[i];
}
@@ -8125,7 +8309,7 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
static_cast<unsigned long>(packedSampleDataSize))) {
return false;
}
- assert(dstLen == static_cast<unsigned long>(unpackedSampleDataSize));
+ TINYEXR_CHECK_AND_RETURN_C(dstLen == static_cast<unsigned long>(unpackedSampleDataSize), TINYEXR_ERROR_INVALID_DATA);
}
}
@@ -8144,16 +8328,17 @@ int LoadDeepEXR(DeepImage *deep_image, const char *filename, const char **err) {
TINYEXR_PIXELTYPE_FLOAT) { // float
channel_offset += 4;
} else {
- assert(0);
+ tinyexr::SetErrorMessage("Invalid pixel_type in chnnels.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
}
}
sampleSize = channel_offset;
}
- assert(sampleSize >= 2);
+ TINYEXR_CHECK_AND_RETURN_C(sampleSize >= 2, TINYEXR_ERROR_INVALID_DATA);
- assert(static_cast<size_t>(
+ TINYEXR_CHECK_AND_RETURN_C(static_cast<size_t>(
pixelOffsetTable[static_cast<size_t>(data_width - 1)] *
- sampleSize) == sample_data.size());
+ sampleSize) == sample_data.size(), TINYEXR_ERROR_INVALID_DATA);
int samples_per_line = static_cast<int>(sample_data.size()) / sampleSize;
//
@@ -8656,7 +8841,10 @@ int LoadEXRMultipartImageFromMemory(EXRImage *exr_images,
} else {
{
std::vector<int> num_x_tiles, num_y_tiles;
- tinyexr::PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i]);
+ if (!tinyexr::PrecalculateTileInfo(num_x_tiles, num_y_tiles, exr_headers[i])) {
+ tinyexr::SetErrorMessage("Invalid tile info.", err);
+ return TINYEXR_ERROR_INVALID_DATA;
+ }
int num_blocks = InitTileOffsets(offset_data, exr_headers[i], num_x_tiles, num_y_tiles);
if (num_blocks != exr_headers[i]->chunk_count) {
tinyexr::SetErrorMessage("Invalid offset table size.", err);