/src/gdal/third_party/libertiff/libertiff.hpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: MIT |
2 | | // Copyright 2024, Even Rouault <even.rouault at spatialys.com> |
3 | | |
4 | | // Canonical URL: https://github.com/libertiff/libertiff/blob/master/libertiff.hpp |
5 | | |
6 | | #ifndef LIBERTIFF_HPP_INCLUDED |
7 | | #define LIBERTIFF_HPP_INCLUDED |
8 | | |
9 | | ////////////////////////////////////////////////////////////// |
10 | | // libertiff = libre TIFF or LIB E(ven) R(ouault) TIFF... ? // |
11 | | ////////////////////////////////////////////////////////////// |
12 | | |
13 | | #if __cplusplus >= 202002L |
14 | | #include <bit> // std::endian |
15 | | #endif |
16 | | |
17 | | #include <algorithm> |
18 | | #include <array> |
19 | | #include <cassert> |
20 | | #include <cstring> |
21 | | #include <limits> |
22 | | #include <memory> |
23 | | #include <set> |
24 | | #include <string> |
25 | | #include <type_traits> |
26 | | #include <vector> |
27 | | |
28 | | #ifndef LIBERTIFF_NS |
29 | | #define LIBERTIFF_NS libertiff |
30 | | #endif |
31 | | |
32 | | /** Libertiff is a C++11 simple, header-only, TIFF reader. It is MIT licensed. |
33 | | * |
34 | | * Handles both ClassicTIFF and BigTIFF, little-endian or big-endian ordered. |
35 | | * |
36 | | * The library does not (yet?) offer codec facilities. It is mostly aimed at |
37 | | * browsing through the linked chain of Image File Directory (IFD) and their tags. |
38 | | * |
39 | | * "Offline" tag values are not loaded at IFD opening time, but only upon |
40 | | * request, which helps handling files with tags with an arbitrarily large |
41 | | * number of values. |
42 | | * |
43 | | * The library is thread-safe (that is the instances that it returns can |
44 | | * be used from multiple threads), if passed FileReader instances are themselves |
45 | | * thread-safe. |
46 | | * |
47 | | * The library does not throw exceptions (but underlying std library might |
48 | | * throw exceptions in case of out-of-memory situations) |
49 | | * |
50 | | * Optional features: |
51 | | * - define LIBERTIFF_C_FILE_READER before including libertiff.hpp, so that |
52 | | * the libertiff::CFileReader class is available |
53 | | */ |
54 | | namespace LIBERTIFF_NS |
55 | | { |
56 | | |
57 | | #if __cplusplus >= 201703L |
58 | 7.26M | #define LIBERTIFF_STATIC_ASSERT(x) static_assert(x) |
59 | | #define LIBERTIFF_CONSTEXPR constexpr |
60 | | #else |
61 | | #define LIBERTIFF_STATIC_ASSERT(x) static_assert((x), #x) |
62 | | #define LIBERTIFF_CONSTEXPR |
63 | | #endif |
64 | | |
65 | | template <typename T, typename... Args> |
66 | | std::unique_ptr<T> make_unique(Args &&...args) |
67 | 29.8k | { |
68 | 29.8k | return std::unique_ptr<T>(new T(std::forward<Args>(args)...)); |
69 | 29.8k | } |
70 | | |
71 | | /** Returns whether the host is little-endian ordered */ |
72 | | inline bool isHostLittleEndian() |
73 | 20.6k | { |
74 | | #if __cplusplus >= 202002L |
75 | | return std::endian::native == std::endian::little; |
76 | | #elif (defined(__BYTE_ORDER__) && defined(__ORDER_LITTLE_ENDIAN__) && \ |
77 | | (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__)) || \ |
78 | | defined(_MSC_VER) |
79 | | return true; |
80 | | #elif defined(__BYTE_ORDER__) && defined(__ORDER_BIG_ENDIAN__) && \ |
81 | | (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__) |
82 | | return false; |
83 | | #else |
84 | | uint32_t one = 1; |
85 | | char one_as_char_array[sizeof(uint32_t)]; |
86 | | std::memcpy(one_as_char_array, &one, sizeof(uint32_t)); |
87 | | return one_as_char_array[0] == 1; |
88 | | #endif |
89 | 20.6k | } |
90 | | |
91 | | /** Byte-swap */ |
92 | | template <class T> inline T byteSwap(T v); |
93 | | |
94 | | /** Byte-swap a uint8_t */ |
95 | | template <> inline uint8_t byteSwap(uint8_t v) |
96 | 0 | { |
97 | 0 | return v; |
98 | 0 | } |
99 | | |
100 | | /** Byte-swap a int8_t */ |
101 | | template <> inline int8_t byteSwap(int8_t v) |
102 | 0 | { |
103 | 0 | return v; |
104 | 0 | } |
105 | | |
106 | | /** Byte-swap a uint16_t */ |
107 | | template <> inline uint16_t byteSwap(uint16_t v) |
108 | 1.44M | { |
109 | 1.44M | return uint16_t((v >> 8) | ((v & 0xff) << 8)); |
110 | 1.44M | } |
111 | | |
112 | | /** Byte-swap a int16_t */ |
113 | | template <> inline int16_t byteSwap(int16_t v) |
114 | 0 | { |
115 | 0 | uint16_t u; |
116 | 0 | LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); |
117 | 0 | std::memcpy(&u, &v, sizeof(u)); |
118 | 0 | u = byteSwap(u); |
119 | 0 | std::memcpy(&v, &u, sizeof(u)); |
120 | 0 | return v; |
121 | 0 | } |
122 | | |
123 | | /** Byte-swap a uint32_t */ |
124 | | template <> inline uint32_t byteSwap(uint32_t v) |
125 | 827k | { |
126 | 827k | return (v >> 24) | (((v >> 16) & 0xff) << 8) | (((v >> 8) & 0xff) << 16) | |
127 | 827k | ((v & 0xff) << 24); |
128 | 827k | } |
129 | | |
130 | | /** Byte-swap a int32_t */ |
131 | | template <> inline int32_t byteSwap(int32_t v) |
132 | 443 | { |
133 | 443 | uint32_t u; |
134 | 443 | LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); |
135 | 443 | std::memcpy(&u, &v, sizeof(u)); |
136 | 443 | u = byteSwap(u); |
137 | 443 | std::memcpy(&v, &u, sizeof(u)); |
138 | 443 | return v; |
139 | 443 | } |
140 | | |
141 | | /** Byte-swap a uint64_t */ |
142 | | template <> inline uint64_t byteSwap(uint64_t v) |
143 | 79.7k | { |
144 | 79.7k | return (uint64_t(byteSwap(uint32_t(v & ~(0U)))) << 32) | |
145 | 79.7k | byteSwap(uint32_t(v >> 32)); |
146 | 79.7k | } |
147 | | |
148 | | /** Byte-swap a int64_t */ |
149 | | template <> inline int64_t byteSwap(int64_t v) |
150 | 0 | { |
151 | 0 | uint64_t u; |
152 | 0 | std::memcpy(&u, &v, sizeof(u)); |
153 | 0 | u = byteSwap(u); |
154 | 0 | std::memcpy(&v, &u, sizeof(u)); |
155 | 0 | return v; |
156 | 0 | } |
157 | | |
158 | | /** Byte-swap a float */ |
159 | | template <> inline float byteSwap(float v) |
160 | 0 | { |
161 | 0 | uint32_t u; |
162 | 0 | LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); |
163 | 0 | std::memcpy(&u, &v, sizeof(u)); |
164 | 0 | u = byteSwap(u); |
165 | 0 | std::memcpy(&v, &u, sizeof(u)); |
166 | 0 | return v; |
167 | 0 | } |
168 | | |
169 | | /** Byte-swap a double */ |
170 | | template <> inline double byteSwap(double v) |
171 | 0 | { |
172 | 0 | uint64_t u; |
173 | 0 | LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u)); |
174 | 0 | std::memcpy(&u, &v, sizeof(u)); |
175 | 0 | u = byteSwap(u); |
176 | 0 | std::memcpy(&v, &u, sizeof(u)); |
177 | 0 | return v; |
178 | 0 | } |
179 | | } // namespace LIBERTIFF_NS |
180 | | |
181 | | namespace LIBERTIFF_NS |
182 | | { |
183 | | #if defined(__clang__) |
184 | | #pragma clang diagnostic push |
185 | | #pragma clang diagnostic ignored "-Wweak-vtables" |
186 | | #endif |
187 | | |
188 | | /** Interface to read from a file. */ |
189 | | class FileReader |
190 | | { |
191 | | public: |
192 | 20.6k | virtual ~FileReader() = default; |
193 | | |
194 | | /** Return file size in bytes */ |
195 | | virtual uint64_t size() const = 0; |
196 | | |
197 | | /** Read 'count' bytes from offset 'offset' into 'buffer' and |
198 | | * return the number of bytes actually read. |
199 | | */ |
200 | | virtual size_t read(uint64_t offset, size_t count, void *buffer) const = 0; |
201 | | }; |
202 | | |
203 | | #if defined(__clang__) |
204 | | #pragma clang diagnostic pop |
205 | | #endif |
206 | | } // namespace LIBERTIFF_NS |
207 | | |
208 | | namespace LIBERTIFF_NS |
209 | | { |
210 | | /** Read context: associates a file, and the byte ordering of the TIFF file */ |
211 | | class ReadContext |
212 | | { |
213 | | public: |
214 | | /** Constructor */ |
215 | | ReadContext(const std::shared_ptr<const FileReader> &file, |
216 | | bool mustByteSwap) |
217 | 20.6k | : m_file(file), m_mustByteSwap(mustByteSwap) |
218 | 20.6k | { |
219 | 20.6k | } |
220 | | |
221 | | /** Return if values of more than 1-byte must be byte swapped. |
222 | | * To be only taken into account when reading pixels. Tag values are |
223 | | * automatically byte-swapped */ |
224 | | inline bool mustByteSwap() const |
225 | 16.3k | { |
226 | 16.3k | return m_mustByteSwap; |
227 | 16.3k | } |
228 | | |
229 | | /** Return file size */ |
230 | | inline uint64_t size() const |
231 | 160k | { |
232 | 160k | return m_file->size(); |
233 | 160k | } |
234 | | |
235 | | /** Read count raw bytes at offset into buffer */ |
236 | | void read(uint64_t offset, size_t count, void *buffer, bool &ok) const |
237 | 100k | { |
238 | 100k | if (m_file->read(offset, count, buffer) != count) |
239 | 3.21k | ok = false; |
240 | 100k | } |
241 | | |
242 | | /** Read single value at offset */ |
243 | | template <class T> T read(uint64_t offset, bool &ok) const |
244 | 25.7M | { |
245 | 25.7M | #if __cplusplus >= 201703L |
246 | 25.7M | static_assert( |
247 | 25.7M | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || |
248 | 25.7M | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || |
249 | 25.7M | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || |
250 | 25.7M | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || |
251 | 25.7M | std::is_same_v<T, float> || std::is_same_v<T, double>); |
252 | 25.7M | #endif |
253 | | |
254 | 25.7M | T res = 0; |
255 | 25.7M | if (m_file->read(offset, sizeof(res), &res) != sizeof(res)) |
256 | 28.9k | { |
257 | 28.9k | ok = false; |
258 | 28.9k | return 0; |
259 | 28.9k | } |
260 | | if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) |
261 | 25.6M | { |
262 | 25.6M | if (m_mustByteSwap) |
263 | 2.15M | res = byteSwap(res); |
264 | 25.6M | } |
265 | 25.7M | return res; |
266 | 25.7M | } unsigned char GDAL_libertiff::ReadContext::read<unsigned char>(unsigned long, bool&) const Line | Count | Source | 244 | 143k | { | 245 | 143k | #if __cplusplus >= 201703L | 246 | 143k | static_assert( | 247 | 143k | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 248 | 143k | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 249 | 143k | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 250 | 143k | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 251 | 143k | std::is_same_v<T, float> || std::is_same_v<T, double>); | 252 | 143k | #endif | 253 | | | 254 | 143k | T res = 0; | 255 | 143k | if (m_file->read(offset, sizeof(res), &res) != sizeof(res)) | 256 | 5.24k | { | 257 | 5.24k | ok = false; | 258 | 5.24k | return 0; | 259 | 5.24k | } | 260 | | if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 261 | | { | 262 | | if (m_mustByteSwap) | 263 | | res = byteSwap(res); | 264 | | } | 265 | 138k | return res; | 266 | 143k | } |
unsigned short GDAL_libertiff::ReadContext::read<unsigned short>(unsigned long, bool&) const Line | Count | Source | 244 | 16.9M | { | 245 | 16.9M | #if __cplusplus >= 201703L | 246 | 16.9M | static_assert( | 247 | 16.9M | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 248 | 16.9M | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 249 | 16.9M | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 250 | 16.9M | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 251 | 16.9M | std::is_same_v<T, float> || std::is_same_v<T, double>); | 252 | 16.9M | #endif | 253 | | | 254 | 16.9M | T res = 0; | 255 | 16.9M | if (m_file->read(offset, sizeof(res), &res) != sizeof(res)) | 256 | 12.3k | { | 257 | 12.3k | ok = false; | 258 | 12.3k | return 0; | 259 | 12.3k | } | 260 | | if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 261 | 16.9M | { | 262 | 16.9M | if (m_mustByteSwap) | 263 | 1.41M | res = byteSwap(res); | 264 | 16.9M | } | 265 | 16.9M | return res; | 266 | 16.9M | } |
unsigned int GDAL_libertiff::ReadContext::read<unsigned int>(unsigned long, bool&) const Line | Count | Source | 244 | 8.60M | { | 245 | 8.60M | #if __cplusplus >= 201703L | 246 | 8.60M | static_assert( | 247 | 8.60M | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 248 | 8.60M | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 249 | 8.60M | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 250 | 8.60M | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 251 | 8.60M | std::is_same_v<T, float> || std::is_same_v<T, double>); | 252 | 8.60M | #endif | 253 | | | 254 | 8.60M | T res = 0; | 255 | 8.60M | if (m_file->read(offset, sizeof(res), &res) != sizeof(res)) | 256 | 8.51k | { | 257 | 8.51k | ok = false; | 258 | 8.51k | return 0; | 259 | 8.51k | } | 260 | | if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 261 | 8.59M | { | 262 | 8.59M | if (m_mustByteSwap) | 263 | 667k | res = byteSwap(res); | 264 | 8.59M | } | 265 | 8.59M | return res; | 266 | 8.60M | } |
unsigned long GDAL_libertiff::ReadContext::read<unsigned long>(unsigned long, bool&) const Line | Count | Source | 244 | 118k | { | 245 | 118k | #if __cplusplus >= 201703L | 246 | 118k | static_assert( | 247 | 118k | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 248 | 118k | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 249 | 118k | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 250 | 118k | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 251 | 118k | std::is_same_v<T, float> || std::is_same_v<T, double>); | 252 | 118k | #endif | 253 | | | 254 | 118k | T res = 0; | 255 | 118k | if (m_file->read(offset, sizeof(res), &res) != sizeof(res)) | 256 | 2.75k | { | 257 | 2.75k | ok = false; | 258 | 2.75k | return 0; | 259 | 2.75k | } | 260 | | if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 261 | 115k | { | 262 | 115k | if (m_mustByteSwap) | 263 | 77.0k | res = byteSwap(res); | 264 | 115k | } | 265 | 115k | return res; | 266 | 118k | } |
int GDAL_libertiff::ReadContext::read<int>(unsigned long, bool&) const Line | Count | Source | 244 | 958 | { | 245 | 958 | #if __cplusplus >= 201703L | 246 | 958 | static_assert( | 247 | 958 | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 248 | 958 | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 249 | 958 | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 250 | 958 | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 251 | 958 | std::is_same_v<T, float> || std::is_same_v<T, double>); | 252 | 958 | #endif | 253 | | | 254 | 958 | T res = 0; | 255 | 958 | if (m_file->read(offset, sizeof(res), &res) != sizeof(res)) | 256 | 24 | { | 257 | 24 | ok = false; | 258 | 24 | return 0; | 259 | 24 | } | 260 | | if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 261 | 934 | { | 262 | 934 | if (m_mustByteSwap) | 263 | 443 | res = byteSwap(res); | 264 | 934 | } | 265 | 934 | return res; | 266 | 958 | } |
|
267 | | |
268 | | /** Read a unsigned rational (type == Type::Rational) */ |
269 | | template <class T = uint32_t> |
270 | | double readRational(uint64_t offset, bool &ok) const |
271 | 1.12k | { |
272 | 1.12k | const auto numerator = read<T>(offset, ok); |
273 | 1.12k | const auto denominator = read<T>(offset + sizeof(T), ok); |
274 | 1.12k | if (denominator == 0) |
275 | 33 | { |
276 | 33 | ok = false; |
277 | 33 | return std::numeric_limits<double>::quiet_NaN(); |
278 | 33 | } |
279 | 1.09k | return double(numerator) / denominator; |
280 | 1.12k | } double GDAL_libertiff::ReadContext::readRational<unsigned int>(unsigned long, bool&) const Line | Count | Source | 271 | 649 | { | 272 | 649 | const auto numerator = read<T>(offset, ok); | 273 | 649 | const auto denominator = read<T>(offset + sizeof(T), ok); | 274 | 649 | if (denominator == 0) | 275 | 16 | { | 276 | 16 | ok = false; | 277 | 16 | return std::numeric_limits<double>::quiet_NaN(); | 278 | 16 | } | 279 | 633 | return double(numerator) / denominator; | 280 | 649 | } |
double GDAL_libertiff::ReadContext::readRational<int>(unsigned long, bool&) const Line | Count | Source | 271 | 479 | { | 272 | 479 | const auto numerator = read<T>(offset, ok); | 273 | 479 | const auto denominator = read<T>(offset + sizeof(T), ok); | 274 | 479 | if (denominator == 0) | 275 | 17 | { | 276 | 17 | ok = false; | 277 | 17 | return std::numeric_limits<double>::quiet_NaN(); | 278 | 17 | } | 279 | 462 | return double(numerator) / denominator; | 280 | 479 | } |
|
281 | | |
282 | | /** Read a signed rational (type == Type::SRational) */ |
283 | | double readSignedRational(uint64_t offset, bool &ok) const |
284 | 479 | { |
285 | 479 | return readRational<int32_t>(offset, ok); |
286 | 479 | } |
287 | | |
288 | | /** Read length bytes at offset (typically for ASCII tag) as a string */ |
289 | | std::string readString(std::string &res, uint64_t offset, size_t length, |
290 | | bool &ok) const |
291 | 4.20k | { |
292 | 4.20k | res.resize(length); |
293 | 4.20k | if (length > 0 && m_file->read(offset, length, &res[0]) != length) |
294 | 313 | { |
295 | 313 | ok = false; |
296 | 313 | res.clear(); |
297 | 313 | return res; |
298 | 313 | } |
299 | | // Strip trailing nul byte if found |
300 | 3.89k | if (length > 0 && res.back() == 0) |
301 | 1.16k | res.pop_back(); |
302 | 3.89k | return res; |
303 | 4.20k | } |
304 | | |
305 | | /** Read length bytes at offset (typically for ASCII tag) as a string */ |
306 | | std::string readString(uint64_t offset, size_t length, bool &ok) const |
307 | 4.20k | { |
308 | 4.20k | std::string res; |
309 | 4.20k | readString(res, offset, length, ok); |
310 | 4.20k | return res; |
311 | 4.20k | } |
312 | | |
313 | | /** Read an array of count values starting at offset */ |
314 | | template <class T> |
315 | | void readArray(std::vector<T> &array, uint64_t offset, size_t count, |
316 | | bool &ok) const |
317 | 5.11k | { |
318 | 5.11k | #if __cplusplus >= 201703L |
319 | 5.11k | static_assert( |
320 | 5.11k | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || |
321 | 5.11k | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || |
322 | 5.11k | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || |
323 | 5.11k | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || |
324 | 5.11k | std::is_same_v<T, float> || std::is_same_v<T, double>); |
325 | 5.11k | #endif |
326 | | |
327 | 5.11k | array.resize(count); |
328 | 5.11k | const size_t countBytes = count * sizeof(T); |
329 | 5.11k | if (count > 0 && |
330 | 5.11k | m_file->read(offset, countBytes, &array[0]) != countBytes) |
331 | 1.66k | { |
332 | 1.66k | ok = false; |
333 | 1.66k | array.clear(); |
334 | 1.66k | } |
335 | | else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) |
336 | 3.43k | { |
337 | 3.43k | if (m_mustByteSwap) |
338 | 326 | { |
339 | | if LIBERTIFF_CONSTEXPR (std::is_same<T, float>::value) |
340 | | { |
341 | | uint32_t *uint32Array = |
342 | | reinterpret_cast<uint32_t *>(array.data()); |
343 | | for (size_t i = 0; i < count; ++i) |
344 | | { |
345 | | uint32Array[i] = byteSwap(uint32Array[i]); |
346 | | } |
347 | | } |
348 | | else if LIBERTIFF_CONSTEXPR (std::is_same<T, double>::value) |
349 | 49 | { |
350 | 49 | uint64_t *uint64Array = |
351 | 49 | reinterpret_cast<uint64_t *>(array.data()); |
352 | 2.83k | for (size_t i = 0; i < count; ++i) |
353 | 2.78k | { |
354 | 2.78k | uint64Array[i] = byteSwap(uint64Array[i]); |
355 | 2.78k | } |
356 | | } |
357 | | else |
358 | 277 | { |
359 | 35.7k | for (size_t i = 0; i < count; ++i) |
360 | 35.4k | { |
361 | 35.4k | array[i] = byteSwap(array[i]); |
362 | 35.4k | } |
363 | 277 | } |
364 | 326 | } |
365 | 3.43k | } |
366 | 5.11k | } void GDAL_libertiff::ReadContext::readArray<unsigned short>(std::__1::vector<unsigned short, std::__1::allocator<unsigned short> >&, unsigned long, unsigned long, bool&) const Line | Count | Source | 317 | 1.99k | { | 318 | 1.99k | #if __cplusplus >= 201703L | 319 | 1.99k | static_assert( | 320 | 1.99k | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 321 | 1.99k | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 322 | 1.99k | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 323 | 1.99k | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 324 | 1.99k | std::is_same_v<T, float> || std::is_same_v<T, double>); | 325 | 1.99k | #endif | 326 | | | 327 | 1.99k | array.resize(count); | 328 | 1.99k | const size_t countBytes = count * sizeof(T); | 329 | 1.99k | if (count > 0 && | 330 | 1.99k | m_file->read(offset, countBytes, &array[0]) != countBytes) | 331 | 549 | { | 332 | 549 | ok = false; | 333 | 549 | array.clear(); | 334 | 549 | } | 335 | | else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 336 | 1.44k | { | 337 | 1.44k | if (m_mustByteSwap) | 338 | 274 | { | 339 | | if LIBERTIFF_CONSTEXPR (std::is_same<T, float>::value) | 340 | | { | 341 | | uint32_t *uint32Array = | 342 | | reinterpret_cast<uint32_t *>(array.data()); | 343 | | for (size_t i = 0; i < count; ++i) | 344 | | { | 345 | | uint32Array[i] = byteSwap(uint32Array[i]); | 346 | | } | 347 | | } | 348 | | else if LIBERTIFF_CONSTEXPR (std::is_same<T, double>::value) | 349 | | { | 350 | | uint64_t *uint64Array = | 351 | | reinterpret_cast<uint64_t *>(array.data()); | 352 | | for (size_t i = 0; i < count; ++i) | 353 | | { | 354 | | uint64Array[i] = byteSwap(uint64Array[i]); | 355 | | } | 356 | | } | 357 | | else | 358 | 274 | { | 359 | 35.7k | for (size_t i = 0; i < count; ++i) | 360 | 35.4k | { | 361 | 35.4k | array[i] = byteSwap(array[i]); | 362 | 35.4k | } | 363 | 274 | } | 364 | 274 | } | 365 | 1.44k | } | 366 | 1.99k | } |
void GDAL_libertiff::ReadContext::readArray<unsigned char>(std::__1::vector<unsigned char, std::__1::allocator<unsigned char> >&, unsigned long, unsigned long, bool&) const Line | Count | Source | 317 | 9 | { | 318 | 9 | #if __cplusplus >= 201703L | 319 | 9 | static_assert( | 320 | 9 | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 321 | 9 | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 322 | 9 | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 323 | 9 | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 324 | 9 | std::is_same_v<T, float> || std::is_same_v<T, double>); | 325 | 9 | #endif | 326 | | | 327 | 9 | array.resize(count); | 328 | 9 | const size_t countBytes = count * sizeof(T); | 329 | 9 | if (count > 0 && | 330 | 9 | m_file->read(offset, countBytes, &array[0]) != countBytes) | 331 | 0 | { | 332 | 0 | ok = false; | 333 | 0 | array.clear(); | 334 | 0 | } | 335 | 9 | else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 336 | 9 | { | 337 | 9 | if (m_mustByteSwap) | 338 | 9 | { | 339 | 9 | if LIBERTIFF_CONSTEXPR (std::is_same<T, float>::value) | 340 | 9 | { | 341 | 9 | uint32_t *uint32Array = | 342 | 9 | reinterpret_cast<uint32_t *>(array.data()); | 343 | 9 | for (size_t i = 0; i < count; ++i) | 344 | 9 | { | 345 | 9 | uint32Array[i] = byteSwap(uint32Array[i]); | 346 | 9 | } | 347 | 9 | } | 348 | 9 | else if LIBERTIFF_CONSTEXPR (std::is_same<T, double>::value) | 349 | 9 | { | 350 | 9 | uint64_t *uint64Array = | 351 | 9 | reinterpret_cast<uint64_t *>(array.data()); | 352 | 9 | for (size_t i = 0; i < count; ++i) | 353 | 9 | { | 354 | 9 | uint64Array[i] = byteSwap(uint64Array[i]); | 355 | 9 | } | 356 | 9 | } | 357 | 9 | else | 358 | 9 | { | 359 | 9 | for (size_t i = 0; i < count; ++i) | 360 | 9 | { | 361 | 9 | array[i] = byteSwap(array[i]); | 362 | 9 | } | 363 | 9 | } | 364 | 9 | } | 365 | 9 | } | 366 | 9 | } |
void GDAL_libertiff::ReadContext::readArray<unsigned int>(std::__1::vector<unsigned int, std::__1::allocator<unsigned int> >&, unsigned long, unsigned long, bool&) const Line | Count | Source | 317 | 752 | { | 318 | 752 | #if __cplusplus >= 201703L | 319 | 752 | static_assert( | 320 | 752 | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 321 | 752 | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 322 | 752 | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 323 | 752 | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 324 | 752 | std::is_same_v<T, float> || std::is_same_v<T, double>); | 325 | 752 | #endif | 326 | | | 327 | 752 | array.resize(count); | 328 | 752 | const size_t countBytes = count * sizeof(T); | 329 | 752 | if (count > 0 && | 330 | 752 | m_file->read(offset, countBytes, &array[0]) != countBytes) | 331 | 108 | { | 332 | 108 | ok = false; | 333 | 108 | array.clear(); | 334 | 108 | } | 335 | | else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 336 | 644 | { | 337 | 644 | if (m_mustByteSwap) | 338 | 3 | { | 339 | | if LIBERTIFF_CONSTEXPR (std::is_same<T, float>::value) | 340 | | { | 341 | | uint32_t *uint32Array = | 342 | | reinterpret_cast<uint32_t *>(array.data()); | 343 | | for (size_t i = 0; i < count; ++i) | 344 | | { | 345 | | uint32Array[i] = byteSwap(uint32Array[i]); | 346 | | } | 347 | | } | 348 | | else if LIBERTIFF_CONSTEXPR (std::is_same<T, double>::value) | 349 | | { | 350 | | uint64_t *uint64Array = | 351 | | reinterpret_cast<uint64_t *>(array.data()); | 352 | | for (size_t i = 0; i < count; ++i) | 353 | | { | 354 | | uint64Array[i] = byteSwap(uint64Array[i]); | 355 | | } | 356 | | } | 357 | | else | 358 | 3 | { | 359 | 12 | for (size_t i = 0; i < count; ++i) | 360 | 9 | { | 361 | 9 | array[i] = byteSwap(array[i]); | 362 | 9 | } | 363 | 3 | } | 364 | 3 | } | 365 | 644 | } | 366 | 752 | } |
void GDAL_libertiff::ReadContext::readArray<unsigned long>(std::__1::vector<unsigned long, std::__1::allocator<unsigned long> >&, unsigned long, unsigned long, bool&) const Line | Count | Source | 317 | 50 | { | 318 | 50 | #if __cplusplus >= 201703L | 319 | 50 | static_assert( | 320 | 50 | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 321 | 50 | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 322 | 50 | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 323 | 50 | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 324 | 50 | std::is_same_v<T, float> || std::is_same_v<T, double>); | 325 | 50 | #endif | 326 | | | 327 | 50 | array.resize(count); | 328 | 50 | const size_t countBytes = count * sizeof(T); | 329 | 50 | if (count > 0 && | 330 | 50 | m_file->read(offset, countBytes, &array[0]) != countBytes) | 331 | 36 | { | 332 | 36 | ok = false; | 333 | 36 | array.clear(); | 334 | 36 | } | 335 | | else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 336 | 14 | { | 337 | 14 | if (m_mustByteSwap) | 338 | 0 | { | 339 | | if LIBERTIFF_CONSTEXPR (std::is_same<T, float>::value) | 340 | | { | 341 | | uint32_t *uint32Array = | 342 | | reinterpret_cast<uint32_t *>(array.data()); | 343 | | for (size_t i = 0; i < count; ++i) | 344 | | { | 345 | | uint32Array[i] = byteSwap(uint32Array[i]); | 346 | | } | 347 | | } | 348 | | else if LIBERTIFF_CONSTEXPR (std::is_same<T, double>::value) | 349 | | { | 350 | | uint64_t *uint64Array = | 351 | | reinterpret_cast<uint64_t *>(array.data()); | 352 | | for (size_t i = 0; i < count; ++i) | 353 | | { | 354 | | uint64Array[i] = byteSwap(uint64Array[i]); | 355 | | } | 356 | | } | 357 | | else | 358 | 0 | { | 359 | 0 | for (size_t i = 0; i < count; ++i) | 360 | 0 | { | 361 | 0 | array[i] = byteSwap(array[i]); | 362 | 0 | } | 363 | 0 | } | 364 | 0 | } | 365 | 14 | } | 366 | 50 | } |
void GDAL_libertiff::ReadContext::readArray<double>(std::__1::vector<double, std::__1::allocator<double> >&, unsigned long, unsigned long, bool&) const Line | Count | Source | 317 | 2.30k | { | 318 | 2.30k | #if __cplusplus >= 201703L | 319 | 2.30k | static_assert( | 320 | 2.30k | std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> || | 321 | 2.30k | std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> || | 322 | 2.30k | std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> || | 323 | 2.30k | std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> || | 324 | 2.30k | std::is_same_v<T, float> || std::is_same_v<T, double>); | 325 | 2.30k | #endif | 326 | | | 327 | 2.30k | array.resize(count); | 328 | 2.30k | const size_t countBytes = count * sizeof(T); | 329 | 2.30k | if (count > 0 && | 330 | 2.30k | m_file->read(offset, countBytes, &array[0]) != countBytes) | 331 | 969 | { | 332 | 969 | ok = false; | 333 | 969 | array.clear(); | 334 | 969 | } | 335 | | else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1) | 336 | 1.33k | { | 337 | 1.33k | if (m_mustByteSwap) | 338 | 49 | { | 339 | | if LIBERTIFF_CONSTEXPR (std::is_same<T, float>::value) | 340 | | { | 341 | | uint32_t *uint32Array = | 342 | | reinterpret_cast<uint32_t *>(array.data()); | 343 | | for (size_t i = 0; i < count; ++i) | 344 | | { | 345 | | uint32Array[i] = byteSwap(uint32Array[i]); | 346 | | } | 347 | | } | 348 | | else if LIBERTIFF_CONSTEXPR (std::is_same<T, double>::value) | 349 | 49 | { | 350 | 49 | uint64_t *uint64Array = | 351 | 49 | reinterpret_cast<uint64_t *>(array.data()); | 352 | 2.83k | for (size_t i = 0; i < count; ++i) | 353 | 2.78k | { | 354 | 2.78k | uint64Array[i] = byteSwap(uint64Array[i]); | 355 | 2.78k | } | 356 | | } | 357 | | else | 358 | | { | 359 | | for (size_t i = 0; i < count; ++i) | 360 | | { | 361 | | array[i] = byteSwap(array[i]); | 362 | | } | 363 | | } | 364 | 49 | } | 365 | 1.33k | } | 366 | 2.30k | } |
Unexecuted instantiation: void GDAL_libertiff::ReadContext::readArray<signed char>(std::__1::vector<signed char, std::__1::allocator<signed char> >&, unsigned long, unsigned long, bool&) const Unexecuted instantiation: void GDAL_libertiff::ReadContext::readArray<short>(std::__1::vector<short, std::__1::allocator<short> >&, unsigned long, unsigned long, bool&) const Unexecuted instantiation: void GDAL_libertiff::ReadContext::readArray<int>(std::__1::vector<int, std::__1::allocator<int> >&, unsigned long, unsigned long, bool&) const Unexecuted instantiation: void GDAL_libertiff::ReadContext::readArray<long>(std::__1::vector<long, std::__1::allocator<long> >&, unsigned long, unsigned long, bool&) const Unexecuted instantiation: void GDAL_libertiff::ReadContext::readArray<float>(std::__1::vector<float, std::__1::allocator<float> >&, unsigned long, unsigned long, bool&) const |
367 | | |
368 | | /** Read an array of count values starting at offset */ |
369 | | template <class T> |
370 | | std::vector<T> readArray(uint64_t offset, size_t count, bool &ok) const |
371 | 5.11k | { |
372 | 5.11k | std::vector<T> array; |
373 | 5.11k | readArray(array, offset, count, ok); |
374 | 5.11k | return array; |
375 | 5.11k | } std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > GDAL_libertiff::ReadContext::readArray<unsigned short>(unsigned long, unsigned long, bool&) const Line | Count | Source | 371 | 1.99k | { | 372 | 1.99k | std::vector<T> array; | 373 | 1.99k | readArray(array, offset, count, ok); | 374 | 1.99k | return array; | 375 | 1.99k | } |
std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > GDAL_libertiff::ReadContext::readArray<unsigned char>(unsigned long, unsigned long, bool&) const Line | Count | Source | 371 | 9 | { | 372 | 9 | std::vector<T> array; | 373 | 9 | readArray(array, offset, count, ok); | 374 | 9 | return array; | 375 | 9 | } |
std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > GDAL_libertiff::ReadContext::readArray<unsigned int>(unsigned long, unsigned long, bool&) const Line | Count | Source | 371 | 752 | { | 372 | 752 | std::vector<T> array; | 373 | 752 | readArray(array, offset, count, ok); | 374 | 752 | return array; | 375 | 752 | } |
std::__1::vector<unsigned long, std::__1::allocator<unsigned long> > GDAL_libertiff::ReadContext::readArray<unsigned long>(unsigned long, unsigned long, bool&) const Line | Count | Source | 371 | 50 | { | 372 | 50 | std::vector<T> array; | 373 | 50 | readArray(array, offset, count, ok); | 374 | 50 | return array; | 375 | 50 | } |
std::__1::vector<double, std::__1::allocator<double> > GDAL_libertiff::ReadContext::readArray<double>(unsigned long, unsigned long, bool&) const Line | Count | Source | 371 | 2.30k | { | 372 | 2.30k | std::vector<T> array; | 373 | 2.30k | readArray(array, offset, count, ok); | 374 | 2.30k | return array; | 375 | 2.30k | } |
Unexecuted instantiation: std::__1::vector<signed char, std::__1::allocator<signed char> > GDAL_libertiff::ReadContext::readArray<signed char>(unsigned long, unsigned long, bool&) const Unexecuted instantiation: std::__1::vector<short, std::__1::allocator<short> > GDAL_libertiff::ReadContext::readArray<short>(unsigned long, unsigned long, bool&) const Unexecuted instantiation: std::__1::vector<int, std::__1::allocator<int> > GDAL_libertiff::ReadContext::readArray<int>(unsigned long, unsigned long, bool&) const Unexecuted instantiation: std::__1::vector<long, std::__1::allocator<long> > GDAL_libertiff::ReadContext::readArray<long>(unsigned long, unsigned long, bool&) const Unexecuted instantiation: std::__1::vector<float, std::__1::allocator<float> > GDAL_libertiff::ReadContext::readArray<float>(unsigned long, unsigned long, bool&) const |
376 | | |
377 | | private: |
378 | | const std::shared_ptr<const FileReader> m_file; |
379 | | const bool m_mustByteSwap; |
380 | | }; |
381 | | } // namespace LIBERTIFF_NS |
382 | | |
383 | | namespace LIBERTIFF_NS |
384 | | { |
385 | | /** Type of a TIFF tag code */ |
386 | | typedef uint16_t TagCodeType; |
387 | | |
388 | | /** TIFF tag codes */ |
389 | | namespace TagCode |
390 | | { |
391 | | constexpr TagCodeType SubFileType = 254; |
392 | | constexpr TagCodeType OldSubFileType = 255; |
393 | | |
394 | | // Base line and extended TIFF tags |
395 | | constexpr TagCodeType ImageWidth = 256; |
396 | | constexpr TagCodeType ImageLength = 257; |
397 | | constexpr TagCodeType BitsPerSample = 258; |
398 | | constexpr TagCodeType Compression = 259; |
399 | | constexpr TagCodeType PhotometricInterpretation = 262; |
400 | | constexpr TagCodeType DocumentName = 269; |
401 | | constexpr TagCodeType ImageDescription = 270; |
402 | | constexpr TagCodeType StripOffsets = 273; |
403 | | constexpr TagCodeType SamplesPerPixel = 277; |
404 | | constexpr TagCodeType RowsPerStrip = 278; |
405 | | constexpr TagCodeType StripByteCounts = 279; |
406 | | constexpr TagCodeType PlanarConfiguration = 284; |
407 | | constexpr TagCodeType Software = 305; |
408 | | constexpr TagCodeType DateTime = 306; |
409 | | constexpr TagCodeType Predictor = 317; |
410 | | constexpr TagCodeType ColorMap = 320; |
411 | | constexpr TagCodeType TileWidth = 322; |
412 | | constexpr TagCodeType TileLength = 323; |
413 | | constexpr TagCodeType TileOffsets = 324; |
414 | | constexpr TagCodeType TileByteCounts = 325; |
415 | | constexpr TagCodeType ExtraSamples = 338; |
416 | | constexpr TagCodeType SampleFormat = 339; |
417 | | constexpr TagCodeType JPEGTables = 347; |
418 | | |
419 | | constexpr TagCodeType Copyright = 33432; |
420 | | |
421 | | // GeoTIFF tags |
422 | | constexpr TagCodeType GeoTIFFPixelScale = 33550; |
423 | | constexpr TagCodeType GeoTIFFTiePoints = 33922; |
424 | | constexpr TagCodeType GeoTIFFGeoTransMatrix = 34264; |
425 | | constexpr TagCodeType GeoTIFFGeoKeyDirectory = 34735; |
426 | | constexpr TagCodeType GeoTIFFDoubleParams = 34736; |
427 | | constexpr TagCodeType GeoTIFFAsciiParams = 34737; |
428 | | |
429 | | // GDAL tags |
430 | | constexpr TagCodeType GDAL_METADATA = 42112; |
431 | | constexpr TagCodeType GDAL_NODATA = 42113; |
432 | | |
433 | | // GeoTIFF related |
434 | | constexpr TagCodeType RPCCoefficients = 50844; |
435 | | |
436 | | // LERC compression related |
437 | | constexpr TagCodeType LERCParameters = |
438 | | 50674; /* Stores LERC version and additional compression method */ |
439 | | |
440 | | } // namespace TagCode |
441 | | |
442 | | /** Binary or'ed value of SubFileType flags */ |
443 | | namespace SubFileTypeFlags |
444 | | { |
445 | | constexpr uint32_t ReducedImage = 0x1; /* reduced resolution version */ |
446 | | constexpr uint32_t Page = 0x2; /* one page of many */ |
447 | | constexpr uint32_t Mask = 0x4; /* transparency mask */ |
448 | | } // namespace SubFileTypeFlags |
449 | | |
450 | | #define LIBERTIFF_CASE_TAGCODE_STR(x) \ |
451 | | case TagCode::x: \ |
452 | | return #x |
453 | | |
454 | | inline const char *tagCodeName(TagCodeType tagCode) |
455 | 0 | { |
456 | 0 | switch (tagCode) |
457 | 0 | { |
458 | 0 | LIBERTIFF_CASE_TAGCODE_STR(SubFileType); |
459 | 0 | LIBERTIFF_CASE_TAGCODE_STR(OldSubFileType); |
460 | 0 | LIBERTIFF_CASE_TAGCODE_STR(ImageWidth); |
461 | 0 | LIBERTIFF_CASE_TAGCODE_STR(ImageLength); |
462 | 0 | LIBERTIFF_CASE_TAGCODE_STR(BitsPerSample); |
463 | 0 | LIBERTIFF_CASE_TAGCODE_STR(Compression); |
464 | 0 | LIBERTIFF_CASE_TAGCODE_STR(PhotometricInterpretation); |
465 | 0 | LIBERTIFF_CASE_TAGCODE_STR(DocumentName); |
466 | 0 | LIBERTIFF_CASE_TAGCODE_STR(ImageDescription); |
467 | 0 | LIBERTIFF_CASE_TAGCODE_STR(StripOffsets); |
468 | 0 | LIBERTIFF_CASE_TAGCODE_STR(SamplesPerPixel); |
469 | 0 | LIBERTIFF_CASE_TAGCODE_STR(RowsPerStrip); |
470 | 0 | LIBERTIFF_CASE_TAGCODE_STR(StripByteCounts); |
471 | 0 | LIBERTIFF_CASE_TAGCODE_STR(PlanarConfiguration); |
472 | 0 | LIBERTIFF_CASE_TAGCODE_STR(Software); |
473 | 0 | LIBERTIFF_CASE_TAGCODE_STR(DateTime); |
474 | 0 | LIBERTIFF_CASE_TAGCODE_STR(Predictor); |
475 | 0 | LIBERTIFF_CASE_TAGCODE_STR(ColorMap); |
476 | 0 | LIBERTIFF_CASE_TAGCODE_STR(TileWidth); |
477 | 0 | LIBERTIFF_CASE_TAGCODE_STR(TileLength); |
478 | 0 | LIBERTIFF_CASE_TAGCODE_STR(TileOffsets); |
479 | 0 | LIBERTIFF_CASE_TAGCODE_STR(TileByteCounts); |
480 | 0 | LIBERTIFF_CASE_TAGCODE_STR(ExtraSamples); |
481 | 0 | LIBERTIFF_CASE_TAGCODE_STR(SampleFormat); |
482 | 0 | LIBERTIFF_CASE_TAGCODE_STR(Copyright); |
483 | 0 | LIBERTIFF_CASE_TAGCODE_STR(JPEGTables); |
484 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFPixelScale); |
485 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFTiePoints); |
486 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFGeoTransMatrix); |
487 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFGeoKeyDirectory); |
488 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFDoubleParams); |
489 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFAsciiParams); |
490 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GDAL_METADATA); |
491 | 0 | LIBERTIFF_CASE_TAGCODE_STR(GDAL_NODATA); |
492 | 0 | LIBERTIFF_CASE_TAGCODE_STR(RPCCoefficients); |
493 | 0 | LIBERTIFF_CASE_TAGCODE_STR(LERCParameters); |
494 | 0 | default: |
495 | 0 | break; |
496 | 0 | } |
497 | 0 | return "(unknown)"; |
498 | 0 | } |
499 | | |
500 | | #undef LIBERTIFF_CASE_TAGCODE_STR |
501 | | |
502 | | /** Type of a TIFF tag type */ |
503 | | typedef uint16_t TagTypeType; |
504 | | |
505 | | /** TIFF tag data types */ |
506 | | namespace TagType |
507 | | { |
508 | | constexpr TagTypeType Byte = 1; /*! Unsigned 8-bit integer */ |
509 | | constexpr TagTypeType ASCII = 2; /*! Character */ |
510 | | constexpr TagTypeType Short = 3; /*! Unsigned 16-bit integer */ |
511 | | constexpr TagTypeType Long = 4; /*! Unsigned 32-bit integer */ |
512 | | constexpr TagTypeType Rational = |
513 | | 5; /*! Positive number as a ratio of two unsigned 32-bit integers */ |
514 | | constexpr TagTypeType SByte = 6; /*! Signed 8-bit integer */ |
515 | | constexpr TagTypeType Undefined = 7; /*! Untyped 8-bit data */ |
516 | | constexpr TagTypeType SShort = 8; /*! Signed 16-bit integer */ |
517 | | constexpr TagTypeType SLong = 9; /*! Signed 32-bit integer */ |
518 | | constexpr TagTypeType SRational = |
519 | | 10; /*! Signed number as a ratio of two signed 32-bit integers */ |
520 | | constexpr TagTypeType Float = 11; /*! 32-bit IEEE-754 floating point number */ |
521 | | constexpr TagTypeType Double = 12; /*! 64-bit IEEE-754 floating point number */ |
522 | | |
523 | | // BigTIFF additions |
524 | | constexpr TagTypeType Long8 = 16; /*! Unsigned 64-bit integer */ |
525 | | constexpr TagTypeType SLong8 = 17; /*! Signed 64-bit integer */ |
526 | | constexpr TagTypeType IFD8 = 18; /*! Unsigned 64-bit IFD offset */ |
527 | | } // namespace TagType |
528 | | |
529 | | #define LIBERTIFF_CASE_TAGTYPE_STR(x) \ |
530 | | case TagType::x: \ |
531 | | return #x |
532 | | |
533 | | inline const char *tagTypeName(TagTypeType tagType) |
534 | 0 | { |
535 | 0 | switch (tagType) |
536 | 0 | { |
537 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Byte); |
538 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(ASCII); |
539 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Short); |
540 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Long); |
541 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Rational); |
542 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(SByte); |
543 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Undefined); |
544 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(SShort); |
545 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(SLong); |
546 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(SRational); |
547 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Float); |
548 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Double); |
549 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(Long8); |
550 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(SLong8); |
551 | 0 | LIBERTIFF_CASE_TAGTYPE_STR(IFD8); |
552 | 0 | default: |
553 | 0 | break; |
554 | 0 | } |
555 | 0 | return "(unknown)"; |
556 | 0 | } |
557 | | |
558 | | #undef LIBERTIFF_CASE_TAGTYPE_STR |
559 | | |
560 | | /** Type of a PlanarConfiguration value */ |
561 | | typedef uint32_t PlanarConfigurationType; |
562 | | |
563 | | /** Values of the PlanarConfiguration tag */ |
564 | | namespace PlanarConfiguration |
565 | | { |
566 | | constexpr PlanarConfigurationType Contiguous = 1; /*! Single image plane */ |
567 | | constexpr PlanarConfigurationType Separate = |
568 | | 2; /*! Separate planes per sample */ |
569 | | } // namespace PlanarConfiguration |
570 | | |
571 | | #define LIBERTIFF_CASE_PLANAR_CONFIG_STR(x) \ |
572 | | case PlanarConfiguration::x: \ |
573 | | return #x |
574 | | |
575 | | inline const char * |
576 | | planarConfigurationName(PlanarConfigurationType planarConfiguration) |
577 | 0 | { |
578 | 0 | switch (planarConfiguration) |
579 | 0 | { |
580 | 0 | LIBERTIFF_CASE_PLANAR_CONFIG_STR(Contiguous); |
581 | 0 | LIBERTIFF_CASE_PLANAR_CONFIG_STR(Separate); |
582 | 0 | default: |
583 | 0 | break; |
584 | 0 | } |
585 | 0 | return "(unknown)"; |
586 | 0 | } |
587 | | |
588 | | #undef LIBERTIFF_CASE_PLANAR_CONFIG_STR |
589 | | |
590 | | /** Type of a PlanarConfiguration value */ |
591 | | typedef uint32_t PhotometricInterpretationType; |
592 | | |
593 | | /** Values of the PhotometricInterpretation tag */ |
594 | | namespace PhotometricInterpretation |
595 | | { |
596 | | constexpr PhotometricInterpretationType MinIsWhite = 0; |
597 | | constexpr PhotometricInterpretationType MinIsBlack = 1; |
598 | | constexpr PhotometricInterpretationType RGB = 2; |
599 | | constexpr PhotometricInterpretationType Palette = 3; |
600 | | constexpr PhotometricInterpretationType Mask = 4; |
601 | | constexpr PhotometricInterpretationType Separated = 5; |
602 | | constexpr PhotometricInterpretationType YCbCr = 6; |
603 | | constexpr PhotometricInterpretationType CIELab = 8; |
604 | | constexpr PhotometricInterpretationType ICCLab = 9; |
605 | | constexpr PhotometricInterpretationType ITULab = 10; |
606 | | } // namespace PhotometricInterpretation |
607 | | |
608 | | #define LIBERTIFF_CASE_PHOTOMETRIC_STR(x) \ |
609 | | case PhotometricInterpretation::x: \ |
610 | | return #x |
611 | | |
612 | | inline const char *photometricInterpretationName( |
613 | | PhotometricInterpretationType photometricInterpretation) |
614 | 0 | { |
615 | 0 | switch (photometricInterpretation) |
616 | 0 | { |
617 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(MinIsWhite); |
618 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(MinIsBlack); |
619 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(RGB); |
620 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(Palette); |
621 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(Mask); |
622 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(Separated); |
623 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(YCbCr); |
624 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(CIELab); |
625 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(ICCLab); |
626 | 0 | LIBERTIFF_CASE_PHOTOMETRIC_STR(ITULab); |
627 | 0 | default: |
628 | 0 | break; |
629 | 0 | } |
630 | 0 | return "(unknown)"; |
631 | 0 | } |
632 | | |
633 | | #undef LIBERTIFF_CASE_PHOTOMETRIC_STR |
634 | | |
635 | | /** Type of a Compression value */ |
636 | | typedef uint32_t CompressionType; |
637 | | |
638 | | /** Compression methods */ |
639 | | namespace Compression |
640 | | { |
641 | | constexpr CompressionType None = 1; |
642 | | constexpr CompressionType CCITT_RLE = 2; |
643 | | constexpr CompressionType CCITT_FAX3 = 3; |
644 | | constexpr CompressionType CCITT_FAX4 = 4; |
645 | | constexpr CompressionType LZW = 5; |
646 | | constexpr CompressionType OldJPEG = 6; |
647 | | constexpr CompressionType JPEG = 7; |
648 | | constexpr CompressionType Deflate = |
649 | | 8; /* Deflate compression, as recognized by Adobe */ |
650 | | constexpr CompressionType PackBits = 32773; |
651 | | constexpr CompressionType LegacyDeflate = |
652 | | 32946; /* Deflate compression, legacy tag */ |
653 | | constexpr CompressionType JBIG = 34661; /* ISO JBIG */ |
654 | | constexpr CompressionType LERC = |
655 | | 34887; /* ESRI Lerc codec: https://github.com/Esri/lerc */ |
656 | | constexpr CompressionType LZMA = 34925; /* LZMA2 */ |
657 | | constexpr CompressionType ZSTD = |
658 | | 50000; /* ZSTD: WARNING not registered in Adobe-maintained registry */ |
659 | | constexpr CompressionType WEBP = |
660 | | 50001; /* WEBP: WARNING not registered in Adobe-maintained registry */ |
661 | | constexpr CompressionType JXL = |
662 | | 50002; /* JPEGXL: WARNING not registered in Adobe-maintained registry */ |
663 | | constexpr CompressionType JXL_DNG_1_7 = |
664 | | 52546; /* JPEGXL from DNG 1.7 specification */ |
665 | | } // namespace Compression |
666 | | |
667 | | #define LIBERTIFF_CASE_COMPRESSION_STR(x) \ |
668 | 195 | case Compression::x: \ |
669 | 195 | return #x |
670 | | |
671 | | inline const char *compressionName(CompressionType compression) |
672 | 459 | { |
673 | 459 | switch (compression) |
674 | 459 | { |
675 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(None); |
676 | 23 | LIBERTIFF_CASE_COMPRESSION_STR(CCITT_RLE); |
677 | 63 | LIBERTIFF_CASE_COMPRESSION_STR(CCITT_FAX3); |
678 | 90 | LIBERTIFF_CASE_COMPRESSION_STR(CCITT_FAX4); |
679 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(LZW); |
680 | 18 | LIBERTIFF_CASE_COMPRESSION_STR(OldJPEG); |
681 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(JPEG); |
682 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(Deflate); |
683 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(PackBits); |
684 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(LegacyDeflate); |
685 | 1 | LIBERTIFF_CASE_COMPRESSION_STR(JBIG); |
686 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(LERC); |
687 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(LZMA); |
688 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(ZSTD); |
689 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(WEBP); |
690 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(JXL); |
691 | 0 | LIBERTIFF_CASE_COMPRESSION_STR(JXL_DNG_1_7); |
692 | 264 | default: |
693 | 264 | break; |
694 | 459 | } |
695 | 264 | return "(unknown)"; |
696 | 459 | } |
697 | | |
698 | | #undef LIBERTIFF_CASE_COMPRESSION_STR |
699 | | |
700 | | /** Type of a SampleFormat value */ |
701 | | typedef uint32_t SampleFormatType; |
702 | | |
703 | | /** Sample format */ |
704 | | namespace SampleFormat |
705 | | { |
706 | | constexpr SampleFormatType UnsignedInt = 1; |
707 | | constexpr SampleFormatType SignedInt = 2; |
708 | | constexpr SampleFormatType IEEEFP = 3; |
709 | | constexpr SampleFormatType Void = 4; |
710 | | constexpr SampleFormatType ComplexInt = 5; |
711 | | constexpr SampleFormatType ComplexIEEEFP = 6; |
712 | | } // namespace SampleFormat |
713 | | |
714 | | #define LIBERTIFF_CASE_SAMPLE_FORMAT_STR(x) \ |
715 | | case SampleFormat::x: \ |
716 | | return #x |
717 | | |
718 | | inline const char *sampleFormatName(SampleFormatType sampleFormat) |
719 | 0 | { |
720 | 0 | switch (sampleFormat) |
721 | 0 | { |
722 | 0 | LIBERTIFF_CASE_SAMPLE_FORMAT_STR(UnsignedInt); |
723 | 0 | LIBERTIFF_CASE_SAMPLE_FORMAT_STR(SignedInt); |
724 | 0 | LIBERTIFF_CASE_SAMPLE_FORMAT_STR(IEEEFP); |
725 | 0 | LIBERTIFF_CASE_SAMPLE_FORMAT_STR(Void); |
726 | 0 | LIBERTIFF_CASE_SAMPLE_FORMAT_STR(ComplexInt); |
727 | 0 | LIBERTIFF_CASE_SAMPLE_FORMAT_STR(ComplexIEEEFP); |
728 | 0 | default: |
729 | 0 | break; |
730 | 0 | } |
731 | 0 | return "(unknown)"; |
732 | 0 | } |
733 | | |
734 | | #undef LIBERTIFF_CASE_SAMPLE_FORMAT_STR |
735 | | |
736 | | /** Type of a ExtraSamples value */ |
737 | | typedef uint32_t ExtraSamplesType; |
738 | | |
739 | | /** Values of the ExtraSamples tag */ |
740 | | namespace ExtraSamples |
741 | | { |
742 | | constexpr ExtraSamplesType Unspecified = 0; |
743 | | constexpr ExtraSamplesType AssociatedAlpha = 1; /* premultiplied */ |
744 | | constexpr ExtraSamplesType UnAssociatedAlpha = 2; /* unpremultiplied */ |
745 | | } // namespace ExtraSamples |
746 | | |
747 | | /** Content of a tag entry in a Image File Directory (IFD) */ |
748 | | struct TagEntry |
749 | | { |
750 | | TagCodeType tag = 0; |
751 | | TagTypeType type = 0; |
752 | | uint64_t count = 0; // number of values in the tag |
753 | | |
754 | | // Inline values. Only valid if value_offset == 0. |
755 | | // The actual number in the arrays is count |
756 | | union |
757 | | { |
758 | | std::array<char, 8> charValues; |
759 | | std::array<uint8_t, 8> uint8Values; |
760 | | std::array<int8_t, 8> int8Values; |
761 | | std::array<uint16_t, 4> uint16Values; |
762 | | std::array<int16_t, 4> int16Values; |
763 | | std::array<uint32_t, 2> uint32Values; |
764 | | std::array<int32_t, 2> int32Values; |
765 | | std::array<float, 2> float32Values; |
766 | | std::array<double, 1> |
767 | | float64Values; // Valid for Double, Rational, SRational |
768 | | std::array<uint64_t, 1> uint64Values = {0}; |
769 | | std::array<int64_t, 1> int64Values; |
770 | | }; |
771 | | |
772 | | uint64_t value_offset = 0; // 0 for inline values |
773 | | bool invalid_value_offset = true; // whether value_offset is invalid |
774 | | }; |
775 | | |
776 | | // clang-format off |
777 | | |
778 | | /** Return the size in bytes of a tag data type, or 0 if unknown */ |
779 | | inline uint32_t tagTypeSize(TagTypeType type) |
780 | 7.26M | { |
781 | 7.26M | switch (type) |
782 | 7.26M | { |
783 | 139k | case TagType::Byte: return 1; |
784 | 37.9k | case TagType::ASCII: return 1; |
785 | 176k | case TagType::Short: return 2; |
786 | 48.1k | case TagType::Long: return 4; |
787 | 8.08k | case TagType::Rational: return 8; // 2 Long |
788 | 10.9k | case TagType::SByte: return 1; |
789 | 3.75k | case TagType::Undefined: return 1; |
790 | 11.7k | case TagType::SShort: return 2; |
791 | 4.38k | case TagType::SLong: return 4; |
792 | 4.89k | case TagType::SRational: return 8; // 2 SLong |
793 | 2.62k | case TagType::Float: return 4; |
794 | 18.4k | case TagType::Double: return 8; |
795 | 6.43k | case TagType::Long8: return 8; |
796 | 3.64k | case TagType::SLong8: return 8; |
797 | 1.44k | case TagType::IFD8: return 8; |
798 | 6.78M | default: break; |
799 | 7.26M | } |
800 | 6.78M | return 0; |
801 | 7.26M | } |
802 | | |
803 | | // clang-format on |
804 | | |
805 | | namespace detail |
806 | | { |
807 | | template <class T> |
808 | | inline std::vector<T> readTagAsVectorInternal(const ReadContext &rc, |
809 | | const TagEntry &tag, |
810 | | TagTypeType expectedType, |
811 | | const T *inlineValues, bool &ok) |
812 | 5.29k | { |
813 | 5.29k | if (tag.type == expectedType) |
814 | 5.29k | { |
815 | 5.29k | if (tag.value_offset) |
816 | 5.12k | { |
817 | 5.12k | if (!tag.invalid_value_offset) |
818 | 5.11k | { |
819 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) |
820 | | { |
821 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) |
822 | | { |
823 | | ok = false; |
824 | | return {}; |
825 | | } |
826 | | } |
827 | 5.11k | return rc.readArray<T>(tag.value_offset, |
828 | 5.11k | static_cast<size_t>(tag.count), ok); |
829 | 5.11k | } |
830 | 5.12k | } |
831 | 170 | else |
832 | 170 | { |
833 | 170 | return std::vector<T>( |
834 | 170 | inlineValues, inlineValues + static_cast<size_t>(tag.count)); |
835 | 170 | } |
836 | 5.29k | } |
837 | 10 | ok = false; |
838 | 10 | return {}; |
839 | 5.29k | } std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > GDAL_libertiff::detail::readTagAsVectorInternal<unsigned short>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, unsigned short const*, bool&) Line | Count | Source | 812 | 2.16k | { | 813 | 2.16k | if (tag.type == expectedType) | 814 | 2.16k | { | 815 | 2.16k | if (tag.value_offset) | 816 | 1.99k | { | 817 | 1.99k | if (!tag.invalid_value_offset) | 818 | 1.99k | { | 819 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) | 820 | | { | 821 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) | 822 | | { | 823 | | ok = false; | 824 | | return {}; | 825 | | } | 826 | | } | 827 | 1.99k | return rc.readArray<T>(tag.value_offset, | 828 | 1.99k | static_cast<size_t>(tag.count), ok); | 829 | 1.99k | } | 830 | 1.99k | } | 831 | 170 | else | 832 | 170 | { | 833 | 170 | return std::vector<T>( | 834 | 170 | inlineValues, inlineValues + static_cast<size_t>(tag.count)); | 835 | 170 | } | 836 | 2.16k | } | 837 | 0 | ok = false; | 838 | 0 | return {}; | 839 | 2.16k | } |
std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > GDAL_libertiff::detail::readTagAsVectorInternal<unsigned char>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, unsigned char const*, bool&) Line | Count | Source | 812 | 9 | { | 813 | 9 | if (tag.type == expectedType) | 814 | 9 | { | 815 | 9 | if (tag.value_offset) | 816 | 9 | { | 817 | 9 | if (!tag.invalid_value_offset) | 818 | 9 | { | 819 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) | 820 | | { | 821 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) | 822 | | { | 823 | | ok = false; | 824 | | return {}; | 825 | | } | 826 | | } | 827 | 9 | return rc.readArray<T>(tag.value_offset, | 828 | 9 | static_cast<size_t>(tag.count), ok); | 829 | 9 | } | 830 | 9 | } | 831 | 0 | else | 832 | 0 | { | 833 | 0 | return std::vector<T>( | 834 | 0 | inlineValues, inlineValues + static_cast<size_t>(tag.count)); | 835 | 0 | } | 836 | 9 | } | 837 | 0 | ok = false; | 838 | 0 | return {}; | 839 | 9 | } |
std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > GDAL_libertiff::detail::readTagAsVectorInternal<unsigned int>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, unsigned int const*, bool&) Line | Count | Source | 812 | 752 | { | 813 | 752 | if (tag.type == expectedType) | 814 | 752 | { | 815 | 752 | if (tag.value_offset) | 816 | 752 | { | 817 | 752 | if (!tag.invalid_value_offset) | 818 | 752 | { | 819 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) | 820 | | { | 821 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) | 822 | | { | 823 | | ok = false; | 824 | | return {}; | 825 | | } | 826 | | } | 827 | 752 | return rc.readArray<T>(tag.value_offset, | 828 | 752 | static_cast<size_t>(tag.count), ok); | 829 | 752 | } | 830 | 752 | } | 831 | 0 | else | 832 | 0 | { | 833 | 0 | return std::vector<T>( | 834 | 0 | inlineValues, inlineValues + static_cast<size_t>(tag.count)); | 835 | 0 | } | 836 | 752 | } | 837 | 0 | ok = false; | 838 | 0 | return {}; | 839 | 752 | } |
std::__1::vector<unsigned long, std::__1::allocator<unsigned long> > GDAL_libertiff::detail::readTagAsVectorInternal<unsigned long>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, unsigned long const*, bool&) Line | Count | Source | 812 | 50 | { | 813 | 50 | if (tag.type == expectedType) | 814 | 50 | { | 815 | 50 | if (tag.value_offset) | 816 | 50 | { | 817 | 50 | if (!tag.invalid_value_offset) | 818 | 50 | { | 819 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) | 820 | | { | 821 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) | 822 | | { | 823 | | ok = false; | 824 | | return {}; | 825 | | } | 826 | | } | 827 | 50 | return rc.readArray<T>(tag.value_offset, | 828 | 50 | static_cast<size_t>(tag.count), ok); | 829 | 50 | } | 830 | 50 | } | 831 | 0 | else | 832 | 0 | { | 833 | 0 | return std::vector<T>( | 834 | 0 | inlineValues, inlineValues + static_cast<size_t>(tag.count)); | 835 | 0 | } | 836 | 50 | } | 837 | 0 | ok = false; | 838 | 0 | return {}; | 839 | 50 | } |
std::__1::vector<double, std::__1::allocator<double> > GDAL_libertiff::detail::readTagAsVectorInternal<double>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, double const*, bool&) Line | Count | Source | 812 | 2.31k | { | 813 | 2.31k | if (tag.type == expectedType) | 814 | 2.31k | { | 815 | 2.31k | if (tag.value_offset) | 816 | 2.31k | { | 817 | 2.31k | if (!tag.invalid_value_offset) | 818 | 2.30k | { | 819 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) | 820 | | { | 821 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) | 822 | | { | 823 | | ok = false; | 824 | | return {}; | 825 | | } | 826 | | } | 827 | 2.30k | return rc.readArray<T>(tag.value_offset, | 828 | 2.30k | static_cast<size_t>(tag.count), ok); | 829 | 2.30k | } | 830 | 2.31k | } | 831 | 0 | else | 832 | 0 | { | 833 | 0 | return std::vector<T>( | 834 | 0 | inlineValues, inlineValues + static_cast<size_t>(tag.count)); | 835 | 0 | } | 836 | 2.31k | } | 837 | 10 | ok = false; | 838 | 10 | return {}; | 839 | 2.31k | } |
Unexecuted instantiation: std::__1::vector<signed char, std::__1::allocator<signed char> > GDAL_libertiff::detail::readTagAsVectorInternal<signed char>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, signed char const*, bool&) Unexecuted instantiation: std::__1::vector<short, std::__1::allocator<short> > GDAL_libertiff::detail::readTagAsVectorInternal<short>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, short const*, bool&) Unexecuted instantiation: std::__1::vector<int, std::__1::allocator<int> > GDAL_libertiff::detail::readTagAsVectorInternal<int>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, int const*, bool&) Unexecuted instantiation: std::__1::vector<long, std::__1::allocator<long> > GDAL_libertiff::detail::readTagAsVectorInternal<long>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, long const*, bool&) Unexecuted instantiation: std::__1::vector<float, std::__1::allocator<float> > GDAL_libertiff::detail::readTagAsVectorInternal<float>(GDAL_libertiff::ReadContext const&, GDAL_libertiff::TagEntry const&, unsigned short, float const*, bool&) |
840 | | |
841 | | template <class T> |
842 | | inline std::vector<T> readTagAsVector(const ReadContext &rc, |
843 | | const TagEntry &tag, bool &ok); |
844 | | |
845 | | template <> |
846 | | inline std::vector<int8_t> readTagAsVector(const ReadContext &rc, |
847 | | const TagEntry &tag, bool &ok) |
848 | 0 | { |
849 | 0 | return readTagAsVectorInternal(rc, tag, TagType::SByte, |
850 | 0 | tag.int8Values.data(), ok); |
851 | 0 | } |
852 | | |
853 | | template <> |
854 | | inline std::vector<uint8_t> readTagAsVector(const ReadContext &rc, |
855 | | const TagEntry &tag, bool &ok) |
856 | 9 | { |
857 | 9 | return readTagAsVectorInternal( |
858 | 9 | rc, tag, tag.type == TagType::Undefined ? tag.type : TagType::Byte, |
859 | 9 | tag.uint8Values.data(), ok); |
860 | 9 | } |
861 | | |
862 | | template <> |
863 | | inline std::vector<int16_t> readTagAsVector(const ReadContext &rc, |
864 | | const TagEntry &tag, bool &ok) |
865 | 0 | { |
866 | 0 | return readTagAsVectorInternal(rc, tag, TagType::SShort, |
867 | 0 | tag.int16Values.data(), ok); |
868 | 0 | } |
869 | | |
870 | | template <> |
871 | | inline std::vector<uint16_t> readTagAsVector(const ReadContext &rc, |
872 | | const TagEntry &tag, bool &ok) |
873 | 2.16k | { |
874 | 2.16k | return readTagAsVectorInternal(rc, tag, TagType::Short, |
875 | 2.16k | tag.uint16Values.data(), ok); |
876 | 2.16k | } |
877 | | |
878 | | template <> |
879 | | inline std::vector<int32_t> readTagAsVector(const ReadContext &rc, |
880 | | const TagEntry &tag, bool &ok) |
881 | 0 | { |
882 | 0 | return readTagAsVectorInternal(rc, tag, TagType::SLong, |
883 | 0 | tag.int32Values.data(), ok); |
884 | 0 | } |
885 | | |
886 | | template <> |
887 | | inline std::vector<uint32_t> readTagAsVector(const ReadContext &rc, |
888 | | const TagEntry &tag, bool &ok) |
889 | 752 | { |
890 | 752 | return readTagAsVectorInternal(rc, tag, TagType::Long, |
891 | 752 | tag.uint32Values.data(), ok); |
892 | 752 | } |
893 | | |
894 | | template <> |
895 | | inline std::vector<int64_t> readTagAsVector(const ReadContext &rc, |
896 | | const TagEntry &tag, bool &ok) |
897 | 0 | { |
898 | 0 | return readTagAsVectorInternal(rc, tag, TagType::SLong8, |
899 | 0 | tag.int64Values.data(), ok); |
900 | 0 | } |
901 | | |
902 | | template <> |
903 | | inline std::vector<uint64_t> readTagAsVector(const ReadContext &rc, |
904 | | const TagEntry &tag, bool &ok) |
905 | 50 | { |
906 | 50 | return readTagAsVectorInternal(rc, tag, TagType::Long8, |
907 | 50 | tag.uint64Values.data(), ok); |
908 | 50 | } |
909 | | |
910 | | template <> |
911 | | inline std::vector<float> readTagAsVector(const ReadContext &rc, |
912 | | const TagEntry &tag, bool &ok) |
913 | 0 | { |
914 | 0 | return readTagAsVectorInternal(rc, tag, TagType::Float, |
915 | 0 | tag.float32Values.data(), ok); |
916 | 0 | } |
917 | | |
918 | | template <> |
919 | | inline std::vector<double> readTagAsVector(const ReadContext &rc, |
920 | | const TagEntry &tag, bool &ok) |
921 | 2.31k | { |
922 | 2.31k | return readTagAsVectorInternal(rc, tag, TagType::Double, |
923 | 2.31k | tag.float64Values.data(), ok); |
924 | 2.31k | } |
925 | | |
926 | | } // namespace detail |
927 | | |
928 | | /** Represents a TIFF Image File Directory (IFD). */ |
929 | | class Image |
930 | | { |
931 | | public: |
932 | | /** Constructor. Should not be called directly. Use the open() method */ |
933 | | Image(const std::shared_ptr<const ReadContext> &rc, bool isBigTIFF) |
934 | 29.8k | : m_rc(rc), m_isBigTIFF(isBigTIFF) |
935 | 29.8k | { |
936 | 29.8k | } |
937 | | |
938 | | /** Return read context */ |
939 | | const std::shared_ptr<const ReadContext> &readContext() const |
940 | 91.8k | { |
941 | 91.8k | return m_rc; |
942 | 91.8k | } |
943 | | |
944 | | /** Return whether the file is BigTIFF (if false, classic TIFF) */ |
945 | | inline bool isBigTIFF() const |
946 | 0 | { |
947 | 0 | return m_isBigTIFF; |
948 | 0 | } |
949 | | |
950 | | /** Return if values of more than 1-byte must be byte swapped. |
951 | | * To be only taken into account when reading pixels. Tag values are |
952 | | * automatically byte-swapped */ |
953 | | inline bool mustByteSwap() const |
954 | 0 | { |
955 | 0 | return m_rc->mustByteSwap(); |
956 | 0 | } |
957 | | |
958 | | /** Return the offset of the this IFD */ |
959 | | inline uint64_t offset() const |
960 | 0 | { |
961 | 0 | return m_offset; |
962 | 0 | } |
963 | | |
964 | | /** Return the offset of the next IFD (to pass to Image::open()), |
965 | | * or 0 if there is no more */ |
966 | | inline uint64_t nextImageOffset() const |
967 | 47 | { |
968 | 47 | return m_nextImageOffset; |
969 | 47 | } |
970 | | |
971 | | /** Return value of SubFileType tag */ |
972 | | inline uint32_t subFileType() const |
973 | 34.2k | { |
974 | 34.2k | return m_subFileType; |
975 | 34.2k | } |
976 | | |
977 | | /** Return width of the image in pixels */ |
978 | | inline uint32_t width() const |
979 | 50.4k | { |
980 | 50.4k | return m_width; |
981 | 50.4k | } |
982 | | |
983 | | /** Return height of the image in pixels */ |
984 | | inline uint32_t height() const |
985 | 115k | { |
986 | 115k | return m_height; |
987 | 115k | } |
988 | | |
989 | | /** Return number of bits per sample */ |
990 | | inline uint32_t bitsPerSample() const |
991 | 24.8M | { |
992 | 24.8M | return m_bitsPerSample; |
993 | 24.8M | } |
994 | | |
995 | | /** Return number of samples (a.k.a. channels, bands) per pixel */ |
996 | | inline uint32_t samplesPerPixel() const |
997 | 187k | { |
998 | 187k | return m_samplesPerPixel; |
999 | 187k | } |
1000 | | |
1001 | | /** Return planar configuration */ |
1002 | | inline PlanarConfigurationType planarConfiguration() const |
1003 | 263k | { |
1004 | 263k | return m_planarConfiguration; |
1005 | 263k | } |
1006 | | |
1007 | | /** Return planar configuration */ |
1008 | | inline PhotometricInterpretationType photometricInterpretation() const |
1009 | 14.3M | { |
1010 | 14.3M | return m_photometricInterpretation; |
1011 | 14.3M | } |
1012 | | |
1013 | | /** Return compression method used */ |
1014 | | inline CompressionType compression() const |
1015 | 365k | { |
1016 | 365k | return m_compression; |
1017 | 365k | } |
1018 | | |
1019 | | /** Return predictor value (used for Deflate, LZW, ZStd, etc. compression) */ |
1020 | | inline uint32_t predictor() const |
1021 | 65.7k | { |
1022 | 65.7k | return m_predictor; |
1023 | 65.7k | } |
1024 | | |
1025 | | /** Return sample format */ |
1026 | | inline SampleFormatType sampleFormat() const |
1027 | 18.4k | { |
1028 | 18.4k | return m_sampleFormat; |
1029 | 18.4k | } |
1030 | | |
1031 | | /** Return the number of rows per strip */ |
1032 | | inline uint32_t rowsPerStrip() const |
1033 | 0 | { |
1034 | 0 | return m_rowsPerStrip; |
1035 | 0 | } |
1036 | | |
1037 | | /** Return the sanitized number of rows per strip */ |
1038 | | inline uint32_t rowsPerStripSanitized() const |
1039 | 95.9k | { |
1040 | 95.9k | return std::min(m_rowsPerStrip, m_height); |
1041 | 95.9k | } |
1042 | | |
1043 | | /** Return the number of strips/tiles. |
1044 | | * Return 0 if inconsistent values between ByteCounts and Offsets arrays. */ |
1045 | | inline uint64_t strileCount() const |
1046 | 0 | { |
1047 | 0 | return m_strileCount; |
1048 | 0 | } |
1049 | | |
1050 | | /** Return whether image is tiled */ |
1051 | | inline bool isTiled() const |
1052 | 300k | { |
1053 | 300k | return m_isTiled; |
1054 | 300k | } |
1055 | | |
1056 | | /** Return tile width */ |
1057 | | inline uint32_t tileWidth() const |
1058 | 2.88k | { |
1059 | 2.88k | return m_tileWidth; |
1060 | 2.88k | } |
1061 | | |
1062 | | /** Return tile width */ |
1063 | | inline uint32_t tileHeight() const |
1064 | 2.84k | { |
1065 | 2.84k | return m_tileHeight; |
1066 | 2.84k | } |
1067 | | |
1068 | | /** Return number of tiles per row */ |
1069 | | uint32_t tilesPerRow() const |
1070 | 19.6k | { |
1071 | 19.6k | if (m_tileWidth > 0) |
1072 | 19.6k | { |
1073 | 19.6k | return uint32_t((uint64_t(m_width) + m_tileWidth - 1) / |
1074 | 19.6k | m_tileWidth); |
1075 | 19.6k | } |
1076 | 0 | return 0; |
1077 | 19.6k | } |
1078 | | |
1079 | | /** Return number of tiles per column */ |
1080 | | uint32_t tilesPerCol() const |
1081 | 19.6k | { |
1082 | 19.6k | if (m_tileHeight > 0) |
1083 | 19.6k | { |
1084 | 19.6k | return uint32_t((uint64_t(m_height) + m_tileHeight - 1) / |
1085 | 19.6k | m_tileHeight); |
1086 | 19.6k | } |
1087 | 0 | return 0; |
1088 | 19.6k | } |
1089 | | |
1090 | | /** Convert a tile coordinate (xtile, ytile, bandIdx) to a flat index */ |
1091 | | uint64_t tileCoordinateToIdx(uint32_t xtile, uint32_t ytile, |
1092 | | uint32_t bandIdx, bool &ok) const |
1093 | 19.6k | { |
1094 | 19.6k | if (m_isTiled && m_tileWidth > 0 && m_tileHeight > 0) |
1095 | 19.6k | { |
1096 | 19.6k | const uint32_t lTilesPerRow = tilesPerRow(); |
1097 | 19.6k | const uint32_t lTilesPerCol = tilesPerCol(); |
1098 | 19.6k | if (xtile >= lTilesPerRow || ytile >= lTilesPerCol) |
1099 | 0 | { |
1100 | 0 | ok = false; |
1101 | 0 | return 0; |
1102 | 0 | } |
1103 | 19.6k | uint64_t idx = uint64_t(ytile) * lTilesPerRow + xtile; |
1104 | 19.6k | if (bandIdx && |
1105 | 4.83k | m_planarConfiguration == PlanarConfiguration::Separate) |
1106 | 4.83k | { |
1107 | 4.83k | const uint64_t lTotalTiles = |
1108 | 4.83k | uint64_t(lTilesPerCol) * lTilesPerRow; |
1109 | 4.83k | if (lTotalTiles > |
1110 | 4.83k | std::numeric_limits<uint64_t>::max() / bandIdx) |
1111 | 4.11k | { |
1112 | 4.11k | ok = false; |
1113 | 4.11k | return 0; |
1114 | 4.11k | } |
1115 | 721 | idx += bandIdx * lTotalTiles; |
1116 | 721 | } |
1117 | 15.5k | return idx; |
1118 | 19.6k | } |
1119 | 0 | ok = false; |
1120 | 0 | return 0; |
1121 | 19.6k | } |
1122 | | |
1123 | | /** Return the offset of strip/tile of index idx */ |
1124 | | uint64_t strileOffset(uint64_t idx, bool &ok) const |
1125 | 119k | { |
1126 | 119k | return readUIntTag(m_strileOffsetsTag, idx, ok); |
1127 | 119k | } |
1128 | | |
1129 | | /** Return the offset of a tile from its coordinates */ |
1130 | | uint64_t tileOffset(uint32_t xtile, uint32_t ytile, uint32_t bandIdx, |
1131 | | bool &ok) const |
1132 | 0 | { |
1133 | 0 | const auto idx = tileCoordinateToIdx(xtile, ytile, bandIdx, ok); |
1134 | 0 | return ok ? strileOffset(idx, ok) : 0; |
1135 | 0 | } |
1136 | | |
1137 | | /** Return the byte count of strip/tile of index idx */ |
1138 | | uint64_t strileByteCount(uint64_t idx, bool &ok) const |
1139 | 94.2k | { |
1140 | 94.2k | return readUIntTag(m_strileByteCountsTag, idx, ok); |
1141 | 94.2k | } |
1142 | | |
1143 | | /** Return the offset of a tile from its coordinates */ |
1144 | | uint64_t tileByteCount(uint32_t xtile, uint32_t ytile, uint32_t bandIdx, |
1145 | | bool &ok) const |
1146 | 0 | { |
1147 | 0 | const auto idx = tileCoordinateToIdx(xtile, ytile, bandIdx, ok); |
1148 | 0 | return ok ? strileByteCount(idx, ok) : 0; |
1149 | 0 | } |
1150 | | |
1151 | | /** Return the list of tags */ |
1152 | | inline const std::vector<TagEntry> &tags() const |
1153 | 0 | { |
1154 | 0 | return m_tags; |
1155 | 0 | } |
1156 | | |
1157 | | /** Return the (first) tag corresponding to a code, or nullptr if not found */ |
1158 | | const TagEntry *tag(TagCodeType tagCode) const |
1159 | 207k | { |
1160 | 207k | for (const auto &tag : m_tags) |
1161 | 17.6M | { |
1162 | 17.6M | if (tag.tag == tagCode) |
1163 | 33.4k | return &tag; |
1164 | 17.6M | } |
1165 | 173k | return nullptr; |
1166 | 207k | } |
1167 | | |
1168 | | /** Read an ASCII tag as a string */ |
1169 | | std::string readTagAsString(const TagEntry &tag, bool &ok) const |
1170 | 4.63k | { |
1171 | 4.63k | if (tag.type == TagType::ASCII) |
1172 | 4.63k | { |
1173 | 4.63k | if (tag.value_offset) |
1174 | 4.20k | { |
1175 | | if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t)) |
1176 | | { |
1177 | | // "- 1" not strictly necessary, but pleases Coverity Scan |
1178 | | if (tag.count > std::numeric_limits<size_t>::max() - 1) |
1179 | | { |
1180 | | ok = false; |
1181 | | return std::string(); |
1182 | | } |
1183 | | } |
1184 | 4.20k | return readContext()->readString( |
1185 | 4.20k | tag.value_offset, static_cast<size_t>(tag.count), ok); |
1186 | 4.20k | } |
1187 | 432 | if (tag.count) |
1188 | 411 | { |
1189 | 411 | std::string res(tag.charValues.data(), |
1190 | 411 | static_cast<size_t>(tag.count)); |
1191 | 411 | if (res.back() == 0) |
1192 | 286 | res.pop_back(); |
1193 | 411 | return res; |
1194 | 411 | } |
1195 | 432 | } |
1196 | 21 | ok = false; |
1197 | 21 | return std::string(); |
1198 | 4.63k | } |
1199 | | |
1200 | | /** Read a numeric tag as a vector. You must use a type T which is |
1201 | | * consistent with the tag.type value. For example, if |
1202 | | * tag.type == libertiff::TagType::Short, T must be uint16_t. |
1203 | | * libertiff::TagType::Undefined must be read with T=uint8_t. |
1204 | | */ |
1205 | | template <class T> |
1206 | | std::vector<T> readTagAsVector(const TagEntry &tag, bool &ok) const |
1207 | 5.29k | { |
1208 | 5.29k | return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok); |
1209 | 5.29k | } std::__1::vector<unsigned short, std::__1::allocator<unsigned short> > GDAL_libertiff::Image::readTagAsVector<unsigned short>(GDAL_libertiff::TagEntry const&, bool&) const Line | Count | Source | 1207 | 2.16k | { | 1208 | 2.16k | return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok); | 1209 | 2.16k | } |
std::__1::vector<unsigned char, std::__1::allocator<unsigned char> > GDAL_libertiff::Image::readTagAsVector<unsigned char>(GDAL_libertiff::TagEntry const&, bool&) const Line | Count | Source | 1207 | 9 | { | 1208 | 9 | return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok); | 1209 | 9 | } |
std::__1::vector<unsigned int, std::__1::allocator<unsigned int> > GDAL_libertiff::Image::readTagAsVector<unsigned int>(GDAL_libertiff::TagEntry const&, bool&) const Line | Count | Source | 1207 | 752 | { | 1208 | 752 | return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok); | 1209 | 752 | } |
std::__1::vector<unsigned long, std::__1::allocator<unsigned long> > GDAL_libertiff::Image::readTagAsVector<unsigned long>(GDAL_libertiff::TagEntry const&, bool&) const Line | Count | Source | 1207 | 50 | { | 1208 | 50 | return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok); | 1209 | 50 | } |
std::__1::vector<double, std::__1::allocator<double> > GDAL_libertiff::Image::readTagAsVector<double>(GDAL_libertiff::TagEntry const&, bool&) const Line | Count | Source | 1207 | 2.31k | { | 1208 | 2.31k | return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok); | 1209 | 2.31k | } |
|
1210 | | |
1211 | | /** Returns a new Image instance for the IFD starting at offset imageOffset */ |
1212 | | template <bool isBigTIFF> |
1213 | | static std::unique_ptr<const Image> |
1214 | | open(const std::shared_ptr<const ReadContext> &rc, |
1215 | | const uint64_t imageOffset, |
1216 | | const std::set<uint64_t> &alreadyVisitedImageOffsets = |
1217 | | std::set<uint64_t>()) |
1218 | 34.5k | { |
1219 | | // To prevent infinite looping on corrupted files |
1220 | 34.5k | if (imageOffset == 0 || alreadyVisitedImageOffsets.find(imageOffset) != |
1221 | 29.9k | alreadyVisitedImageOffsets.end()) |
1222 | 4.63k | { |
1223 | 4.63k | return nullptr; |
1224 | 4.63k | } |
1225 | | |
1226 | 29.8k | auto image = LIBERTIFF_NS::make_unique<Image>(rc, isBigTIFF); |
1227 | | |
1228 | 29.8k | image->m_offset = imageOffset; |
1229 | 29.8k | image->m_alreadyVisitedImageOffsets = alreadyVisitedImageOffsets; |
1230 | 29.8k | image->m_alreadyVisitedImageOffsets.insert(imageOffset); |
1231 | | |
1232 | 29.8k | bool ok = true; |
1233 | 29.8k | int tagCount = 0; |
1234 | 29.8k | uint64_t offset = imageOffset; |
1235 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) |
1236 | 2.29k | { |
1237 | | // To prevent unsigned integer overflows in later additions. The |
1238 | | // theoretical max should be much closer to UINT64_MAX, but half of |
1239 | | // it is already more than needed in practice :-) |
1240 | 2.29k | if (offset >= std::numeric_limits<uint64_t>::max() / 2) |
1241 | 228 | return nullptr; |
1242 | | |
1243 | 2.06k | const auto tagCount64Bit = rc->read<uint64_t>(offset, ok); |
1244 | | // Artificially limit to the same number of entries as ClassicTIFF |
1245 | 2.06k | if (tagCount64Bit > std::numeric_limits<uint16_t>::max()) |
1246 | 72 | return nullptr; |
1247 | 1.99k | tagCount = static_cast<int>(tagCount64Bit); |
1248 | 1.99k | offset += sizeof(uint64_t); |
1249 | | } |
1250 | | else |
1251 | 27.6k | { |
1252 | 27.6k | tagCount = rc->read<uint16_t>(offset, ok); |
1253 | 27.6k | offset += sizeof(uint16_t); |
1254 | 27.6k | } |
1255 | 29.8k | if (!ok) |
1256 | 7.19k | return nullptr; |
1257 | 22.7k | image->m_tags.reserve(tagCount); |
1258 | 22.7k | assert(tagCount <= 65535); |
1259 | 8.36M | for (int i = 0; i < tagCount; ++i) |
1260 | 8.35M | { |
1261 | 8.35M | TagEntry entry; |
1262 | | |
1263 | | // Read tag code |
1264 | 8.35M | entry.tag = rc->read<uint16_t>(offset, ok); |
1265 | 8.35M | offset += sizeof(uint16_t); |
1266 | | |
1267 | | // Read tag data type |
1268 | 8.35M | entry.type = rc->read<uint16_t>(offset, ok); |
1269 | 8.35M | offset += sizeof(uint16_t); |
1270 | | |
1271 | | // Read number of values |
1272 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) |
1273 | 104k | { |
1274 | 104k | auto count = rc->read<uint64_t>(offset, ok); |
1275 | 104k | entry.count = count; |
1276 | 104k | offset += sizeof(count); |
1277 | | } |
1278 | | else |
1279 | 8.24M | { |
1280 | 8.24M | auto count = rc->read<uint32_t>(offset, ok); |
1281 | 8.24M | entry.count = count; |
1282 | 8.24M | offset += sizeof(count); |
1283 | 8.24M | } |
1284 | | |
1285 | 8.35M | uint32_t singleValue = 0; |
1286 | 8.35M | bool singleValueFitsInUInt32 = false; |
1287 | 8.35M | if (entry.count) |
1288 | 7.26M | { |
1289 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) |
1290 | 99.9k | { |
1291 | 99.9k | image->ParseTagEntryDataOrOffset<uint64_t>( |
1292 | 99.9k | entry, offset, singleValueFitsInUInt32, singleValue, |
1293 | 99.9k | ok); |
1294 | | } |
1295 | | else |
1296 | 7.16M | { |
1297 | 7.16M | image->ParseTagEntryDataOrOffset<uint32_t>( |
1298 | 7.16M | entry, offset, singleValueFitsInUInt32, singleValue, |
1299 | 7.16M | ok); |
1300 | 7.16M | } |
1301 | 7.26M | } |
1302 | 8.35M | if (!ok) |
1303 | 5.39k | return nullptr; |
1304 | | |
1305 | 8.34M | image->processTag(entry, singleValueFitsInUInt32, singleValue); |
1306 | | |
1307 | 8.34M | image->m_tags.push_back(entry); |
1308 | 8.34M | } |
1309 | | |
1310 | 17.0k | image->finalTagProcessing(); |
1311 | | |
1312 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) |
1313 | 843 | image->m_nextImageOffset = rc->read<uint64_t>(offset, ok); |
1314 | | else |
1315 | 16.1k | image->m_nextImageOffset = rc->read<uint32_t>(offset, ok); |
1316 | | |
1317 | 17.0k | image->m_openFunc = open<isBigTIFF>; |
1318 | | |
1319 | 17.0k | return std::unique_ptr<const Image>(image.release()); |
1320 | 22.4k | } std::__1::unique_ptr<GDAL_libertiff::Image const, std::__1::default_delete<GDAL_libertiff::Image const> > GDAL_libertiff::Image::open<false>(std::__1::shared_ptr<GDAL_libertiff::ReadContext const> const&, unsigned long, std::__1::set<unsigned long, std::__1::less<unsigned long>, std::__1::allocator<unsigned long> > const&) Line | Count | Source | 1218 | 31.8k | { | 1219 | | // To prevent infinite looping on corrupted files | 1220 | 31.8k | if (imageOffset == 0 || alreadyVisitedImageOffsets.find(imageOffset) != | 1221 | 27.6k | alreadyVisitedImageOffsets.end()) | 1222 | 4.28k | { | 1223 | 4.28k | return nullptr; | 1224 | 4.28k | } | 1225 | | | 1226 | 27.6k | auto image = LIBERTIFF_NS::make_unique<Image>(rc, isBigTIFF); | 1227 | | | 1228 | 27.6k | image->m_offset = imageOffset; | 1229 | 27.6k | image->m_alreadyVisitedImageOffsets = alreadyVisitedImageOffsets; | 1230 | 27.6k | image->m_alreadyVisitedImageOffsets.insert(imageOffset); | 1231 | | | 1232 | 27.6k | bool ok = true; | 1233 | 27.6k | int tagCount = 0; | 1234 | 27.6k | uint64_t offset = imageOffset; | 1235 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1236 | | { | 1237 | | // To prevent unsigned integer overflows in later additions. The | 1238 | | // theoretical max should be much closer to UINT64_MAX, but half of | 1239 | | // it is already more than needed in practice :-) | 1240 | | if (offset >= std::numeric_limits<uint64_t>::max() / 2) | 1241 | | return nullptr; | 1242 | | | 1243 | | const auto tagCount64Bit = rc->read<uint64_t>(offset, ok); | 1244 | | // Artificially limit to the same number of entries as ClassicTIFF | 1245 | | if (tagCount64Bit > std::numeric_limits<uint16_t>::max()) | 1246 | | return nullptr; | 1247 | | tagCount = static_cast<int>(tagCount64Bit); | 1248 | | offset += sizeof(uint64_t); | 1249 | | } | 1250 | | else | 1251 | 27.6k | { | 1252 | 27.6k | tagCount = rc->read<uint16_t>(offset, ok); | 1253 | 27.6k | offset += sizeof(uint16_t); | 1254 | 27.6k | } | 1255 | 27.6k | if (!ok) | 1256 | 6.87k | return nullptr; | 1257 | 20.7k | image->m_tags.reserve(tagCount); | 1258 | 20.7k | assert(tagCount <= 65535); | 1259 | 8.26M | for (int i = 0; i < tagCount; ++i) | 1260 | 8.24M | { | 1261 | 8.24M | TagEntry entry; | 1262 | | | 1263 | | // Read tag code | 1264 | 8.24M | entry.tag = rc->read<uint16_t>(offset, ok); | 1265 | 8.24M | offset += sizeof(uint16_t); | 1266 | | | 1267 | | // Read tag data type | 1268 | 8.24M | entry.type = rc->read<uint16_t>(offset, ok); | 1269 | 8.24M | offset += sizeof(uint16_t); | 1270 | | | 1271 | | // Read number of values | 1272 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1273 | | { | 1274 | | auto count = rc->read<uint64_t>(offset, ok); | 1275 | | entry.count = count; | 1276 | | offset += sizeof(count); | 1277 | | } | 1278 | | else | 1279 | 8.24M | { | 1280 | 8.24M | auto count = rc->read<uint32_t>(offset, ok); | 1281 | 8.24M | entry.count = count; | 1282 | 8.24M | offset += sizeof(count); | 1283 | 8.24M | } | 1284 | | | 1285 | 8.24M | uint32_t singleValue = 0; | 1286 | 8.24M | bool singleValueFitsInUInt32 = false; | 1287 | 8.24M | if (entry.count) | 1288 | 7.16M | { | 1289 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1290 | | { | 1291 | | image->ParseTagEntryDataOrOffset<uint64_t>( | 1292 | | entry, offset, singleValueFitsInUInt32, singleValue, | 1293 | | ok); | 1294 | | } | 1295 | | else | 1296 | 7.16M | { | 1297 | 7.16M | image->ParseTagEntryDataOrOffset<uint32_t>( | 1298 | 7.16M | entry, offset, singleValueFitsInUInt32, singleValue, | 1299 | 7.16M | ok); | 1300 | 7.16M | } | 1301 | 7.16M | } | 1302 | 8.24M | if (!ok) | 1303 | 4.55k | return nullptr; | 1304 | | | 1305 | 8.24M | image->processTag(entry, singleValueFitsInUInt32, singleValue); | 1306 | | | 1307 | 8.24M | image->m_tags.push_back(entry); | 1308 | 8.24M | } | 1309 | | | 1310 | 16.1k | image->finalTagProcessing(); | 1311 | | | 1312 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1313 | | image->m_nextImageOffset = rc->read<uint64_t>(offset, ok); | 1314 | | else | 1315 | 16.1k | image->m_nextImageOffset = rc->read<uint32_t>(offset, ok); | 1316 | | | 1317 | 16.1k | image->m_openFunc = open<isBigTIFF>; | 1318 | | | 1319 | 16.1k | return std::unique_ptr<const Image>(image.release()); | 1320 | 20.7k | } |
std::__1::unique_ptr<GDAL_libertiff::Image const, std::__1::default_delete<GDAL_libertiff::Image const> > GDAL_libertiff::Image::open<true>(std::__1::shared_ptr<GDAL_libertiff::ReadContext const> const&, unsigned long, std::__1::set<unsigned long, std::__1::less<unsigned long>, std::__1::allocator<unsigned long> > const&) Line | Count | Source | 1218 | 2.65k | { | 1219 | | // To prevent infinite looping on corrupted files | 1220 | 2.65k | if (imageOffset == 0 || alreadyVisitedImageOffsets.find(imageOffset) != | 1221 | 2.29k | alreadyVisitedImageOffsets.end()) | 1222 | 355 | { | 1223 | 355 | return nullptr; | 1224 | 355 | } | 1225 | | | 1226 | 2.29k | auto image = LIBERTIFF_NS::make_unique<Image>(rc, isBigTIFF); | 1227 | | | 1228 | 2.29k | image->m_offset = imageOffset; | 1229 | 2.29k | image->m_alreadyVisitedImageOffsets = alreadyVisitedImageOffsets; | 1230 | 2.29k | image->m_alreadyVisitedImageOffsets.insert(imageOffset); | 1231 | | | 1232 | 2.29k | bool ok = true; | 1233 | 2.29k | int tagCount = 0; | 1234 | 2.29k | uint64_t offset = imageOffset; | 1235 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1236 | 2.29k | { | 1237 | | // To prevent unsigned integer overflows in later additions. The | 1238 | | // theoretical max should be much closer to UINT64_MAX, but half of | 1239 | | // it is already more than needed in practice :-) | 1240 | 2.29k | if (offset >= std::numeric_limits<uint64_t>::max() / 2) | 1241 | 228 | return nullptr; | 1242 | | | 1243 | 2.06k | const auto tagCount64Bit = rc->read<uint64_t>(offset, ok); | 1244 | | // Artificially limit to the same number of entries as ClassicTIFF | 1245 | 2.06k | if (tagCount64Bit > std::numeric_limits<uint16_t>::max()) | 1246 | 72 | return nullptr; | 1247 | 1.99k | tagCount = static_cast<int>(tagCount64Bit); | 1248 | 1.99k | offset += sizeof(uint64_t); | 1249 | | } | 1250 | | else | 1251 | | { | 1252 | | tagCount = rc->read<uint16_t>(offset, ok); | 1253 | | offset += sizeof(uint16_t); | 1254 | | } | 1255 | 2.29k | if (!ok) | 1256 | 312 | return nullptr; | 1257 | 1.98k | image->m_tags.reserve(tagCount); | 1258 | 1.98k | assert(tagCount <= 65535); | 1259 | 105k | for (int i = 0; i < tagCount; ++i) | 1260 | 104k | { | 1261 | 104k | TagEntry entry; | 1262 | | | 1263 | | // Read tag code | 1264 | 104k | entry.tag = rc->read<uint16_t>(offset, ok); | 1265 | 104k | offset += sizeof(uint16_t); | 1266 | | | 1267 | | // Read tag data type | 1268 | 104k | entry.type = rc->read<uint16_t>(offset, ok); | 1269 | 104k | offset += sizeof(uint16_t); | 1270 | | | 1271 | | // Read number of values | 1272 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1273 | 104k | { | 1274 | 104k | auto count = rc->read<uint64_t>(offset, ok); | 1275 | 104k | entry.count = count; | 1276 | 104k | offset += sizeof(count); | 1277 | | } | 1278 | | else | 1279 | | { | 1280 | | auto count = rc->read<uint32_t>(offset, ok); | 1281 | | entry.count = count; | 1282 | | offset += sizeof(count); | 1283 | | } | 1284 | | | 1285 | 104k | uint32_t singleValue = 0; | 1286 | 104k | bool singleValueFitsInUInt32 = false; | 1287 | 104k | if (entry.count) | 1288 | 99.9k | { | 1289 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1290 | 99.9k | { | 1291 | 99.9k | image->ParseTagEntryDataOrOffset<uint64_t>( | 1292 | 99.9k | entry, offset, singleValueFitsInUInt32, singleValue, | 1293 | 99.9k | ok); | 1294 | | } | 1295 | | else | 1296 | | { | 1297 | | image->ParseTagEntryDataOrOffset<uint32_t>( | 1298 | | entry, offset, singleValueFitsInUInt32, singleValue, | 1299 | | ok); | 1300 | | } | 1301 | 99.9k | } | 1302 | 104k | if (!ok) | 1303 | 842 | return nullptr; | 1304 | | | 1305 | 103k | image->processTag(entry, singleValueFitsInUInt32, singleValue); | 1306 | | | 1307 | 103k | image->m_tags.push_back(entry); | 1308 | 103k | } | 1309 | | | 1310 | 843 | image->finalTagProcessing(); | 1311 | | | 1312 | | if LIBERTIFF_CONSTEXPR (isBigTIFF) | 1313 | 843 | image->m_nextImageOffset = rc->read<uint64_t>(offset, ok); | 1314 | | else | 1315 | | image->m_nextImageOffset = rc->read<uint32_t>(offset, ok); | 1316 | | | 1317 | 843 | image->m_openFunc = open<isBigTIFF>; | 1318 | | | 1319 | 843 | return std::unique_ptr<const Image>(image.release()); | 1320 | 1.68k | } |
|
1321 | | |
1322 | | /** Returns a new Image instance at the next IFD, or nullptr if there is none */ |
1323 | | std::unique_ptr<const Image> next() const |
1324 | 13.9k | { |
1325 | 13.9k | return m_openFunc(m_rc, m_nextImageOffset, |
1326 | 13.9k | m_alreadyVisitedImageOffsets); |
1327 | 13.9k | } |
1328 | | |
1329 | | private: |
1330 | | const std::shared_ptr<const ReadContext> m_rc; |
1331 | | std::unique_ptr<const Image> (*m_openFunc)( |
1332 | | const std::shared_ptr<const ReadContext> &, const uint64_t, |
1333 | | const std::set<uint64_t> &) = nullptr; |
1334 | | |
1335 | | std::set<uint64_t> m_alreadyVisitedImageOffsets{}; |
1336 | | uint64_t m_offset = 0; |
1337 | | uint64_t m_nextImageOffset = 0; |
1338 | | uint32_t m_subFileType = 0; |
1339 | | uint32_t m_width = 0; |
1340 | | uint32_t m_height = 0; |
1341 | | uint32_t m_bitsPerSample = 0; |
1342 | | uint32_t m_samplesPerPixel = 0; |
1343 | | uint32_t m_rowsPerStrip = 0; |
1344 | | CompressionType m_compression = Compression::None; |
1345 | | SampleFormatType m_sampleFormat = SampleFormat::UnsignedInt; |
1346 | | PlanarConfigurationType m_planarConfiguration = |
1347 | | PlanarConfiguration::Contiguous; |
1348 | | PhotometricInterpretationType m_photometricInterpretation = |
1349 | | PhotometricInterpretation::MinIsBlack; |
1350 | | uint32_t m_predictor = 0; |
1351 | | |
1352 | | const bool m_isBigTIFF; |
1353 | | bool m_isTiled = false; |
1354 | | uint32_t m_tileWidth = 0; |
1355 | | uint32_t m_tileHeight = 0; |
1356 | | uint64_t m_strileCount = 0; |
1357 | | |
1358 | | std::vector<TagEntry> m_tags{}; |
1359 | | const TagEntry *m_strileOffsetsTag = nullptr; |
1360 | | const TagEntry *m_strileByteCountsTag = nullptr; |
1361 | | |
1362 | | Image(const Image &) = delete; |
1363 | | Image &operator=(const Image &) = delete; |
1364 | | |
1365 | | /** Process tag */ |
1366 | | void processTag(const TagEntry &entry, bool singleValueFitsInUInt32, |
1367 | | uint32_t singleValue) |
1368 | 8.34M | { |
1369 | 8.34M | if (singleValueFitsInUInt32) |
1370 | 185k | { |
1371 | 185k | switch (entry.tag) |
1372 | 185k | { |
1373 | 2.53k | case TagCode::SubFileType: |
1374 | 2.53k | m_subFileType = singleValue; |
1375 | 2.53k | break; |
1376 | | |
1377 | 24.5k | case TagCode::ImageWidth: |
1378 | 24.5k | m_width = singleValue; |
1379 | 24.5k | break; |
1380 | | |
1381 | 25.1k | case TagCode::ImageLength: |
1382 | 25.1k | m_height = singleValue; |
1383 | 25.1k | break; |
1384 | | |
1385 | 13.5k | case TagCode::Compression: |
1386 | 13.5k | m_compression = singleValue; |
1387 | 13.5k | break; |
1388 | | |
1389 | 22.7k | case TagCode::SamplesPerPixel: |
1390 | 22.7k | m_samplesPerPixel = singleValue; |
1391 | 22.7k | break; |
1392 | | |
1393 | 23.4k | case TagCode::RowsPerStrip: |
1394 | 23.4k | m_rowsPerStrip = singleValue; |
1395 | 23.4k | break; |
1396 | | |
1397 | 8.66k | case TagCode::PlanarConfiguration: |
1398 | 8.66k | m_planarConfiguration = singleValue; |
1399 | 8.66k | break; |
1400 | | |
1401 | 7.34k | case TagCode::PhotometricInterpretation: |
1402 | 7.34k | m_photometricInterpretation = singleValue; |
1403 | 7.34k | break; |
1404 | | |
1405 | 1.77k | case TagCode::Predictor: |
1406 | 1.77k | m_predictor = singleValue; |
1407 | 1.77k | break; |
1408 | | |
1409 | 2.99k | case TagCode::TileWidth: |
1410 | 2.99k | m_tileWidth = singleValue; |
1411 | 2.99k | break; |
1412 | | |
1413 | 1.68k | case TagCode::TileLength: |
1414 | 1.68k | m_tileHeight = singleValue; |
1415 | 1.68k | break; |
1416 | | |
1417 | 51.4k | default: |
1418 | 51.4k | break; |
1419 | 185k | } |
1420 | 185k | } |
1421 | | |
1422 | 8.34M | if (entry.count && |
1423 | 7.26M | (entry.type == TagType::Byte || entry.type == TagType::Short || |
1424 | 6.94M | entry.type == TagType::Long)) |
1425 | 362k | { |
1426 | | // Values of those 2 tags are repeated per sample, but should be |
1427 | | // at the same value. |
1428 | 362k | if (entry.tag == TagCode::SampleFormat) |
1429 | 8.53k | { |
1430 | 8.53k | bool localOk = true; |
1431 | 8.53k | const auto sampleFormat = |
1432 | 8.53k | static_cast<uint32_t>(readUIntTag(&entry, 0, localOk)); |
1433 | 8.53k | if (localOk) |
1434 | 6.94k | { |
1435 | 6.94k | m_sampleFormat = sampleFormat; |
1436 | 6.94k | } |
1437 | 8.53k | } |
1438 | 353k | else if (entry.tag == TagCode::BitsPerSample) |
1439 | 23.5k | { |
1440 | 23.5k | bool localOk = true; |
1441 | 23.5k | const auto bitsPerSample = |
1442 | 23.5k | static_cast<uint32_t>(readUIntTag(&entry, 0, localOk)); |
1443 | 23.5k | if (localOk) |
1444 | 21.4k | { |
1445 | 21.4k | m_bitsPerSample = bitsPerSample; |
1446 | 21.4k | } |
1447 | 23.5k | } |
1448 | 362k | } |
1449 | 8.34M | } |
1450 | | |
1451 | | /** Final tag processing */ |
1452 | | void finalTagProcessing() |
1453 | 17.0k | { |
1454 | 17.0k | m_strileOffsetsTag = tag(TagCode::TileOffsets); |
1455 | 17.0k | if (m_strileOffsetsTag) |
1456 | 2.14k | { |
1457 | 2.14k | m_strileByteCountsTag = tag(TagCode::TileByteCounts); |
1458 | 2.14k | if (m_strileByteCountsTag && |
1459 | 1.89k | m_strileOffsetsTag->count == m_strileByteCountsTag->count) |
1460 | 868 | { |
1461 | 868 | m_isTiled = true; |
1462 | 868 | m_strileCount = m_strileOffsetsTag->count; |
1463 | 868 | } |
1464 | 2.14k | } |
1465 | 14.8k | else |
1466 | 14.8k | { |
1467 | 14.8k | m_strileOffsetsTag = tag(TagCode::StripOffsets); |
1468 | 14.8k | if (m_strileOffsetsTag) |
1469 | 7.83k | { |
1470 | 7.83k | m_strileByteCountsTag = tag(TagCode::StripByteCounts); |
1471 | 7.83k | if (m_strileByteCountsTag && |
1472 | 6.28k | m_strileOffsetsTag->count == m_strileByteCountsTag->count) |
1473 | 3.09k | { |
1474 | 3.09k | m_strileCount = m_strileOffsetsTag->count; |
1475 | 3.09k | } |
1476 | 7.83k | } |
1477 | 14.8k | } |
1478 | 17.0k | } |
1479 | | |
1480 | | /** Read a value from a byte/short/long/long8 array tag */ |
1481 | | uint64_t readUIntTag(const TagEntry *tag, uint64_t idx, bool &ok) const |
1482 | 245k | { |
1483 | 245k | if (tag && idx < tag->count) |
1484 | 233k | { |
1485 | 233k | if (tag->type == TagType::Byte) |
1486 | 149k | { |
1487 | 149k | if (tag->count <= (m_isBigTIFF ? 8 : 4)) |
1488 | 5.97k | { |
1489 | 5.97k | return tag->uint8Values[size_t(idx)]; |
1490 | 5.97k | } |
1491 | 143k | return m_rc->read<uint8_t>( |
1492 | 143k | tag->value_offset + sizeof(uint8_t) * idx, ok); |
1493 | 149k | } |
1494 | 83.4k | else if (tag->type == TagType::Short) |
1495 | 42.5k | { |
1496 | 42.5k | if (tag->count <= (m_isBigTIFF ? 4 : 2)) |
1497 | 18.3k | { |
1498 | 18.3k | return tag->uint16Values[size_t(idx)]; |
1499 | 18.3k | } |
1500 | 24.2k | return m_rc->read<uint16_t>( |
1501 | 24.2k | tag->value_offset + sizeof(uint16_t) * idx, ok); |
1502 | 42.5k | } |
1503 | 40.8k | else if (tag->type == TagType::Long) |
1504 | 37.9k | { |
1505 | 37.9k | if (tag->count <= (m_isBigTIFF ? 2 : 1)) |
1506 | 17.4k | { |
1507 | 17.4k | return tag->uint32Values[size_t(idx)]; |
1508 | 17.4k | } |
1509 | 20.4k | return m_rc->read<uint32_t>( |
1510 | 20.4k | tag->value_offset + sizeof(uint32_t) * idx, ok); |
1511 | 37.9k | } |
1512 | 2.96k | else if (m_isBigTIFF && tag->type == TagType::Long8) |
1513 | 2.23k | { |
1514 | 2.23k | if (tag->count <= 1) |
1515 | 22 | { |
1516 | 22 | return tag->uint64Values[size_t(idx)]; |
1517 | 22 | } |
1518 | 2.21k | return m_rc->read<uint64_t>( |
1519 | 2.21k | tag->value_offset + sizeof(uint64_t) * idx, ok); |
1520 | 2.23k | } |
1521 | 233k | } |
1522 | 13.0k | ok = false; |
1523 | 13.0k | return 0; |
1524 | 245k | } |
1525 | | |
1526 | | template <class DataOrOffsetType> |
1527 | | void ParseTagEntryDataOrOffset(TagEntry &entry, uint64_t &offset, |
1528 | | bool &singleValueFitsInUInt32, |
1529 | | uint32_t &singleValue, bool &ok) |
1530 | 7.26M | { |
1531 | 7.26M | LIBERTIFF_STATIC_ASSERT( |
1532 | 7.26M | (std::is_same<DataOrOffsetType, uint32_t>::value || |
1533 | 7.26M | std::is_same<DataOrOffsetType, uint64_t>::value)); |
1534 | 7.26M | assert(entry.count > 0); |
1535 | | |
1536 | 7.26M | const uint32_t dataTypeSize = tagTypeSize(entry.type); |
1537 | 7.26M | if (dataTypeSize == 0) |
1538 | 6.78M | { |
1539 | 6.78M | return; |
1540 | 6.78M | } |
1541 | | |
1542 | | // There are 2 cases: |
1543 | | // - either the number of values for the data type can fit |
1544 | | // in the next DataOrOffsetType bytes |
1545 | | // - or it cannot, and then the next DataOrOffsetType bytes are an offset |
1546 | | // to the values |
1547 | 478k | if (dataTypeSize > sizeof(DataOrOffsetType) / entry.count) |
1548 | 280k | { |
1549 | | // Out-of-line values. We read a file offset |
1550 | 280k | entry.value_offset = m_rc->read<DataOrOffsetType>(offset, ok); |
1551 | 280k | if (entry.value_offset == 0) |
1552 | 3.19k | { |
1553 | | // value_offset = 0 for a out-of-line tag is obviously |
1554 | | // wrong and would cause later confusion in readTagAsVector<>, |
1555 | | // so better reject the file. |
1556 | 3.19k | ok = false; |
1557 | 3.19k | return; |
1558 | 3.19k | } |
1559 | 277k | if (dataTypeSize > |
1560 | 277k | std::numeric_limits<uint64_t>::max() / entry.count) |
1561 | 1.12k | { |
1562 | 1.12k | entry.invalid_value_offset = true; |
1563 | 1.12k | } |
1564 | 276k | else |
1565 | 276k | { |
1566 | 276k | const uint64_t byteCount = uint64_t(dataTypeSize) * entry.count; |
1567 | | |
1568 | | // Size of tag data beyond which we check the tag position and size |
1569 | | // w.r.t the file size. |
1570 | 276k | constexpr uint32_t THRESHOLD_CHECK_FILE_SIZE = 10 * 1000 * 1000; |
1571 | | |
1572 | 276k | entry.invalid_value_offset = |
1573 | 276k | (byteCount > THRESHOLD_CHECK_FILE_SIZE && |
1574 | 159k | (m_rc->size() < byteCount || |
1575 | 0 | entry.value_offset > m_rc->size() - byteCount)); |
1576 | 276k | } |
1577 | 277k | } |
1578 | 197k | else if (dataTypeSize == sizeof(uint8_t)) |
1579 | 30.1k | { |
1580 | | // Read up to 4 (classic) or 8 (BigTIFF) inline bytes |
1581 | 30.1k | m_rc->read(offset, size_t(entry.count), &entry.uint8Values[0], ok); |
1582 | 30.1k | if (entry.count == 1 && entry.type == TagType::Byte) |
1583 | 24.3k | { |
1584 | 24.3k | singleValueFitsInUInt32 = true; |
1585 | 24.3k | singleValue = entry.uint8Values[0]; |
1586 | 24.3k | } |
1587 | 30.1k | } |
1588 | 167k | else if (dataTypeSize == sizeof(uint16_t)) |
1589 | 138k | { |
1590 | | // Read up to 2 (classic) or 4 (BigTIFF) inline 16-bit values |
1591 | 138k | assert(entry.count <= 4); |
1592 | 278k | for (uint32_t idx = 0; idx < entry.count; ++idx) |
1593 | 140k | { |
1594 | 140k | entry.uint16Values[idx] = |
1595 | 140k | m_rc->read<uint16_t>(offset + idx * sizeof(uint16_t), ok); |
1596 | 140k | } |
1597 | 138k | if (entry.count == 1 && entry.type == TagType::Short) |
1598 | 135k | { |
1599 | 135k | singleValueFitsInUInt32 = true; |
1600 | 135k | singleValue = entry.uint16Values[0]; |
1601 | 135k | } |
1602 | 138k | } |
1603 | 29.2k | else if (dataTypeSize == sizeof(uint32_t)) |
1604 | 27.8k | { |
1605 | | // Read up to 1 (classic) or 2 (BigTIFF) inline 32-bit values |
1606 | 27.8k | entry.uint32Values[0] = m_rc->read<uint32_t>(offset, ok); |
1607 | 27.8k | if (entry.count == 1 && entry.type == TagType::Long) |
1608 | 25.9k | { |
1609 | 25.9k | singleValueFitsInUInt32 = true; |
1610 | 25.9k | singleValue = entry.uint32Values[0]; |
1611 | 25.9k | } |
1612 | | if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType, |
1613 | | uint64_t>::value) |
1614 | 1.16k | { |
1615 | 1.16k | if (entry.count == 2) |
1616 | 792 | { |
1617 | 792 | entry.uint32Values[1] = |
1618 | 792 | m_rc->read<uint32_t>(offset + sizeof(uint32_t), ok); |
1619 | 792 | } |
1620 | 1.16k | } |
1621 | 27.8k | } |
1622 | | else if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType, |
1623 | | uint64_t>::value) |
1624 | 1.38k | { |
1625 | 1.38k | if (dataTypeSize == sizeof(uint64_t)) |
1626 | 1.38k | { |
1627 | | // Read one inline 64-bit value |
1628 | 1.38k | if (entry.type == TagType::Rational) |
1629 | 649 | entry.float64Values[0] = m_rc->readRational(offset, ok); |
1630 | 734 | else if (entry.type == TagType::SRational) |
1631 | 479 | entry.float64Values[0] = |
1632 | 479 | m_rc->readSignedRational(offset, ok); |
1633 | 255 | else |
1634 | 255 | entry.uint64Values[0] = m_rc->read<uint64_t>(offset, ok); |
1635 | 1.38k | } |
1636 | 0 | else |
1637 | 0 | { |
1638 | 0 | assert(false); |
1639 | 0 | } |
1640 | | } |
1641 | | else |
1642 | 0 | { |
1643 | | // fprintf(stderr, "Unexpected case: tag=%u, dataType=%u, count=%u\n", entry.tag, entry.type, entry.count); |
1644 | 0 | assert(false); |
1645 | 0 | } |
1646 | | |
1647 | 475k | offset += sizeof(DataOrOffsetType); |
1648 | 475k | } void GDAL_libertiff::Image::ParseTagEntryDataOrOffset<unsigned int>(GDAL_libertiff::TagEntry&, unsigned long&, bool&, unsigned int&, bool&) Line | Count | Source | 1530 | 7.16M | { | 1531 | 7.16M | LIBERTIFF_STATIC_ASSERT( | 1532 | 7.16M | (std::is_same<DataOrOffsetType, uint32_t>::value || | 1533 | 7.16M | std::is_same<DataOrOffsetType, uint64_t>::value)); | 1534 | 7.16M | assert(entry.count > 0); | 1535 | | | 1536 | 7.16M | const uint32_t dataTypeSize = tagTypeSize(entry.type); | 1537 | 7.16M | if (dataTypeSize == 0) | 1538 | 6.70M | { | 1539 | 6.70M | return; | 1540 | 6.70M | } | 1541 | | | 1542 | | // There are 2 cases: | 1543 | | // - either the number of values for the data type can fit | 1544 | | // in the next DataOrOffsetType bytes | 1545 | | // - or it cannot, and then the next DataOrOffsetType bytes are an offset | 1546 | | // to the values | 1547 | 463k | if (dataTypeSize > sizeof(DataOrOffsetType) / entry.count) | 1548 | 273k | { | 1549 | | // Out-of-line values. We read a file offset | 1550 | 273k | entry.value_offset = m_rc->read<DataOrOffsetType>(offset, ok); | 1551 | 273k | if (entry.value_offset == 0) | 1552 | 3.11k | { | 1553 | | // value_offset = 0 for a out-of-line tag is obviously | 1554 | | // wrong and would cause later confusion in readTagAsVector<>, | 1555 | | // so better reject the file. | 1556 | 3.11k | ok = false; | 1557 | 3.11k | return; | 1558 | 3.11k | } | 1559 | 270k | if (dataTypeSize > | 1560 | 270k | std::numeric_limits<uint64_t>::max() / entry.count) | 1561 | 0 | { | 1562 | 0 | entry.invalid_value_offset = true; | 1563 | 0 | } | 1564 | 270k | else | 1565 | 270k | { | 1566 | 270k | const uint64_t byteCount = uint64_t(dataTypeSize) * entry.count; | 1567 | | | 1568 | | // Size of tag data beyond which we check the tag position and size | 1569 | | // w.r.t the file size. | 1570 | 270k | constexpr uint32_t THRESHOLD_CHECK_FILE_SIZE = 10 * 1000 * 1000; | 1571 | | | 1572 | 270k | entry.invalid_value_offset = | 1573 | 270k | (byteCount > THRESHOLD_CHECK_FILE_SIZE && | 1574 | 154k | (m_rc->size() < byteCount || | 1575 | 0 | entry.value_offset > m_rc->size() - byteCount)); | 1576 | 270k | } | 1577 | 270k | } | 1578 | 189k | else if (dataTypeSize == sizeof(uint8_t)) | 1579 | 29.3k | { | 1580 | | // Read up to 4 (classic) or 8 (BigTIFF) inline bytes | 1581 | 29.3k | m_rc->read(offset, size_t(entry.count), &entry.uint8Values[0], ok); | 1582 | 29.3k | if (entry.count == 1 && entry.type == TagType::Byte) | 1583 | 24.0k | { | 1584 | 24.0k | singleValueFitsInUInt32 = true; | 1585 | 24.0k | singleValue = entry.uint8Values[0]; | 1586 | 24.0k | } | 1587 | 29.3k | } | 1588 | 160k | else if (dataTypeSize == sizeof(uint16_t)) | 1589 | 133k | { | 1590 | | // Read up to 2 (classic) or 4 (BigTIFF) inline 16-bit values | 1591 | 133k | assert(entry.count <= 4); | 1592 | 268k | for (uint32_t idx = 0; idx < entry.count; ++idx) | 1593 | 135k | { | 1594 | 135k | entry.uint16Values[idx] = | 1595 | 135k | m_rc->read<uint16_t>(offset + idx * sizeof(uint16_t), ok); | 1596 | 135k | } | 1597 | 133k | if (entry.count == 1 && entry.type == TagType::Short) | 1598 | 131k | { | 1599 | 131k | singleValueFitsInUInt32 = true; | 1600 | 131k | singleValue = entry.uint16Values[0]; | 1601 | 131k | } | 1602 | 133k | } | 1603 | 26.7k | else if (dataTypeSize == sizeof(uint32_t)) | 1604 | 26.7k | { | 1605 | | // Read up to 1 (classic) or 2 (BigTIFF) inline 32-bit values | 1606 | 26.7k | entry.uint32Values[0] = m_rc->read<uint32_t>(offset, ok); | 1607 | 26.7k | if (entry.count == 1 && entry.type == TagType::Long) | 1608 | 25.8k | { | 1609 | 25.8k | singleValueFitsInUInt32 = true; | 1610 | 25.8k | singleValue = entry.uint32Values[0]; | 1611 | 25.8k | } | 1612 | | if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType, | 1613 | | uint64_t>::value) | 1614 | | { | 1615 | | if (entry.count == 2) | 1616 | | { | 1617 | | entry.uint32Values[1] = | 1618 | | m_rc->read<uint32_t>(offset + sizeof(uint32_t), ok); | 1619 | | } | 1620 | | } | 1621 | 26.7k | } | 1622 | | else if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType, | 1623 | | uint64_t>::value) | 1624 | | { | 1625 | | if (dataTypeSize == sizeof(uint64_t)) | 1626 | | { | 1627 | | // Read one inline 64-bit value | 1628 | | if (entry.type == TagType::Rational) | 1629 | | entry.float64Values[0] = m_rc->readRational(offset, ok); | 1630 | | else if (entry.type == TagType::SRational) | 1631 | | entry.float64Values[0] = | 1632 | | m_rc->readSignedRational(offset, ok); | 1633 | | else | 1634 | | entry.uint64Values[0] = m_rc->read<uint64_t>(offset, ok); | 1635 | | } | 1636 | | else | 1637 | | { | 1638 | | assert(false); | 1639 | | } | 1640 | | } | 1641 | | else | 1642 | 0 | { | 1643 | | // fprintf(stderr, "Unexpected case: tag=%u, dataType=%u, count=%u\n", entry.tag, entry.type, entry.count); | 1644 | 0 | assert(false); | 1645 | 0 | } | 1646 | | | 1647 | 460k | offset += sizeof(DataOrOffsetType); | 1648 | 460k | } |
void GDAL_libertiff::Image::ParseTagEntryDataOrOffset<unsigned long>(GDAL_libertiff::TagEntry&, unsigned long&, bool&, unsigned int&, bool&) Line | Count | Source | 1530 | 99.9k | { | 1531 | 99.9k | LIBERTIFF_STATIC_ASSERT( | 1532 | 99.9k | (std::is_same<DataOrOffsetType, uint32_t>::value || | 1533 | 99.9k | std::is_same<DataOrOffsetType, uint64_t>::value)); | 1534 | 99.9k | assert(entry.count > 0); | 1535 | | | 1536 | 99.9k | const uint32_t dataTypeSize = tagTypeSize(entry.type); | 1537 | 99.9k | if (dataTypeSize == 0) | 1538 | 84.8k | { | 1539 | 84.8k | return; | 1540 | 84.8k | } | 1541 | | | 1542 | | // There are 2 cases: | 1543 | | // - either the number of values for the data type can fit | 1544 | | // in the next DataOrOffsetType bytes | 1545 | | // - or it cannot, and then the next DataOrOffsetType bytes are an offset | 1546 | | // to the values | 1547 | 15.1k | if (dataTypeSize > sizeof(DataOrOffsetType) / entry.count) | 1548 | 7.16k | { | 1549 | | // Out-of-line values. We read a file offset | 1550 | 7.16k | entry.value_offset = m_rc->read<DataOrOffsetType>(offset, ok); | 1551 | 7.16k | if (entry.value_offset == 0) | 1552 | 80 | { | 1553 | | // value_offset = 0 for a out-of-line tag is obviously | 1554 | | // wrong and would cause later confusion in readTagAsVector<>, | 1555 | | // so better reject the file. | 1556 | 80 | ok = false; | 1557 | 80 | return; | 1558 | 80 | } | 1559 | 7.08k | if (dataTypeSize > | 1560 | 7.08k | std::numeric_limits<uint64_t>::max() / entry.count) | 1561 | 1.12k | { | 1562 | 1.12k | entry.invalid_value_offset = true; | 1563 | 1.12k | } | 1564 | 5.96k | else | 1565 | 5.96k | { | 1566 | 5.96k | const uint64_t byteCount = uint64_t(dataTypeSize) * entry.count; | 1567 | | | 1568 | | // Size of tag data beyond which we check the tag position and size | 1569 | | // w.r.t the file size. | 1570 | 5.96k | constexpr uint32_t THRESHOLD_CHECK_FILE_SIZE = 10 * 1000 * 1000; | 1571 | | | 1572 | 5.96k | entry.invalid_value_offset = | 1573 | 5.96k | (byteCount > THRESHOLD_CHECK_FILE_SIZE && | 1574 | 5.10k | (m_rc->size() < byteCount || | 1575 | 0 | entry.value_offset > m_rc->size() - byteCount)); | 1576 | 5.96k | } | 1577 | 7.08k | } | 1578 | 8.00k | else if (dataTypeSize == sizeof(uint8_t)) | 1579 | 794 | { | 1580 | | // Read up to 4 (classic) or 8 (BigTIFF) inline bytes | 1581 | 794 | m_rc->read(offset, size_t(entry.count), &entry.uint8Values[0], ok); | 1582 | 794 | if (entry.count == 1 && entry.type == TagType::Byte) | 1583 | 251 | { | 1584 | 251 | singleValueFitsInUInt32 = true; | 1585 | 251 | singleValue = entry.uint8Values[0]; | 1586 | 251 | } | 1587 | 794 | } | 1588 | 7.21k | else if (dataTypeSize == sizeof(uint16_t)) | 1589 | 4.66k | { | 1590 | | // Read up to 2 (classic) or 4 (BigTIFF) inline 16-bit values | 1591 | 4.66k | assert(entry.count <= 4); | 1592 | 10.2k | for (uint32_t idx = 0; idx < entry.count; ++idx) | 1593 | 5.53k | { | 1594 | 5.53k | entry.uint16Values[idx] = | 1595 | 5.53k | m_rc->read<uint16_t>(offset + idx * sizeof(uint16_t), ok); | 1596 | 5.53k | } | 1597 | 4.66k | if (entry.count == 1 && entry.type == TagType::Short) | 1598 | 4.15k | { | 1599 | 4.15k | singleValueFitsInUInt32 = true; | 1600 | 4.15k | singleValue = entry.uint16Values[0]; | 1601 | 4.15k | } | 1602 | 4.66k | } | 1603 | 2.54k | else if (dataTypeSize == sizeof(uint32_t)) | 1604 | 1.16k | { | 1605 | | // Read up to 1 (classic) or 2 (BigTIFF) inline 32-bit values | 1606 | 1.16k | entry.uint32Values[0] = m_rc->read<uint32_t>(offset, ok); | 1607 | 1.16k | if (entry.count == 1 && entry.type == TagType::Long) | 1608 | 82 | { | 1609 | 82 | singleValueFitsInUInt32 = true; | 1610 | 82 | singleValue = entry.uint32Values[0]; | 1611 | 82 | } | 1612 | | if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType, | 1613 | | uint64_t>::value) | 1614 | 1.16k | { | 1615 | 1.16k | if (entry.count == 2) | 1616 | 792 | { | 1617 | 792 | entry.uint32Values[1] = | 1618 | 792 | m_rc->read<uint32_t>(offset + sizeof(uint32_t), ok); | 1619 | 792 | } | 1620 | 1.16k | } | 1621 | 1.16k | } | 1622 | | else if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType, | 1623 | | uint64_t>::value) | 1624 | 1.38k | { | 1625 | 1.38k | if (dataTypeSize == sizeof(uint64_t)) | 1626 | 1.38k | { | 1627 | | // Read one inline 64-bit value | 1628 | 1.38k | if (entry.type == TagType::Rational) | 1629 | 649 | entry.float64Values[0] = m_rc->readRational(offset, ok); | 1630 | 734 | else if (entry.type == TagType::SRational) | 1631 | 479 | entry.float64Values[0] = | 1632 | 479 | m_rc->readSignedRational(offset, ok); | 1633 | 255 | else | 1634 | 255 | entry.uint64Values[0] = m_rc->read<uint64_t>(offset, ok); | 1635 | 1.38k | } | 1636 | 0 | else | 1637 | 0 | { | 1638 | 0 | assert(false); | 1639 | 0 | } | 1640 | | } | 1641 | | else | 1642 | | { | 1643 | | // fprintf(stderr, "Unexpected case: tag=%u, dataType=%u, count=%u\n", entry.tag, entry.type, entry.count); | 1644 | | assert(false); | 1645 | | } | 1646 | | | 1647 | 15.0k | offset += sizeof(DataOrOffsetType); | 1648 | 15.0k | } |
|
1649 | | }; |
1650 | | |
1651 | | /** Open a TIFF file and return its first Image File Directory |
1652 | | */ |
1653 | | template <bool acceptBigTIFF = true> |
1654 | | std::unique_ptr<const Image> open(const std::shared_ptr<const FileReader> &file) |
1655 | 20.6k | { |
1656 | 20.6k | unsigned char signature[2] = {0, 0}; |
1657 | 20.6k | (void)file->read(0, 2, signature); |
1658 | 20.6k | const bool littleEndian = signature[0] == 'I' && signature[1] == 'I'; |
1659 | 20.6k | const bool bigEndian = signature[0] == 'M' && signature[1] == 'M'; |
1660 | 20.6k | if (!littleEndian && !bigEndian) |
1661 | 0 | return nullptr; |
1662 | | |
1663 | 20.6k | const bool mustByteSwap = littleEndian ^ isHostLittleEndian(); |
1664 | | |
1665 | 20.6k | auto rc = std::make_shared<ReadContext>(file, mustByteSwap); |
1666 | 20.6k | bool ok = true; |
1667 | 20.6k | const int version = rc->read<uint16_t>(2, ok); |
1668 | 20.6k | constexpr int CLASSIC_TIFF_VERSION = 42; |
1669 | 20.6k | if (version == CLASSIC_TIFF_VERSION) |
1670 | 18.7k | { |
1671 | 18.7k | const auto firstImageOffset = rc->read<uint32_t>(4, ok); |
1672 | 18.7k | return Image::open<false>(rc, firstImageOffset, {}); |
1673 | 18.7k | } |
1674 | | else if LIBERTIFF_CONSTEXPR (acceptBigTIFF) |
1675 | 1.92k | { |
1676 | 1.92k | constexpr int BIGTIFF_VERSION = 43; |
1677 | 1.92k | if (version == BIGTIFF_VERSION) |
1678 | 1.92k | { |
1679 | 1.92k | const auto byteSizeOfOffsets = rc->read<uint16_t>(4, ok); |
1680 | 1.92k | if (byteSizeOfOffsets != 8) |
1681 | 30 | return nullptr; |
1682 | 1.89k | const auto zeroWord = rc->read<uint16_t>(6, ok); |
1683 | 1.89k | if (zeroWord != 0 || !ok) |
1684 | 16 | return nullptr; |
1685 | 1.87k | const auto firstImageOffset = rc->read<uint64_t>(8, ok); |
1686 | 1.87k | return Image::open<true>(rc, firstImageOffset, {}); |
1687 | 1.89k | } |
1688 | 1.92k | } |
1689 | | |
1690 | 1.92k | return nullptr; |
1691 | 20.6k | } std::__1::unique_ptr<GDAL_libertiff::Image const, std::__1::default_delete<GDAL_libertiff::Image const> > GDAL_libertiff::open<true>(std::__1::shared_ptr<GDAL_libertiff::FileReader const> const&) Line | Count | Source | 1655 | 20.5k | { | 1656 | 20.5k | unsigned char signature[2] = {0, 0}; | 1657 | 20.5k | (void)file->read(0, 2, signature); | 1658 | 20.5k | const bool littleEndian = signature[0] == 'I' && signature[1] == 'I'; | 1659 | 20.5k | const bool bigEndian = signature[0] == 'M' && signature[1] == 'M'; | 1660 | 20.5k | if (!littleEndian && !bigEndian) | 1661 | 0 | return nullptr; | 1662 | | | 1663 | 20.5k | const bool mustByteSwap = littleEndian ^ isHostLittleEndian(); | 1664 | | | 1665 | 20.5k | auto rc = std::make_shared<ReadContext>(file, mustByteSwap); | 1666 | 20.5k | bool ok = true; | 1667 | 20.5k | const int version = rc->read<uint16_t>(2, ok); | 1668 | 20.5k | constexpr int CLASSIC_TIFF_VERSION = 42; | 1669 | 20.5k | if (version == CLASSIC_TIFF_VERSION) | 1670 | 18.6k | { | 1671 | 18.6k | const auto firstImageOffset = rc->read<uint32_t>(4, ok); | 1672 | 18.6k | return Image::open<false>(rc, firstImageOffset, {}); | 1673 | 18.6k | } | 1674 | | else if LIBERTIFF_CONSTEXPR (acceptBigTIFF) | 1675 | 1.92k | { | 1676 | 1.92k | constexpr int BIGTIFF_VERSION = 43; | 1677 | 1.92k | if (version == BIGTIFF_VERSION) | 1678 | 1.92k | { | 1679 | 1.92k | const auto byteSizeOfOffsets = rc->read<uint16_t>(4, ok); | 1680 | 1.92k | if (byteSizeOfOffsets != 8) | 1681 | 30 | return nullptr; | 1682 | 1.89k | const auto zeroWord = rc->read<uint16_t>(6, ok); | 1683 | 1.89k | if (zeroWord != 0 || !ok) | 1684 | 16 | return nullptr; | 1685 | 1.87k | const auto firstImageOffset = rc->read<uint64_t>(8, ok); | 1686 | 1.87k | return Image::open<true>(rc, firstImageOffset, {}); | 1687 | 1.89k | } | 1688 | 1.92k | } | 1689 | | | 1690 | 1.92k | return nullptr; | 1691 | 20.5k | } |
std::__1::unique_ptr<GDAL_libertiff::Image const, std::__1::default_delete<GDAL_libertiff::Image const> > GDAL_libertiff::open<false>(std::__1::shared_ptr<GDAL_libertiff::FileReader const> const&) Line | Count | Source | 1655 | 121 | { | 1656 | 121 | unsigned char signature[2] = {0, 0}; | 1657 | 121 | (void)file->read(0, 2, signature); | 1658 | 121 | const bool littleEndian = signature[0] == 'I' && signature[1] == 'I'; | 1659 | 121 | const bool bigEndian = signature[0] == 'M' && signature[1] == 'M'; | 1660 | 121 | if (!littleEndian && !bigEndian) | 1661 | 0 | return nullptr; | 1662 | | | 1663 | 121 | const bool mustByteSwap = littleEndian ^ isHostLittleEndian(); | 1664 | | | 1665 | 121 | auto rc = std::make_shared<ReadContext>(file, mustByteSwap); | 1666 | 121 | bool ok = true; | 1667 | 121 | const int version = rc->read<uint16_t>(2, ok); | 1668 | 121 | constexpr int CLASSIC_TIFF_VERSION = 42; | 1669 | 121 | if (version == CLASSIC_TIFF_VERSION) | 1670 | 121 | { | 1671 | 121 | const auto firstImageOffset = rc->read<uint32_t>(4, ok); | 1672 | 121 | return Image::open<false>(rc, firstImageOffset, {}); | 1673 | 121 | } | 1674 | 0 | else if LIBERTIFF_CONSTEXPR (acceptBigTIFF) | 1675 | 0 | { | 1676 | 0 | constexpr int BIGTIFF_VERSION = 43; | 1677 | 0 | if (version == BIGTIFF_VERSION) | 1678 | 0 | { | 1679 | 0 | const auto byteSizeOfOffsets = rc->read<uint16_t>(4, ok); | 1680 | 0 | if (byteSizeOfOffsets != 8) | 1681 | 0 | return nullptr; | 1682 | 0 | const auto zeroWord = rc->read<uint16_t>(6, ok); | 1683 | 0 | if (zeroWord != 0 || !ok) | 1684 | 0 | return nullptr; | 1685 | 0 | const auto firstImageOffset = rc->read<uint64_t>(8, ok); | 1686 | 0 | return Image::open<true>(rc, firstImageOffset, {}); | 1687 | 0 | } | 1688 | 0 | } | 1689 | | | 1690 | 0 | return nullptr; | 1691 | 121 | } |
|
1692 | | } // namespace LIBERTIFF_NS |
1693 | | |
1694 | | #ifdef LIBERTIFF_C_FILE_READER |
1695 | | #include <cstdio> |
1696 | | #include <mutex> |
1697 | | |
1698 | | namespace LIBERTIFF_NS |
1699 | | { |
1700 | | /** Interface to read from a FILE* handle */ |
1701 | | class CFileReader final : public FileReader |
1702 | | { |
1703 | | public: |
1704 | | explicit CFileReader(FILE *f) : m_f(f) |
1705 | | { |
1706 | | } |
1707 | | |
1708 | | ~CFileReader() override |
1709 | | { |
1710 | | fclose(m_f); |
1711 | | } |
1712 | | |
1713 | | uint64_t size() const override |
1714 | | { |
1715 | | std::lock_guard<std::mutex> oLock(m_oMutex); |
1716 | | fseek(m_f, 0, SEEK_END); |
1717 | | return ftell(m_f); |
1718 | | } |
1719 | | |
1720 | | size_t read(uint64_t offset, size_t count, void *buffer) const override |
1721 | | { |
1722 | | std::lock_guard<std::mutex> oLock(m_oMutex); |
1723 | | if (fseek(m_f, static_cast<long>(offset), SEEK_SET) != 0) |
1724 | | return 0; |
1725 | | return fread(buffer, 1, count, m_f); |
1726 | | } |
1727 | | |
1728 | | private: |
1729 | | FILE *const m_f; |
1730 | | mutable std::mutex m_oMutex{}; |
1731 | | |
1732 | | CFileReader(const CFileReader &) = delete; |
1733 | | CFileReader &operator=(const CFileReader &) = delete; |
1734 | | }; |
1735 | | } // namespace LIBERTIFF_NS |
1736 | | #endif |
1737 | | |
1738 | | #endif // LIBERTIFF_HPP_INCLUDED |