forked from syoyo/tinyexr
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstreamreader.hh
More file actions
171 lines (148 loc) · 3.69 KB
/
Copy pathstreamreader.hh
File metadata and controls
171 lines (148 loc) · 3.69 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
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_