Merge pull request #118779 from Chubercik/tinyexr-1.0.13

tinyexr: Update to 1.0.13
This commit is contained in:
Thaddeus Crews
2026-04-20 14:32:03 -05:00
5 changed files with 2386 additions and 47 deletions
+4 -1
View File
@@ -1100,12 +1100,15 @@ Patches:
## tinyexr
- Upstream: https://github.com/syoyo/tinyexr
- Version: 1.0.12 (735ff73ce5959cf005eb99ce517c9bcecab89dfb, 2025)
- Version: 1.0.13 (4946b5d92e13bcc8102ac2c8efd129596a90bf75, 2026)
- License: BSD-3-Clause
Files extracted from upstream source:
- `exr_reader.hh`
- `streamreader.hh`
- `tinyexr.{cc,h}`
- `LICENSE`
Patches:
+29
View File
@@ -0,0 +1,29 @@
BSD 3-Clause License
Copyright (c) 2014 - 2021, Syoyo Fujita and many contributors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the names of its
contributors may be used to endorse or promote products derived from
this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+191
View File
@@ -0,0 +1,191 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2025, Syoyo Fujita and many contributors.
// All rights reserved.
//
// EXR Reader: Reader class with error stack for safe memory reading
#ifndef TINYEXR_EXR_READER_HH_
#define TINYEXR_EXR_READER_HH_
#include <vector>
#include <string>
#include "streamreader.hh"
namespace tinyexr {
// Reader class that wraps StreamReader and accumulates errors
class Reader {
public:
Reader(const uint8_t* data, size_t length, Endian endian = Endian::Little)
: stream_(data, length, endian), has_error_(false) {}
// Check if any errors have occurred
bool has_error() const { return has_error_; }
// Get all accumulated errors
const std::vector<std::string>& errors() const { return errors_; }
// Get the most recent error
std::string last_error() const {
return errors_.empty() ? "" : errors_.back();
}
// Get all errors as a single string
std::string all_errors() const {
std::string result;
for (size_t i = 0; i < errors_.size(); i++) {
if (i > 0) result += "\n";
result += errors_[i];
}
return result;
}
// Clear error stack
void clear_errors() {
errors_.clear();
has_error_ = false;
}
// Read n bytes into destination buffer
bool read(size_t n, uint8_t* dst) {
if (!stream_.read(n, dst)) {
add_error("Failed to read " + std::to_string(n) + " bytes at position " +
std::to_string(stream_.tell()));
return false;
}
return true;
}
// Read 1 byte
bool read1(uint8_t* dst) {
if (!stream_.read1(dst)) {
add_error("Failed to read 1 byte at position " +
std::to_string(stream_.tell()));
return false;
}
return true;
}
// Read 2 bytes with endian swap
bool read2(uint16_t* dst) {
if (!stream_.read2(dst)) {
add_error("Failed to read 2 bytes at position " +
std::to_string(stream_.tell()));
return false;
}
return true;
}
// Read 4 bytes with endian swap
bool read4(uint32_t* dst) {
if (!stream_.read4(dst)) {
add_error("Failed to read 4 bytes at position " +
std::to_string(stream_.tell()));
return false;
}
return true;
}
// Read 8 bytes with endian swap
bool read8(uint64_t* dst) {
if (!stream_.read8(dst)) {
add_error("Failed to read 8 bytes at position " +
std::to_string(stream_.tell()));
return false;
}
return true;
}
// Read a null-terminated string up to max_len bytes
// Returns false if no null terminator found within max_len
bool read_string(std::string* str, size_t max_len = 256) {
if (!str) {
add_error("Null pointer passed to read_string");
return false;
}
str->clear();
size_t start_pos = stream_.tell();
for (size_t i = 0; i < max_len; i++) {
uint8_t c;
if (!stream_.read1(&c)) {
add_error("Failed to read string at position " + std::to_string(start_pos));
return false;
}
if (c == '\0') {
return true;
}
str->push_back(static_cast<char>(c));
}
add_error("String not null-terminated within " + std::to_string(max_len) +
" bytes at position " + std::to_string(start_pos));
return false;
}
// Seek to absolute position
bool seek(size_t pos) {
if (!stream_.seek(pos)) {
add_error("Failed to seek to position " + std::to_string(pos));
return false;
}
return true;
}
// Seek relative to current position
bool seek_relative(int64_t offset) {
size_t current = stream_.tell();
int64_t new_pos = static_cast<int64_t>(current) + offset;
if (new_pos < 0) {
add_error("Seek would move before start of stream");
return false;
}
return seek(static_cast<size_t>(new_pos));
}
// Rewind to beginning
void rewind() {
stream_.rewind();
}
// Get current position
size_t tell() const {
return stream_.tell();
}
// Get remaining bytes
size_t remaining() const {
return stream_.remaining();
}
// Check if at end
bool eof() const {
return stream_.eof();
}
// Get total length
size_t length() const {
return stream_.length();
}
// Add a custom error message
void add_error(const std::string& msg) {
errors_.push_back(msg);
has_error_ = true;
}
// Get direct access to underlying StreamReader (use with caution)
const StreamReader& stream() const { return stream_; }
private:
StreamReader stream_;
std::vector<std::string> errors_;
bool has_error_;
};
} // namespace tinyexr
#endif // TINYEXR_EXR_READER_HH_
+171
View File
@@ -0,0 +1,171 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2025, Syoyo Fujita and many contributors.
// All rights reserved.
//
// StreamReader: Simple header-only stream reader with endian support
//
// Part of TinyEXR V2 API (EXPERIMENTAL)
#ifndef TINYEXR_STREAMREADER_HH_
#define TINYEXR_STREAMREADER_HH_
#include <cstdint>
#include <cstring>
namespace tinyexr {
enum class Endian {
Little,
Big,
Native
};
class StreamReader {
public:
// Constructor: takes memory address, length, and endianness
StreamReader(const uint8_t* data, size_t length, Endian endian = Endian::Little)
: data_(data), length_(length), pos_(0), endian_(endian) {
// Detect native endian
uint16_t test = 0x0001;
native_is_little_ = (*reinterpret_cast<uint8_t*>(&test) == 0x01);
// Determine if we need to swap bytes
if (endian_ == Endian::Native) {
needs_swap_ = false;
} else {
bool data_is_little = (endian_ == Endian::Little);
needs_swap_ = (data_is_little != native_is_little_);
}
}
// Read n bytes into destination buffer
// Returns false on out-of-bounds or error
bool read(size_t n, uint8_t* dst) {
if (!dst || n == 0) {
return false;
}
if (pos_ + n > length_) {
return false; // Out of bounds
}
std::memcpy(dst, data_ + pos_, n);
pos_ += n;
return true;
}
// Read 1 byte (uint8_t)
bool read1(uint8_t* dst) {
return read(1, dst);
}
// Read 2 bytes (uint16_t) with endian swap if needed
bool read2(uint16_t* dst) {
if (!dst) {
return false;
}
uint8_t buf[2];
if (!read(2, buf)) {
return false;
}
if (needs_swap_) {
*dst = static_cast<uint16_t>(buf[1]) << 8 |
static_cast<uint16_t>(buf[0]);
} else {
std::memcpy(dst, buf, 2);
}
return true;
}
// Read 4 bytes (uint32_t) with endian swap if needed
bool read4(uint32_t* dst) {
if (!dst) {
return false;
}
uint8_t buf[4];
if (!read(4, buf)) {
return false;
}
if (needs_swap_) {
*dst = static_cast<uint32_t>(buf[3]) << 24 |
static_cast<uint32_t>(buf[2]) << 16 |
static_cast<uint32_t>(buf[1]) << 8 |
static_cast<uint32_t>(buf[0]);
} else {
std::memcpy(dst, buf, 4);
}
return true;
}
// Read 8 bytes (uint64_t) with endian swap if needed
bool read8(uint64_t* dst) {
if (!dst) {
return false;
}
uint8_t buf[8];
if (!read(8, buf)) {
return false;
}
if (needs_swap_) {
*dst = static_cast<uint64_t>(buf[7]) << 56 |
static_cast<uint64_t>(buf[6]) << 48 |
static_cast<uint64_t>(buf[5]) << 40 |
static_cast<uint64_t>(buf[4]) << 32 |
static_cast<uint64_t>(buf[3]) << 24 |
static_cast<uint64_t>(buf[2]) << 16 |
static_cast<uint64_t>(buf[1]) << 8 |
static_cast<uint64_t>(buf[0]);
} else {
std::memcpy(dst, buf, 8);
}
return true;
}
// Seek to absolute position
// Returns false if position is out of bounds
bool seek(size_t pos) {
if (pos > length_) {
return false;
}
pos_ = pos;
return true;
}
// Rewind to beginning
void rewind() {
pos_ = 0;
}
// Get current position
size_t tell() const {
return pos_;
}
// Get remaining bytes
size_t remaining() const {
return length_ - pos_;
}
// Check if at end
bool eof() const {
return pos_ >= length_;
}
// Get total length
size_t length() const {
return length_;
}
private:
const uint8_t* data_;
size_t length_;
size_t pos_;
Endian endian_;
bool native_is_little_;
bool needs_swap_;
};
} // namespace tinyexr
#endif // TINYEXR_STREAMREADER_HH_
+1991 -46
View File
File diff suppressed because it is too large Load Diff