Line data Source code
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 : #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 1446 : std::unique_ptr<T> make_unique(Args &&...args)
67 : {
68 1446 : return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
69 : }
70 :
71 : /** Returns whether the host is little-endian ordered */
72 1342 : inline bool isHostLittleEndian()
73 : {
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 1342 : 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 : }
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 : {
97 : return v;
98 : }
99 :
100 : /** Byte-swap a int8_t */
101 : template <> inline int8_t byteSwap(int8_t v)
102 : {
103 : return v;
104 : }
105 :
106 : /** Byte-swap a uint16_t */
107 5931 : template <> inline uint16_t byteSwap(uint16_t v)
108 : {
109 5931 : return uint16_t((v >> 8) | ((v & 0xff) << 8));
110 : }
111 :
112 : /** Byte-swap a int16_t */
113 : template <> inline int16_t byteSwap(int16_t v)
114 : {
115 : uint16_t u;
116 : LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u));
117 : std::memcpy(&u, &v, sizeof(u));
118 : u = byteSwap(u);
119 : std::memcpy(&v, &u, sizeof(u));
120 : return v;
121 : }
122 :
123 : /** Byte-swap a uint32_t */
124 309705 : template <> inline uint32_t byteSwap(uint32_t v)
125 : {
126 309705 : return (v >> 24) | (((v >> 16) & 0xff) << 8) | (((v >> 8) & 0xff) << 16) |
127 309705 : ((v & 0xff) << 24);
128 : }
129 :
130 : /** Byte-swap a int32_t */
131 0 : template <> inline int32_t byteSwap(int32_t v)
132 : {
133 : uint32_t u;
134 : LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u));
135 0 : std::memcpy(&u, &v, sizeof(u));
136 0 : u = byteSwap(u);
137 0 : std::memcpy(&v, &u, sizeof(u));
138 0 : return v;
139 : }
140 :
141 : /** Byte-swap a uint64_t */
142 153395 : template <> inline uint64_t byteSwap(uint64_t v)
143 : {
144 153395 : return (uint64_t(byteSwap(uint32_t(v & ~(0U)))) << 32) |
145 153395 : byteSwap(uint32_t(v >> 32));
146 : }
147 :
148 : /** Byte-swap a int64_t */
149 : template <> inline int64_t byteSwap(int64_t v)
150 : {
151 : uint64_t u;
152 : std::memcpy(&u, &v, sizeof(u));
153 : u = byteSwap(u);
154 : std::memcpy(&v, &u, sizeof(u));
155 : return v;
156 : }
157 :
158 : /** Byte-swap a float */
159 : template <> inline float byteSwap(float v)
160 : {
161 : uint32_t u;
162 : LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u));
163 : std::memcpy(&u, &v, sizeof(u));
164 : u = byteSwap(u);
165 : std::memcpy(&v, &u, sizeof(u));
166 : return v;
167 : }
168 :
169 : /** Byte-swap a double */
170 : template <> inline double byteSwap(double v)
171 : {
172 : uint64_t u;
173 : LIBERTIFF_STATIC_ASSERT(sizeof(v) == sizeof(u));
174 : std::memcpy(&u, &v, sizeof(u));
175 : u = byteSwap(u);
176 : std::memcpy(&v, &u, sizeof(u));
177 : return v;
178 : }
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 1342 : 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 1342 : ReadContext(const std::shared_ptr<const FileReader> &file,
216 : bool mustByteSwap)
217 1342 : : m_file(file), m_mustByteSwap(mustByteSwap)
218 : {
219 1342 : }
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 6408 : inline bool mustByteSwap() const
225 : {
226 6408 : return m_mustByteSwap;
227 : }
228 :
229 : /** Return file size */
230 108 : inline uint64_t size() const
231 : {
232 108 : return m_file->size();
233 : }
234 :
235 : /** Read count raw bytes at offset into buffer */
236 7773 : void read(uint64_t offset, size_t count, void *buffer, bool &ok) const
237 : {
238 7773 : if (m_file->read(offset, count, buffer) != count)
239 17 : ok = false;
240 7821 : }
241 :
242 : /** Read single value at offset */
243 90014 : template <class T> T read(uint64_t offset, bool &ok) const
244 : {
245 : #if __cplusplus >= 201703L
246 : static_assert(
247 : std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> ||
248 : std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> ||
249 : std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> ||
250 : std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> ||
251 : std::is_same_v<T, float> || std::is_same_v<T, double>);
252 : #endif
253 :
254 90014 : T res = 0;
255 90014 : if (m_file->read(offset, sizeof(res), &res) != sizeof(res))
256 : {
257 186 : ok = false;
258 186 : return 0;
259 : }
260 : if LIBERTIFF_CONSTEXPR (sizeof(T) > 1)
261 : {
262 89805 : if (m_mustByteSwap)
263 8837 : res = byteSwap(res);
264 : }
265 89805 : return res;
266 : }
267 :
268 : /** Read a unsigned rational (type == Type::Rational) */
269 : template <class T = uint32_t>
270 0 : double readRational(uint64_t offset, bool &ok) const
271 : {
272 0 : const auto numerator = read<T>(offset, ok);
273 0 : const auto denominator = read<T>(offset + sizeof(T), ok);
274 0 : if (denominator == 0)
275 : {
276 0 : ok = false;
277 0 : return std::numeric_limits<double>::quiet_NaN();
278 : }
279 0 : return double(numerator) / denominator;
280 : }
281 :
282 : /** Read a signed rational (type == Type::SRational) */
283 0 : double readSignedRational(uint64_t offset, bool &ok) const
284 : {
285 0 : return readRational<int32_t>(offset, ok);
286 : }
287 :
288 : /** Read length bytes at offset (typically for ASCII tag) as a string */
289 100 : std::string readString(std::string &res, uint64_t offset, size_t length,
290 : bool &ok) const
291 : {
292 100 : res.resize(length);
293 100 : if (length > 0 && m_file->read(offset, length, &res[0]) != length)
294 : {
295 0 : ok = false;
296 0 : res.clear();
297 0 : return res;
298 : }
299 : // Strip trailing nul byte if found
300 100 : if (length > 0 && res.back() == 0)
301 99 : res.pop_back();
302 100 : return res;
303 : }
304 :
305 : /** Read length bytes at offset (typically for ASCII tag) as a string */
306 100 : std::string readString(uint64_t offset, size_t length, bool &ok) const
307 : {
308 100 : std::string res;
309 100 : readString(res, offset, length, ok);
310 100 : return res;
311 : }
312 :
313 : /** Read an array of count values starting at offset */
314 : template <class T>
315 1084 : void readArray(std::vector<T> &array, uint64_t offset, size_t count,
316 : bool &ok) const
317 : {
318 : #if __cplusplus >= 201703L
319 : static_assert(
320 : std::is_same_v<T, uint8_t> || std::is_same_v<T, int8_t> ||
321 : std::is_same_v<T, uint16_t> || std::is_same_v<T, int16_t> ||
322 : std::is_same_v<T, uint32_t> || std::is_same_v<T, int32_t> ||
323 : std::is_same_v<T, uint64_t> || std::is_same_v<T, int64_t> ||
324 : std::is_same_v<T, float> || std::is_same_v<T, double>);
325 : #endif
326 :
327 1084 : array.resize(count);
328 1084 : const size_t countBytes = count * sizeof(T);
329 2168 : if (count > 0 &&
330 1084 : m_file->read(offset, countBytes, &array[0]) != countBytes)
331 : {
332 11 : ok = false;
333 11 : array.clear();
334 : }
335 : else if LIBERTIFF_CONSTEXPR (sizeof(T) > 1)
336 : {
337 1036 : if (m_mustByteSwap)
338 : {
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 20 : reinterpret_cast<uint64_t *>(array.data());
352 153194 : for (size_t i = 0; i < count; ++i)
353 : {
354 153174 : uint64Array[i] = byteSwap(uint64Array[i]);
355 : }
356 : }
357 : else
358 : {
359 240 : for (size_t i = 0; i < count; ++i)
360 : {
361 230 : array[i] = byteSwap(array[i]);
362 : }
363 : }
364 : }
365 : }
366 1084 : }
367 :
368 : /** Read an array of count values starting at offset */
369 : template <class T>
370 1084 : std::vector<T> readArray(uint64_t offset, size_t count, bool &ok) const
371 : {
372 1084 : std::vector<T> array;
373 1084 : readArray(array, offset, count, ok);
374 1084 : return array;
375 : }
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 : {
456 : switch (tagCode)
457 : {
458 : LIBERTIFF_CASE_TAGCODE_STR(SubFileType);
459 : LIBERTIFF_CASE_TAGCODE_STR(OldSubFileType);
460 : LIBERTIFF_CASE_TAGCODE_STR(ImageWidth);
461 : LIBERTIFF_CASE_TAGCODE_STR(ImageLength);
462 : LIBERTIFF_CASE_TAGCODE_STR(BitsPerSample);
463 : LIBERTIFF_CASE_TAGCODE_STR(Compression);
464 : LIBERTIFF_CASE_TAGCODE_STR(PhotometricInterpretation);
465 : LIBERTIFF_CASE_TAGCODE_STR(DocumentName);
466 : LIBERTIFF_CASE_TAGCODE_STR(ImageDescription);
467 : LIBERTIFF_CASE_TAGCODE_STR(StripOffsets);
468 : LIBERTIFF_CASE_TAGCODE_STR(SamplesPerPixel);
469 : LIBERTIFF_CASE_TAGCODE_STR(RowsPerStrip);
470 : LIBERTIFF_CASE_TAGCODE_STR(StripByteCounts);
471 : LIBERTIFF_CASE_TAGCODE_STR(PlanarConfiguration);
472 : LIBERTIFF_CASE_TAGCODE_STR(Software);
473 : LIBERTIFF_CASE_TAGCODE_STR(DateTime);
474 : LIBERTIFF_CASE_TAGCODE_STR(Predictor);
475 : LIBERTIFF_CASE_TAGCODE_STR(ColorMap);
476 : LIBERTIFF_CASE_TAGCODE_STR(TileWidth);
477 : LIBERTIFF_CASE_TAGCODE_STR(TileLength);
478 : LIBERTIFF_CASE_TAGCODE_STR(TileOffsets);
479 : LIBERTIFF_CASE_TAGCODE_STR(TileByteCounts);
480 : LIBERTIFF_CASE_TAGCODE_STR(ExtraSamples);
481 : LIBERTIFF_CASE_TAGCODE_STR(SampleFormat);
482 : LIBERTIFF_CASE_TAGCODE_STR(Copyright);
483 : LIBERTIFF_CASE_TAGCODE_STR(JPEGTables);
484 : LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFPixelScale);
485 : LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFTiePoints);
486 : LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFGeoTransMatrix);
487 : LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFGeoKeyDirectory);
488 : LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFDoubleParams);
489 : LIBERTIFF_CASE_TAGCODE_STR(GeoTIFFAsciiParams);
490 : LIBERTIFF_CASE_TAGCODE_STR(GDAL_METADATA);
491 : LIBERTIFF_CASE_TAGCODE_STR(GDAL_NODATA);
492 : LIBERTIFF_CASE_TAGCODE_STR(RPCCoefficients);
493 : LIBERTIFF_CASE_TAGCODE_STR(LERCParameters);
494 : default:
495 : break;
496 : }
497 : return "(unknown)";
498 : }
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 : {
535 : switch (tagType)
536 : {
537 : LIBERTIFF_CASE_TAGTYPE_STR(Byte);
538 : LIBERTIFF_CASE_TAGTYPE_STR(ASCII);
539 : LIBERTIFF_CASE_TAGTYPE_STR(Short);
540 : LIBERTIFF_CASE_TAGTYPE_STR(Long);
541 : LIBERTIFF_CASE_TAGTYPE_STR(Rational);
542 : LIBERTIFF_CASE_TAGTYPE_STR(SByte);
543 : LIBERTIFF_CASE_TAGTYPE_STR(Undefined);
544 : LIBERTIFF_CASE_TAGTYPE_STR(SShort);
545 : LIBERTIFF_CASE_TAGTYPE_STR(SLong);
546 : LIBERTIFF_CASE_TAGTYPE_STR(SRational);
547 : LIBERTIFF_CASE_TAGTYPE_STR(Float);
548 : LIBERTIFF_CASE_TAGTYPE_STR(Double);
549 : LIBERTIFF_CASE_TAGTYPE_STR(Long8);
550 : LIBERTIFF_CASE_TAGTYPE_STR(SLong8);
551 : LIBERTIFF_CASE_TAGTYPE_STR(IFD8);
552 : default:
553 : break;
554 : }
555 : return "(unknown)";
556 : }
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 : {
578 : switch (planarConfiguration)
579 : {
580 : LIBERTIFF_CASE_PLANAR_CONFIG_STR(Contiguous);
581 : LIBERTIFF_CASE_PLANAR_CONFIG_STR(Separate);
582 : default:
583 : break;
584 : }
585 : return "(unknown)";
586 : }
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 : {
615 : switch (photometricInterpretation)
616 : {
617 : LIBERTIFF_CASE_PHOTOMETRIC_STR(MinIsWhite);
618 : LIBERTIFF_CASE_PHOTOMETRIC_STR(MinIsBlack);
619 : LIBERTIFF_CASE_PHOTOMETRIC_STR(RGB);
620 : LIBERTIFF_CASE_PHOTOMETRIC_STR(Palette);
621 : LIBERTIFF_CASE_PHOTOMETRIC_STR(Mask);
622 : LIBERTIFF_CASE_PHOTOMETRIC_STR(Separated);
623 : LIBERTIFF_CASE_PHOTOMETRIC_STR(YCbCr);
624 : LIBERTIFF_CASE_PHOTOMETRIC_STR(CIELab);
625 : LIBERTIFF_CASE_PHOTOMETRIC_STR(ICCLab);
626 : LIBERTIFF_CASE_PHOTOMETRIC_STR(ITULab);
627 : default:
628 : break;
629 : }
630 : return "(unknown)";
631 : }
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 : case Compression::x: \
669 : return #x
670 :
671 18 : inline const char *compressionName(CompressionType compression)
672 : {
673 18 : switch (compression)
674 : {
675 0 : LIBERTIFF_CASE_COMPRESSION_STR(None);
676 1 : LIBERTIFF_CASE_COMPRESSION_STR(CCITT_RLE);
677 0 : LIBERTIFF_CASE_COMPRESSION_STR(CCITT_FAX3);
678 1 : LIBERTIFF_CASE_COMPRESSION_STR(CCITT_FAX4);
679 0 : LIBERTIFF_CASE_COMPRESSION_STR(LZW);
680 2 : 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 0 : 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 14 : default:
693 14 : break;
694 : }
695 14 : return "(unknown)";
696 : }
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 : {
720 : switch (sampleFormat)
721 : {
722 : LIBERTIFF_CASE_SAMPLE_FORMAT_STR(UnsignedInt);
723 : LIBERTIFF_CASE_SAMPLE_FORMAT_STR(SignedInt);
724 : LIBERTIFF_CASE_SAMPLE_FORMAT_STR(IEEEFP);
725 : LIBERTIFF_CASE_SAMPLE_FORMAT_STR(Void);
726 : LIBERTIFF_CASE_SAMPLE_FORMAT_STR(ComplexInt);
727 : LIBERTIFF_CASE_SAMPLE_FORMAT_STR(ComplexIEEEFP);
728 : default:
729 : break;
730 : }
731 : return "(unknown)";
732 : }
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 17402 : inline uint32_t tagTypeSize(TagTypeType type)
780 : {
781 17402 : switch (type)
782 : {
783 13 : case TagType::Byte: return 1;
784 505 : case TagType::ASCII: return 1;
785 12704 : case TagType::Short: return 2;
786 2510 : case TagType::Long: return 4;
787 84 : case TagType::Rational: return 8; // 2 Long
788 0 : case TagType::SByte: return 1;
789 38 : case TagType::Undefined: return 1;
790 0 : case TagType::SShort: return 2;
791 0 : case TagType::SLong: return 4;
792 0 : case TagType::SRational: return 8; // 2 SLong
793 0 : case TagType::Float: return 4;
794 933 : case TagType::Double: return 8;
795 41 : case TagType::Long8: return 8;
796 1 : case TagType::SLong8: return 8;
797 0 : case TagType::IFD8: return 8;
798 573 : default: break;
799 : }
800 573 : return 0;
801 : }
802 :
803 : // clang-format on
804 :
805 : namespace detail
806 : {
807 : template <class T>
808 1099 : inline std::vector<T> readTagAsVectorInternal(const ReadContext &rc,
809 : const TagEntry &tag,
810 : TagTypeType expectedType,
811 : const T *inlineValues, bool &ok)
812 : {
813 1099 : if (tag.type == expectedType)
814 : {
815 1099 : if (tag.value_offset)
816 : {
817 1076 : if (!tag.invalid_value_offset)
818 : {
819 : if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t))
820 : {
821 : if (tag.count > std::numeric_limits<size_t>::max())
822 : {
823 : ok = false;
824 : return {};
825 : }
826 : }
827 1076 : return rc.readArray<T>(tag.value_offset,
828 1076 : static_cast<size_t>(tag.count), ok);
829 : }
830 : }
831 : else
832 : {
833 : return std::vector<T>(
834 23 : inlineValues, inlineValues + static_cast<size_t>(tag.count));
835 : }
836 : }
837 0 : ok = false;
838 0 : return {};
839 : }
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 : {
849 : return readTagAsVectorInternal(rc, tag, TagType::SByte,
850 : tag.int8Values.data(), ok);
851 : }
852 :
853 : template <>
854 37 : inline std::vector<uint8_t> readTagAsVector(const ReadContext &rc,
855 : const TagEntry &tag, bool &ok)
856 : {
857 : return readTagAsVectorInternal(
858 74 : rc, tag, tag.type == TagType::Undefined ? tag.type : TagType::Byte,
859 37 : tag.uint8Values.data(), ok);
860 : }
861 :
862 : template <>
863 : inline std::vector<int16_t> readTagAsVector(const ReadContext &rc,
864 : const TagEntry &tag, bool &ok)
865 : {
866 : return readTagAsVectorInternal(rc, tag, TagType::SShort,
867 : tag.int16Values.data(), ok);
868 : }
869 :
870 : template <>
871 351 : inline std::vector<uint16_t> readTagAsVector(const ReadContext &rc,
872 : const TagEntry &tag, bool &ok)
873 : {
874 : return readTagAsVectorInternal(rc, tag, TagType::Short,
875 351 : tag.uint16Values.data(), ok);
876 : }
877 :
878 : template <>
879 : inline std::vector<int32_t> readTagAsVector(const ReadContext &rc,
880 : const TagEntry &tag, bool &ok)
881 : {
882 : return readTagAsVectorInternal(rc, tag, TagType::SLong,
883 : tag.int32Values.data(), ok);
884 : }
885 :
886 : template <>
887 73 : inline std::vector<uint32_t> readTagAsVector(const ReadContext &rc,
888 : const TagEntry &tag, bool &ok)
889 : {
890 : return readTagAsVectorInternal(rc, tag, TagType::Long,
891 73 : tag.uint32Values.data(), ok);
892 : }
893 :
894 : template <>
895 : inline std::vector<int64_t> readTagAsVector(const ReadContext &rc,
896 : const TagEntry &tag, bool &ok)
897 : {
898 : return readTagAsVectorInternal(rc, tag, TagType::SLong8,
899 : tag.int64Values.data(), ok);
900 : }
901 :
902 : template <>
903 0 : inline std::vector<uint64_t> readTagAsVector(const ReadContext &rc,
904 : const TagEntry &tag, bool &ok)
905 : {
906 : return readTagAsVectorInternal(rc, tag, TagType::Long8,
907 0 : tag.uint64Values.data(), ok);
908 : }
909 :
910 : template <>
911 : inline std::vector<float> readTagAsVector(const ReadContext &rc,
912 : const TagEntry &tag, bool &ok)
913 : {
914 : return readTagAsVectorInternal(rc, tag, TagType::Float,
915 : tag.float32Values.data(), ok);
916 : }
917 :
918 : template <>
919 638 : inline std::vector<double> readTagAsVector(const ReadContext &rc,
920 : const TagEntry &tag, bool &ok)
921 : {
922 : return readTagAsVectorInternal(rc, tag, TagType::Double,
923 638 : tag.float64Values.data(), ok);
924 : }
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 1446 : Image(const std::shared_ptr<const ReadContext> &rc, bool isBigTIFF)
934 1446 : : m_rc(rc), m_isBigTIFF(isBigTIFF)
935 : {
936 1446 : }
937 :
938 : /** Return read context */
939 14318 : const std::shared_ptr<const ReadContext> &readContext() const
940 : {
941 14318 : return m_rc;
942 : }
943 :
944 : /** Return whether the file is BigTIFF (if false, classic TIFF) */
945 : inline bool isBigTIFF() const
946 : {
947 : return m_isBigTIFF;
948 : }
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 4 : inline bool mustByteSwap() const
954 : {
955 4 : return m_rc->mustByteSwap();
956 : }
957 :
958 : /** Return the offset of the this IFD */
959 3 : inline uint64_t offset() const
960 : {
961 3 : return m_offset;
962 : }
963 :
964 : /** Return the offset of the next IFD (to pass to Image::open()),
965 : * or 0 if there is no more */
966 111 : inline uint64_t nextImageOffset() const
967 : {
968 111 : return m_nextImageOffset;
969 : }
970 :
971 : /** Return value of SubFileType tag */
972 2447 : inline uint32_t subFileType() const
973 : {
974 2447 : return m_subFileType;
975 : }
976 :
977 : /** Return width of the image in pixels */
978 3532 : inline uint32_t width() const
979 : {
980 3532 : return m_width;
981 : }
982 :
983 : /** Return height of the image in pixels */
984 3819 : inline uint32_t height() const
985 : {
986 3819 : return m_height;
987 : }
988 :
989 : /** Return number of bits per sample */
990 155834 : inline uint32_t bitsPerSample() const
991 : {
992 155834 : return m_bitsPerSample;
993 : }
994 :
995 : /** Return number of samples (a.k.a. channels, bands) per pixel */
996 5213 : inline uint32_t samplesPerPixel() const
997 : {
998 5213 : return m_samplesPerPixel;
999 : }
1000 :
1001 : /** Return planar configuration */
1002 13560 : inline PlanarConfigurationType planarConfiguration() const
1003 : {
1004 13560 : return m_planarConfiguration;
1005 : }
1006 :
1007 : /** Return planar configuration */
1008 137606 : inline PhotometricInterpretationType photometricInterpretation() const
1009 : {
1010 137606 : return m_photometricInterpretation;
1011 : }
1012 :
1013 : /** Return compression method used */
1014 78992 : inline CompressionType compression() const
1015 : {
1016 78992 : return m_compression;
1017 : }
1018 :
1019 : /** Return predictor value (used for Deflate, LZW, ZStd, etc. compression) */
1020 15145 : inline uint32_t predictor() const
1021 : {
1022 15145 : return m_predictor;
1023 : }
1024 :
1025 : /** Return sample format */
1026 1334 : inline SampleFormatType sampleFormat() const
1027 : {
1028 1334 : return m_sampleFormat;
1029 : }
1030 :
1031 : /** Return the number of rows per strip */
1032 6 : inline uint32_t rowsPerStrip() const
1033 : {
1034 6 : return m_rowsPerStrip;
1035 : }
1036 :
1037 : /** Return the sanitized number of rows per strip */
1038 2268 : inline uint32_t rowsPerStripSanitized() const
1039 : {
1040 2268 : return std::min(m_rowsPerStrip, m_height);
1041 : }
1042 :
1043 : /** Return the number of strips/tiles.
1044 : * Return 0 if inconsistent values between ByteCounts and Offsets arrays. */
1045 6 : inline uint64_t strileCount() const
1046 : {
1047 6 : return m_strileCount;
1048 : }
1049 :
1050 : /** Return whether image is tiled */
1051 26173 : inline bool isTiled() const
1052 : {
1053 26173 : return m_isTiled;
1054 : }
1055 :
1056 : /** Return tile width */
1057 423 : inline uint32_t tileWidth() const
1058 : {
1059 423 : return m_tileWidth;
1060 : }
1061 :
1062 : /** Return tile width */
1063 419 : inline uint32_t tileHeight() const
1064 : {
1065 419 : return m_tileHeight;
1066 : }
1067 :
1068 : /** Return number of tiles per row */
1069 6401 : uint32_t tilesPerRow() const
1070 : {
1071 6401 : if (m_tileWidth > 0)
1072 : {
1073 6396 : return uint32_t((uint64_t(m_width) + m_tileWidth - 1) /
1074 6396 : m_tileWidth);
1075 : }
1076 5 : return 0;
1077 : }
1078 :
1079 : /** Return number of tiles per column */
1080 6385 : uint32_t tilesPerCol() const
1081 : {
1082 6385 : if (m_tileHeight > 0)
1083 : {
1084 6408 : return uint32_t((uint64_t(m_height) + m_tileHeight - 1) /
1085 6408 : m_tileHeight);
1086 : }
1087 0 : return 0;
1088 : }
1089 :
1090 : /** Convert a tile coordinate (xtile, ytile, bandIdx) to a flat index */
1091 6398 : uint64_t tileCoordinateToIdx(uint32_t xtile, uint32_t ytile,
1092 : uint32_t bandIdx, bool &ok) const
1093 : {
1094 6398 : if (m_isTiled && m_tileWidth > 0 && m_tileHeight > 0)
1095 : {
1096 6388 : const uint32_t lTilesPerRow = tilesPerRow();
1097 6392 : const uint32_t lTilesPerCol = tilesPerCol();
1098 6399 : if (xtile >= lTilesPerRow || ytile >= lTilesPerCol)
1099 : {
1100 0 : ok = false;
1101 0 : return 0;
1102 : }
1103 6399 : uint64_t idx = uint64_t(ytile) * lTilesPerRow + xtile;
1104 6399 : if (bandIdx &&
1105 3659 : m_planarConfiguration == PlanarConfiguration::Separate)
1106 : {
1107 3659 : const uint64_t lTotalTiles =
1108 3659 : uint64_t(lTilesPerCol) * lTilesPerRow;
1109 3657 : if (lTotalTiles >
1110 3659 : std::numeric_limits<uint64_t>::max() / bandIdx)
1111 : {
1112 0 : ok = false;
1113 0 : return 0;
1114 : }
1115 3657 : idx += bandIdx * lTotalTiles;
1116 : }
1117 6397 : return idx;
1118 : }
1119 10 : ok = false;
1120 10 : return 0;
1121 : }
1122 :
1123 : /** Return the offset of strip/tile of index idx */
1124 8083 : uint64_t strileOffset(uint64_t idx, bool &ok) const
1125 : {
1126 8083 : return readUIntTag(m_strileOffsetsTag, idx, ok);
1127 : }
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 : {
1133 : const auto idx = tileCoordinateToIdx(xtile, ytile, bandIdx, ok);
1134 : return ok ? strileOffset(idx, ok) : 0;
1135 : }
1136 :
1137 : /** Return the byte count of strip/tile of index idx */
1138 7927 : uint64_t strileByteCount(uint64_t idx, bool &ok) const
1139 : {
1140 7927 : return readUIntTag(m_strileByteCountsTag, idx, ok);
1141 : }
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 : {
1147 : const auto idx = tileCoordinateToIdx(xtile, ytile, bandIdx, ok);
1148 : return ok ? strileByteCount(idx, ok) : 0;
1149 : }
1150 :
1151 : /** Return the list of tags */
1152 : inline const std::vector<TagEntry> &tags() const
1153 : {
1154 : return m_tags;
1155 : }
1156 :
1157 : /** Return the (first) tag corresponding to a code, or nullptr if not found */
1158 16597 : const TagEntry *tag(TagCodeType tagCode) const
1159 : {
1160 212547 : for (const auto &tag : m_tags)
1161 : {
1162 199987 : if (tag.tag == tagCode)
1163 4037 : return &tag;
1164 : }
1165 12560 : return nullptr;
1166 : }
1167 :
1168 : /** Read an ASCII tag as a string */
1169 121 : std::string readTagAsString(const TagEntry &tag, bool &ok) const
1170 : {
1171 121 : if (tag.type == TagType::ASCII)
1172 : {
1173 121 : if (tag.value_offset)
1174 : {
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 98 : return readContext()->readString(
1185 98 : tag.value_offset, static_cast<size_t>(tag.count), ok);
1186 : }
1187 23 : if (tag.count)
1188 : {
1189 : std::string res(tag.charValues.data(),
1190 46 : static_cast<size_t>(tag.count));
1191 23 : if (res.back() == 0)
1192 23 : res.pop_back();
1193 23 : return res;
1194 : }
1195 : }
1196 0 : ok = false;
1197 0 : return std::string();
1198 : }
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 1099 : std::vector<T> readTagAsVector(const TagEntry &tag, bool &ok) const
1207 : {
1208 1099 : return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok);
1209 : }
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 2293 : 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 : {
1219 : // To prevent infinite looping on corrupted files
1220 3739 : if (imageOffset == 0 || alreadyVisitedImageOffsets.find(imageOffset) !=
1221 3739 : alreadyVisitedImageOffsets.end())
1222 : {
1223 847 : return nullptr;
1224 : }
1225 :
1226 2892 : auto image = LIBERTIFF_NS::make_unique<Image>(rc, isBigTIFF);
1227 :
1228 1446 : image->m_offset = imageOffset;
1229 1446 : image->m_alreadyVisitedImageOffsets = alreadyVisitedImageOffsets;
1230 1446 : image->m_alreadyVisitedImageOffsets.insert(imageOffset);
1231 :
1232 1446 : bool ok = true;
1233 1446 : int tagCount = 0;
1234 1446 : 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 29 : if (offset >= std::numeric_limits<uint64_t>::max() / 2)
1241 0 : return nullptr;
1242 :
1243 29 : const auto tagCount64Bit = rc->read<uint64_t>(offset, ok);
1244 : // Artificially limit to the same number of entries as ClassicTIFF
1245 29 : if (tagCount64Bit > std::numeric_limits<uint16_t>::max())
1246 0 : return nullptr;
1247 29 : tagCount = static_cast<int>(tagCount64Bit);
1248 29 : offset += sizeof(uint64_t);
1249 : }
1250 : else
1251 : {
1252 1417 : tagCount = rc->read<uint16_t>(offset, ok);
1253 1417 : offset += sizeof(uint16_t);
1254 : }
1255 1446 : if (!ok)
1256 78 : return nullptr;
1257 1368 : image->m_tags.reserve(tagCount);
1258 1368 : assert(tagCount <= 65535);
1259 18814 : for (int i = 0; i < tagCount; ++i)
1260 : {
1261 17489 : TagEntry entry;
1262 :
1263 : // Read tag code
1264 17489 : entry.tag = rc->read<uint16_t>(offset, ok);
1265 17489 : offset += sizeof(uint16_t);
1266 :
1267 : // Read tag data type
1268 17489 : entry.type = rc->read<uint16_t>(offset, ok);
1269 17489 : offset += sizeof(uint16_t);
1270 :
1271 : // Read number of values
1272 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1273 : {
1274 327 : auto count = rc->read<uint64_t>(offset, ok);
1275 327 : entry.count = count;
1276 327 : offset += sizeof(count);
1277 : }
1278 : else
1279 : {
1280 17162 : auto count = rc->read<uint32_t>(offset, ok);
1281 17162 : entry.count = count;
1282 17162 : offset += sizeof(count);
1283 : }
1284 :
1285 17489 : uint32_t singleValue = 0;
1286 17489 : bool singleValueFitsInUInt32 = false;
1287 17489 : if (entry.count)
1288 : {
1289 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1290 : {
1291 327 : image->ParseTagEntryDataOrOffset<uint64_t>(
1292 : entry, offset, singleValueFitsInUInt32, singleValue,
1293 : ok);
1294 : }
1295 : else
1296 : {
1297 17075 : image->ParseTagEntryDataOrOffset<uint32_t>(
1298 : entry, offset, singleValueFitsInUInt32, singleValue,
1299 : ok);
1300 : }
1301 : }
1302 17489 : if (!ok)
1303 43 : return nullptr;
1304 :
1305 17446 : image->processTag(entry, singleValueFitsInUInt32, singleValue);
1306 :
1307 17446 : image->m_tags.push_back(entry);
1308 : }
1309 :
1310 1325 : image->finalTagProcessing();
1311 :
1312 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1313 29 : image->m_nextImageOffset = rc->read<uint64_t>(offset, ok);
1314 : else
1315 1296 : image->m_nextImageOffset = rc->read<uint32_t>(offset, ok);
1316 :
1317 1325 : image->m_openFunc = open<isBigTIFF>;
1318 :
1319 1325 : return std::unique_ptr<const Image>(image.release());
1320 : }
1321 :
1322 : /** Returns a new Image instance at the next IFD, or nullptr if there is none */
1323 951 : std::unique_ptr<const Image> next() const
1324 : {
1325 951 : return m_openFunc(m_rc, m_nextImageOffset,
1326 951 : m_alreadyVisitedImageOffsets);
1327 : }
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 17446 : void processTag(const TagEntry &entry, bool singleValueFitsInUInt32,
1367 : uint32_t singleValue)
1368 : {
1369 17446 : if (singleValueFitsInUInt32)
1370 : {
1371 13445 : switch (entry.tag)
1372 : {
1373 27 : case TagCode::SubFileType:
1374 27 : m_subFileType = singleValue;
1375 27 : break;
1376 :
1377 1323 : case TagCode::ImageWidth:
1378 1323 : m_width = singleValue;
1379 1323 : break;
1380 :
1381 1313 : case TagCode::ImageLength:
1382 1313 : m_height = singleValue;
1383 1313 : break;
1384 :
1385 1300 : case TagCode::Compression:
1386 1300 : m_compression = singleValue;
1387 1300 : break;
1388 :
1389 1279 : case TagCode::SamplesPerPixel:
1390 1279 : m_samplesPerPixel = singleValue;
1391 1279 : break;
1392 :
1393 1129 : case TagCode::RowsPerStrip:
1394 1129 : m_rowsPerStrip = singleValue;
1395 1129 : break;
1396 :
1397 1277 : case TagCode::PlanarConfiguration:
1398 1277 : m_planarConfiguration = singleValue;
1399 1277 : break;
1400 :
1401 1297 : case TagCode::PhotometricInterpretation:
1402 1297 : m_photometricInterpretation = singleValue;
1403 1297 : break;
1404 :
1405 114 : case TagCode::Predictor:
1406 114 : m_predictor = singleValue;
1407 114 : break;
1408 :
1409 149 : case TagCode::TileWidth:
1410 149 : m_tileWidth = singleValue;
1411 149 : break;
1412 :
1413 149 : case TagCode::TileLength:
1414 149 : m_tileHeight = singleValue;
1415 149 : break;
1416 :
1417 4088 : default:
1418 4088 : break;
1419 : }
1420 : }
1421 :
1422 17446 : if (entry.count &&
1423 17386 : (entry.type == TagType::Byte || entry.type == TagType::Short ||
1424 4684 : entry.type == TagType::Long))
1425 : {
1426 : // Values of those 2 tags are repeated per sample, but should be
1427 : // at the same value.
1428 15211 : if (entry.tag == TagCode::SampleFormat)
1429 : {
1430 1191 : bool localOk = true;
1431 : const auto sampleFormat =
1432 1191 : static_cast<uint32_t>(readUIntTag(&entry, 0, localOk));
1433 1191 : if (localOk)
1434 : {
1435 1166 : m_sampleFormat = sampleFormat;
1436 : }
1437 : }
1438 14020 : else if (entry.tag == TagCode::BitsPerSample)
1439 : {
1440 1311 : bool localOk = true;
1441 : const auto bitsPerSample =
1442 1311 : static_cast<uint32_t>(readUIntTag(&entry, 0, localOk));
1443 1311 : if (localOk)
1444 : {
1445 1311 : m_bitsPerSample = bitsPerSample;
1446 : }
1447 : }
1448 : }
1449 17446 : }
1450 :
1451 : /** Final tag processing */
1452 1325 : void finalTagProcessing()
1453 : {
1454 1325 : m_strileOffsetsTag = tag(TagCode::TileOffsets);
1455 1325 : if (m_strileOffsetsTag)
1456 : {
1457 149 : m_strileByteCountsTag = tag(TagCode::TileByteCounts);
1458 149 : if (m_strileByteCountsTag &&
1459 149 : m_strileOffsetsTag->count == m_strileByteCountsTag->count)
1460 : {
1461 149 : m_isTiled = true;
1462 149 : m_strileCount = m_strileOffsetsTag->count;
1463 : }
1464 : }
1465 : else
1466 : {
1467 1176 : m_strileOffsetsTag = tag(TagCode::StripOffsets);
1468 1176 : if (m_strileOffsetsTag)
1469 : {
1470 1153 : m_strileByteCountsTag = tag(TagCode::StripByteCounts);
1471 1153 : if (m_strileByteCountsTag &&
1472 1130 : m_strileOffsetsTag->count == m_strileByteCountsTag->count)
1473 : {
1474 1095 : m_strileCount = m_strileOffsetsTag->count;
1475 : }
1476 : }
1477 : }
1478 1325 : }
1479 :
1480 : /** Read a value from a byte/short/long/long8 array tag */
1481 18528 : uint64_t readUIntTag(const TagEntry *tag, uint64_t idx, bool &ok) const
1482 : {
1483 18528 : if (tag && idx < tag->count)
1484 : {
1485 18504 : if (tag->type == TagType::Byte)
1486 : {
1487 7 : if (tag->count <= (m_isBigTIFF ? 8 : 4))
1488 : {
1489 7 : return tag->uint8Values[size_t(idx)];
1490 : }
1491 0 : return m_rc->read<uint8_t>(
1492 0 : tag->value_offset + sizeof(uint8_t) * idx, ok);
1493 : }
1494 18497 : else if (tag->type == TagType::Short)
1495 : {
1496 9031 : if (tag->count <= (m_isBigTIFF ? 4 : 2))
1497 : {
1498 1947 : return tag->uint16Values[size_t(idx)];
1499 : }
1500 7084 : return m_rc->read<uint16_t>(
1501 7100 : tag->value_offset + sizeof(uint16_t) * idx, ok);
1502 : }
1503 9466 : else if (tag->type == TagType::Long)
1504 : {
1505 9386 : if (tag->count <= (m_isBigTIFF ? 2 : 1))
1506 : {
1507 1356 : return tag->uint32Values[size_t(idx)];
1508 : }
1509 8030 : return m_rc->read<uint32_t>(
1510 8008 : tag->value_offset + sizeof(uint32_t) * idx, ok);
1511 : }
1512 80 : else if (m_isBigTIFF && tag->type == TagType::Long8)
1513 : {
1514 53 : if (tag->count <= 1)
1515 : {
1516 24 : return tag->uint64Values[size_t(idx)];
1517 : }
1518 29 : return m_rc->read<uint64_t>(
1519 29 : tag->value_offset + sizeof(uint64_t) * idx, ok);
1520 : }
1521 : }
1522 51 : ok = false;
1523 51 : return 0;
1524 : }
1525 :
1526 : template <class DataOrOffsetType>
1527 17402 : void ParseTagEntryDataOrOffset(TagEntry &entry, uint64_t &offset,
1528 : bool &singleValueFitsInUInt32,
1529 : uint32_t &singleValue, bool &ok)
1530 : {
1531 : LIBERTIFF_STATIC_ASSERT(
1532 : (std::is_same<DataOrOffsetType, uint32_t>::value ||
1533 : std::is_same<DataOrOffsetType, uint64_t>::value));
1534 17402 : assert(entry.count > 0);
1535 :
1536 17402 : const uint32_t dataTypeSize = tagTypeSize(entry.type);
1537 17402 : if (dataTypeSize == 0)
1538 : {
1539 573 : return;
1540 : }
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 16829 : if (dataTypeSize > sizeof(DataOrOffsetType) / entry.count)
1548 : {
1549 : // Out-of-line values. We read a file offset
1550 3258 : entry.value_offset = m_rc->read<DataOrOffsetType>(offset, ok);
1551 3258 : if (entry.value_offset == 0)
1552 : {
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 16 : ok = false;
1557 16 : return;
1558 : }
1559 6484 : if (dataTypeSize >
1560 3242 : std::numeric_limits<uint64_t>::max() / entry.count)
1561 : {
1562 1 : entry.invalid_value_offset = true;
1563 : }
1564 : else
1565 : {
1566 3241 : 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 3241 : constexpr uint32_t THRESHOLD_CHECK_FILE_SIZE = 10 * 1000 * 1000;
1571 :
1572 3241 : entry.invalid_value_offset =
1573 3318 : (byteCount > THRESHOLD_CHECK_FILE_SIZE &&
1574 77 : (m_rc->size() < byteCount ||
1575 3 : entry.value_offset > m_rc->size() - byteCount));
1576 : }
1577 : }
1578 13571 : else if (dataTypeSize == sizeof(uint8_t))
1579 : {
1580 : // Read up to 4 (classic) or 8 (BigTIFF) inline bytes
1581 39 : m_rc->read(offset, size_t(entry.count), &entry.uint8Values[0], ok);
1582 39 : if (entry.count == 1 && entry.type == TagType::Byte)
1583 : {
1584 13 : singleValueFitsInUInt32 = true;
1585 13 : singleValue = entry.uint8Values[0];
1586 : }
1587 : }
1588 13532 : else if (dataTypeSize == sizeof(uint16_t))
1589 : {
1590 : // Read up to 2 (classic) or 4 (BigTIFF) inline 16-bit values
1591 11423 : assert(entry.count <= 4);
1592 22924 : for (uint32_t idx = 0; idx < entry.count; ++idx)
1593 : {
1594 11501 : entry.uint16Values[idx] =
1595 11501 : m_rc->read<uint16_t>(offset + idx * sizeof(uint16_t), ok);
1596 : }
1597 11423 : if (entry.count == 1 && entry.type == TagType::Short)
1598 : {
1599 11353 : singleValueFitsInUInt32 = true;
1600 11353 : singleValue = entry.uint16Values[0];
1601 : }
1602 : }
1603 2109 : else if (dataTypeSize == sizeof(uint32_t))
1604 : {
1605 : // Read up to 1 (classic) or 2 (BigTIFF) inline 32-bit values
1606 2087 : entry.uint32Values[0] = m_rc->read<uint32_t>(offset, ok);
1607 2087 : if (entry.count == 1 && entry.type == TagType::Long)
1608 : {
1609 2079 : singleValueFitsInUInt32 = true;
1610 2079 : singleValue = entry.uint32Values[0];
1611 : }
1612 : if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType,
1613 : uint64_t>::value)
1614 : {
1615 16 : if (entry.count == 2)
1616 : {
1617 8 : entry.uint32Values[1] =
1618 8 : m_rc->read<uint32_t>(offset + sizeof(uint32_t), ok);
1619 : }
1620 : }
1621 : }
1622 : else if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType,
1623 : uint64_t>::value)
1624 : {
1625 22 : if (dataTypeSize == sizeof(uint64_t))
1626 : {
1627 : // Read one inline 64-bit value
1628 22 : if (entry.type == TagType::Rational)
1629 0 : entry.float64Values[0] = m_rc->readRational(offset, ok);
1630 22 : else if (entry.type == TagType::SRational)
1631 0 : entry.float64Values[0] =
1632 0 : m_rc->readSignedRational(offset, ok);
1633 : else
1634 22 : entry.uint64Values[0] = m_rc->read<uint64_t>(offset, ok);
1635 : }
1636 : else
1637 : {
1638 0 : assert(false);
1639 : }
1640 : }
1641 : else
1642 : {
1643 : // fprintf(stderr, "Unexpected case: tag=%u, dataType=%u, count=%u\n", entry.tag, entry.type, entry.count);
1644 0 : assert(false);
1645 : }
1646 :
1647 16813 : offset += sizeof(DataOrOffsetType);
1648 : }
1649 : };
1650 :
1651 : /** Open a TIFF file and return its first Image File Directory
1652 : */
1653 : template <bool acceptBigTIFF = true>
1654 1342 : std::unique_ptr<const Image> open(const std::shared_ptr<const FileReader> &file)
1655 : {
1656 1342 : unsigned char signature[2] = {0, 0};
1657 1342 : (void)file->read(0, 2, signature);
1658 1342 : const bool littleEndian = signature[0] == 'I' && signature[1] == 'I';
1659 1342 : const bool bigEndian = signature[0] == 'M' && signature[1] == 'M';
1660 1342 : if (!littleEndian && !bigEndian)
1661 0 : return nullptr;
1662 :
1663 1342 : const bool mustByteSwap = littleEndian ^ isHostLittleEndian();
1664 :
1665 2684 : auto rc = std::make_shared<ReadContext>(file, mustByteSwap);
1666 1342 : bool ok = true;
1667 1342 : const int version = rc->read<uint16_t>(2, ok);
1668 1342 : constexpr int CLASSIC_TIFF_VERSION = 42;
1669 1342 : if (version == CLASSIC_TIFF_VERSION)
1670 : {
1671 1313 : const auto firstImageOffset = rc->read<uint32_t>(4, ok);
1672 1313 : return Image::open<false>(rc, firstImageOffset, {});
1673 : }
1674 : else if LIBERTIFF_CONSTEXPR (acceptBigTIFF)
1675 : {
1676 29 : constexpr int BIGTIFF_VERSION = 43;
1677 29 : if (version == BIGTIFF_VERSION)
1678 : {
1679 29 : const auto byteSizeOfOffsets = rc->read<uint16_t>(4, ok);
1680 29 : if (byteSizeOfOffsets != 8)
1681 0 : return nullptr;
1682 29 : const auto zeroWord = rc->read<uint16_t>(6, ok);
1683 29 : if (zeroWord != 0 || !ok)
1684 0 : return nullptr;
1685 29 : const auto firstImageOffset = rc->read<uint64_t>(8, ok);
1686 29 : return Image::open<true>(rc, firstImageOffset, {});
1687 : }
1688 : }
1689 :
1690 0 : return nullptr;
1691 : }
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
|