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