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 6424 : inline bool mustByteSwap() const
216 : {
217 6424 : 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 7843 : void read(uint64_t offset, size_t count, void *buffer, bool &ok) const
228 : {
229 7843 : if (m_file->read(offset, count, buffer) != count)
230 17 : ok = false;
231 7846 : }
232 :
233 : /** Read single value at offset */
234 89797 : 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 89797 : T res = 0;
246 89797 : 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 89623 : if (m_mustByteSwap)
254 8861 : res = byteSwap(res);
255 : }
256 89623 : 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 14352 : const std::shared_ptr<const ReadContext> &readContext() const
931 : {
932 14352 : 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 155783 : inline uint32_t bitsPerSample() const
982 : {
983 155783 : return m_bitsPerSample;
984 : }
985 :
986 : /** Return number of samples (a.k.a. channels, bands) per pixel */
987 5175 : inline uint32_t samplesPerPixel() const
988 : {
989 5175 : 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 78874 : inline CompressionType compression() const
1006 : {
1007 78874 : return m_compression;
1008 : }
1009 :
1010 : /** Return predictor value (used for Deflate, LZW, ZStd, etc. compression) */
1011 15156 : inline uint32_t predictor() const
1012 : {
1013 15156 : return m_predictor;
1014 : }
1015 :
1016 : /** Return sample format */
1017 1309 : inline SampleFormatType sampleFormat() const
1018 : {
1019 1309 : 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 26293 : inline bool isTiled() const
1043 : {
1044 26293 : return m_isTiled;
1045 : }
1046 :
1047 : /** Return tile width */
1048 402 : inline uint32_t tileWidth() const
1049 : {
1050 402 : return m_tileWidth;
1051 : }
1052 :
1053 : /** Return tile width */
1054 398 : inline uint32_t tileHeight() const
1055 : {
1056 398 : return m_tileHeight;
1057 : }
1058 :
1059 : /** Return number of tiles per row */
1060 6444 : uint32_t tilesPerRow() const
1061 : {
1062 6444 : if (m_tileWidth > 0)
1063 : {
1064 6441 : return uint32_t((uint64_t(m_width) + m_tileWidth - 1) /
1065 6441 : m_tileWidth);
1066 : }
1067 3 : 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 6442 : return uint32_t((uint64_t(m_height) + m_tileHeight - 1) /
1076 6442 : 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 6445 : const uint32_t lTilesPerRow = tilesPerRow();
1088 6442 : const uint32_t lTilesPerCol = tilesPerCol();
1089 6439 : if (xtile >= lTilesPerRow || ytile >= lTilesPerCol)
1090 : {
1091 0 : ok = false;
1092 0 : return 0;
1093 : }
1094 6439 : uint64_t idx = uint64_t(ytile) * lTilesPerRow + xtile;
1095 6439 : if (bandIdx &&
1096 3677 : m_planarConfiguration == PlanarConfiguration::Separate)
1097 : {
1098 3678 : const uint64_t lTotalTiles =
1099 3678 : uint64_t(lTilesPerCol) * lTilesPerRow;
1100 3678 : if (lTotalTiles >
1101 3678 : std::numeric_limits<uint64_t>::max() / bandIdx)
1102 : {
1103 0 : ok = false;
1104 0 : return 0;
1105 : }
1106 3678 : idx += bandIdx * lTotalTiles;
1107 : }
1108 6439 : return idx;
1109 : }
1110 1 : ok = false;
1111 1 : return 0;
1112 : }
1113 :
1114 : /** Return the offset of strip/tile of index idx */
1115 8105 : uint64_t strileOffset(uint64_t idx, bool &ok) const
1116 : {
1117 8105 : return readUIntTag(m_strileOffsetsTag, idx, ok);
1118 : }
1119 :
1120 : /** Return the offset of a tile from its coordinates */
1121 : uint64_t tileOffset(uint32_t xtile, uint32_t ytile, uint32_t bandIdx,
1122 : bool &ok) const
1123 : {
1124 : const auto idx = tileCoordinateToIdx(xtile, ytile, bandIdx, ok);
1125 : return ok ? strileOffset(idx, ok) : 0;
1126 : }
1127 :
1128 : /** Return the byte count of strip/tile of index idx */
1129 8024 : uint64_t strileByteCount(uint64_t idx, bool &ok) const
1130 : {
1131 8024 : return readUIntTag(m_strileByteCountsTag, idx, ok);
1132 : }
1133 :
1134 : /** Return the offset of a tile from its coordinates */
1135 : uint64_t tileByteCount(uint32_t xtile, uint32_t ytile, uint32_t bandIdx,
1136 : bool &ok) const
1137 : {
1138 : const auto idx = tileCoordinateToIdx(xtile, ytile, bandIdx, ok);
1139 : return ok ? strileByteCount(idx, ok) : 0;
1140 : }
1141 :
1142 : /** Return the list of tags */
1143 : inline const std::vector<TagEntry> &tags() const
1144 : {
1145 : return m_tags;
1146 : }
1147 :
1148 : /** Return the (first) tag corresponding to a code, or nullptr if not found */
1149 16533 : const TagEntry *tag(TagCodeType tagCode) const
1150 : {
1151 211497 : for (const auto &tag : m_tags)
1152 : {
1153 198972 : if (tag.tag == tagCode)
1154 4008 : return &tag;
1155 : }
1156 12525 : return nullptr;
1157 : }
1158 :
1159 : /** Read an ASCII tag as a string */
1160 116 : std::string readTagAsString(const TagEntry &tag, bool &ok) const
1161 : {
1162 116 : if (tag.type == TagType::ASCII)
1163 : {
1164 116 : if (tag.value_offset)
1165 : {
1166 : if LIBERTIFF_CONSTEXPR (sizeof(tag.count) > sizeof(size_t))
1167 : {
1168 : // coverity[result_independent_of_operands]
1169 : if (tag.count > std::numeric_limits<size_t>::max())
1170 : {
1171 : ok = false;
1172 : return std::string();
1173 : }
1174 : }
1175 94 : return readContext()->readString(
1176 94 : tag.value_offset, static_cast<size_t>(tag.count), ok);
1177 : }
1178 22 : if (tag.count)
1179 : {
1180 : std::string res(tag.charValues.data(),
1181 44 : static_cast<size_t>(tag.count));
1182 22 : if (res.back() == 0)
1183 22 : res.pop_back();
1184 22 : return res;
1185 : }
1186 : }
1187 0 : ok = false;
1188 0 : return std::string();
1189 : }
1190 :
1191 : /** Read a numeric tag as a vector. You must use a type T which is
1192 : * consistent with the tag.type value. For example, if
1193 : * tag.type == libertiff::TagType::Short, T must be uint16_t.
1194 : * libertiff::TagType::Undefined must be read with T=uint8_t.
1195 : */
1196 : template <class T>
1197 1083 : std::vector<T> readTagAsVector(const TagEntry &tag, bool &ok) const
1198 : {
1199 1083 : return detail::readTagAsVector<T>(*(m_rc.get()), tag, ok);
1200 : }
1201 :
1202 : /** Returns a new Image instance for the IFD starting at offset imageOffset */
1203 : template <bool isBigTIFF>
1204 : static std::unique_ptr<const Image>
1205 2285 : open(const std::shared_ptr<const ReadContext> &rc,
1206 : const uint64_t imageOffset,
1207 : const std::set<uint64_t> &alreadyVisitedImageOffsets =
1208 : std::set<uint64_t>())
1209 : {
1210 : // To prevent infinite looping on corrupted files
1211 3727 : if (imageOffset == 0 || alreadyVisitedImageOffsets.find(imageOffset) !=
1212 3727 : alreadyVisitedImageOffsets.end())
1213 : {
1214 843 : return nullptr;
1215 : }
1216 :
1217 2884 : auto image = LIBERTIFF_NS::make_unique<Image>(rc, isBigTIFF);
1218 :
1219 1442 : image->m_offset = imageOffset;
1220 1442 : image->m_alreadyVisitedImageOffsets = alreadyVisitedImageOffsets;
1221 1442 : image->m_alreadyVisitedImageOffsets.insert(imageOffset);
1222 :
1223 1442 : bool ok = true;
1224 1442 : int tagCount = 0;
1225 1442 : uint64_t offset = imageOffset;
1226 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1227 : {
1228 : // To prevent unsigned integer overflows in later additions. The
1229 : // theoretical max should be much closer to UINT64_MAX, but half of
1230 : // it is already more than needed in practice :-)
1231 29 : if (offset >= std::numeric_limits<uint64_t>::max() / 2)
1232 0 : return nullptr;
1233 :
1234 29 : const auto tagCount64Bit = rc->read<uint64_t>(offset, ok);
1235 : // Artificially limit to the same number of entries as ClassicTIFF
1236 29 : if (tagCount64Bit > std::numeric_limits<uint16_t>::max())
1237 0 : return nullptr;
1238 29 : tagCount = static_cast<int>(tagCount64Bit);
1239 29 : offset += sizeof(uint64_t);
1240 : }
1241 : else
1242 : {
1243 1413 : tagCount = rc->read<uint16_t>(offset, ok);
1244 1413 : offset += sizeof(uint16_t);
1245 : }
1246 1442 : if (!ok)
1247 78 : return nullptr;
1248 1364 : image->m_tags.reserve(tagCount);
1249 : // coverity[tainted_data]
1250 18736 : for (int i = 0; i < tagCount; ++i)
1251 : {
1252 17415 : TagEntry entry;
1253 :
1254 : // Read tag code
1255 17415 : entry.tag = rc->read<uint16_t>(offset, ok);
1256 17415 : offset += sizeof(uint16_t);
1257 :
1258 : // Read tag data type
1259 17415 : entry.type = rc->read<uint16_t>(offset, ok);
1260 17415 : offset += sizeof(uint16_t);
1261 :
1262 : // Read number of values
1263 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1264 : {
1265 327 : auto count = rc->read<uint64_t>(offset, ok);
1266 327 : entry.count = count;
1267 327 : offset += sizeof(count);
1268 : }
1269 : else
1270 : {
1271 17088 : auto count = rc->read<uint32_t>(offset, ok);
1272 17088 : entry.count = count;
1273 17088 : offset += sizeof(count);
1274 : }
1275 :
1276 17415 : uint32_t singleValue = 0;
1277 17415 : bool singleValueFitsInUInt32 = false;
1278 17415 : if (entry.count)
1279 : {
1280 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1281 : {
1282 327 : image->ParseTagEntryDataOrOffset<uint64_t>(
1283 : entry, offset, singleValueFitsInUInt32, singleValue,
1284 : ok);
1285 : }
1286 : else
1287 : {
1288 17001 : image->ParseTagEntryDataOrOffset<uint32_t>(
1289 : entry, offset, singleValueFitsInUInt32, singleValue,
1290 : ok);
1291 : }
1292 : }
1293 17415 : if (!ok)
1294 43 : return nullptr;
1295 :
1296 17372 : image->processTag(entry, singleValueFitsInUInt32, singleValue);
1297 :
1298 17372 : image->m_tags.push_back(entry);
1299 : }
1300 :
1301 1321 : image->finalTagProcessing();
1302 :
1303 : if LIBERTIFF_CONSTEXPR (isBigTIFF)
1304 29 : image->m_nextImageOffset = rc->read<uint64_t>(offset, ok);
1305 : else
1306 1292 : image->m_nextImageOffset = rc->read<uint32_t>(offset, ok);
1307 :
1308 1321 : image->m_openFunc = open<isBigTIFF>;
1309 :
1310 1321 : return std::unique_ptr<const Image>(image.release());
1311 : }
1312 :
1313 : /** Returns a new Image instance at the next IFD, or nullptr if there is none */
1314 947 : std::unique_ptr<const Image> next() const
1315 : {
1316 947 : return m_openFunc(m_rc, m_nextImageOffset,
1317 947 : m_alreadyVisitedImageOffsets);
1318 : }
1319 :
1320 : private:
1321 : const std::shared_ptr<const ReadContext> m_rc;
1322 : std::unique_ptr<const Image> (*m_openFunc)(
1323 : const std::shared_ptr<const ReadContext> &, const uint64_t,
1324 : const std::set<uint64_t> &) = nullptr;
1325 :
1326 : std::set<uint64_t> m_alreadyVisitedImageOffsets{};
1327 : uint64_t m_offset = 0;
1328 : uint64_t m_nextImageOffset = 0;
1329 : uint32_t m_subFileType = 0;
1330 : uint32_t m_width = 0;
1331 : uint32_t m_height = 0;
1332 : uint32_t m_bitsPerSample = 0;
1333 : uint32_t m_samplesPerPixel = 0;
1334 : uint32_t m_rowsPerStrip = 0;
1335 : CompressionType m_compression = Compression::None;
1336 : SampleFormatType m_sampleFormat = SampleFormat::UnsignedInt;
1337 : PlanarConfigurationType m_planarConfiguration =
1338 : PlanarConfiguration::Contiguous;
1339 : PhotometricInterpretationType m_photometricInterpretation =
1340 : PhotometricInterpretation::MinIsBlack;
1341 : uint32_t m_predictor = 0;
1342 :
1343 : const bool m_isBigTIFF;
1344 : bool m_isTiled = false;
1345 : uint32_t m_tileWidth = 0;
1346 : uint32_t m_tileHeight = 0;
1347 : uint64_t m_strileCount = 0;
1348 :
1349 : std::vector<TagEntry> m_tags{};
1350 : const TagEntry *m_strileOffsetsTag = nullptr;
1351 : const TagEntry *m_strileByteCountsTag = nullptr;
1352 :
1353 : Image(const Image &) = delete;
1354 : Image &operator=(const Image &) = delete;
1355 :
1356 : /** Process tag */
1357 17372 : void processTag(const TagEntry &entry, bool singleValueFitsInUInt32,
1358 : uint32_t singleValue)
1359 : {
1360 17372 : if (singleValueFitsInUInt32)
1361 : {
1362 13411 : switch (entry.tag)
1363 : {
1364 27 : case TagCode::SubFileType:
1365 27 : m_subFileType = singleValue;
1366 27 : break;
1367 :
1368 1319 : case TagCode::ImageWidth:
1369 1319 : m_width = singleValue;
1370 1319 : break;
1371 :
1372 1309 : case TagCode::ImageLength:
1373 1309 : m_height = singleValue;
1374 1309 : break;
1375 :
1376 1296 : case TagCode::Compression:
1377 1296 : m_compression = singleValue;
1378 1296 : break;
1379 :
1380 1275 : case TagCode::SamplesPerPixel:
1381 1275 : m_samplesPerPixel = singleValue;
1382 1275 : break;
1383 :
1384 1125 : case TagCode::RowsPerStrip:
1385 1125 : m_rowsPerStrip = singleValue;
1386 1125 : break;
1387 :
1388 1273 : case TagCode::PlanarConfiguration:
1389 1273 : m_planarConfiguration = singleValue;
1390 1273 : break;
1391 :
1392 1293 : case TagCode::PhotometricInterpretation:
1393 1293 : m_photometricInterpretation = singleValue;
1394 1293 : break;
1395 :
1396 113 : case TagCode::Predictor:
1397 113 : m_predictor = singleValue;
1398 113 : break;
1399 :
1400 149 : case TagCode::TileWidth:
1401 149 : m_tileWidth = singleValue;
1402 149 : break;
1403 :
1404 149 : case TagCode::TileLength:
1405 149 : m_tileHeight = singleValue;
1406 149 : break;
1407 :
1408 4083 : default:
1409 4083 : break;
1410 : }
1411 : }
1412 :
1413 17372 : if (entry.count &&
1414 17312 : (entry.type == TagType::Byte || entry.type == TagType::Short ||
1415 4655 : entry.type == TagType::Long))
1416 : {
1417 : // Values of those 2 tags are repeated per sample, but should be
1418 : // at the same value.
1419 15158 : if (entry.tag == TagCode::SampleFormat)
1420 : {
1421 1187 : bool localOk = true;
1422 : const auto sampleFormat =
1423 1187 : static_cast<uint32_t>(readUIntTag(&entry, 0, localOk));
1424 1187 : if (localOk)
1425 : {
1426 1186 : m_sampleFormat = sampleFormat;
1427 : }
1428 : }
1429 13971 : else if (entry.tag == TagCode::BitsPerSample)
1430 : {
1431 1307 : bool localOk = true;
1432 : const auto bitsPerSample =
1433 1307 : static_cast<uint32_t>(readUIntTag(&entry, 0, localOk));
1434 1307 : if (localOk)
1435 : {
1436 1307 : m_bitsPerSample = bitsPerSample;
1437 : }
1438 : }
1439 : }
1440 17372 : }
1441 :
1442 : /** Final tag processing */
1443 1321 : void finalTagProcessing()
1444 : {
1445 1321 : m_strileOffsetsTag = tag(TagCode::TileOffsets);
1446 1321 : if (m_strileOffsetsTag)
1447 : {
1448 149 : m_strileByteCountsTag = tag(TagCode::TileByteCounts);
1449 149 : if (m_strileByteCountsTag &&
1450 149 : m_strileOffsetsTag->count == m_strileByteCountsTag->count)
1451 : {
1452 149 : m_isTiled = true;
1453 149 : m_strileCount = m_strileOffsetsTag->count;
1454 : }
1455 : }
1456 : else
1457 : {
1458 1172 : m_strileOffsetsTag = tag(TagCode::StripOffsets);
1459 1172 : if (m_strileOffsetsTag)
1460 : {
1461 1149 : m_strileByteCountsTag = tag(TagCode::StripByteCounts);
1462 1149 : if (m_strileByteCountsTag &&
1463 1126 : m_strileOffsetsTag->count == m_strileByteCountsTag->count)
1464 : {
1465 1091 : m_strileCount = m_strileOffsetsTag->count;
1466 : }
1467 : }
1468 : }
1469 1321 : }
1470 :
1471 : /** Read a value from a byte/short/long/long8 array tag */
1472 18622 : uint64_t readUIntTag(const TagEntry *tag, uint64_t idx, bool &ok) const
1473 : {
1474 18622 : if (tag && idx < tag->count)
1475 : {
1476 18584 : if (tag->type == TagType::Byte)
1477 : {
1478 7 : if (tag->count <= (m_isBigTIFF ? 8 : 4))
1479 : {
1480 7 : return tag->uint8Values[size_t(idx)];
1481 : }
1482 0 : return m_rc->read<uint8_t>(
1483 0 : tag->value_offset + sizeof(uint8_t) * idx, ok);
1484 : }
1485 18577 : else if (tag->type == TagType::Short)
1486 : {
1487 9129 : if (tag->count <= (m_isBigTIFF ? 4 : 2))
1488 : {
1489 1947 : return tag->uint16Values[size_t(idx)];
1490 : }
1491 7182 : return m_rc->read<uint16_t>(
1492 7186 : tag->value_offset + sizeof(uint16_t) * idx, ok);
1493 : }
1494 9448 : else if (tag->type == TagType::Long)
1495 : {
1496 9384 : if (tag->count <= (m_isBigTIFF ? 2 : 1))
1497 : {
1498 1354 : return tag->uint32Values[size_t(idx)];
1499 : }
1500 8030 : return m_rc->read<uint32_t>(
1501 8032 : tag->value_offset + sizeof(uint32_t) * idx, ok);
1502 : }
1503 64 : else if (m_isBigTIFF && tag->type == TagType::Long8)
1504 : {
1505 53 : if (tag->count <= 1)
1506 : {
1507 24 : return tag->uint64Values[size_t(idx)];
1508 : }
1509 29 : return m_rc->read<uint64_t>(
1510 29 : tag->value_offset + sizeof(uint64_t) * idx, ok);
1511 : }
1512 : }
1513 49 : ok = false;
1514 49 : return 0;
1515 : }
1516 :
1517 : template <class DataOrOffsetType>
1518 17328 : void ParseTagEntryDataOrOffset(TagEntry &entry, uint64_t &offset,
1519 : bool &singleValueFitsInUInt32,
1520 : uint32_t &singleValue, bool &ok)
1521 : {
1522 : LIBERTIFF_STATIC_ASSERT(
1523 : (std::is_same<DataOrOffsetType, uint32_t>::value ||
1524 : std::is_same<DataOrOffsetType, uint64_t>::value));
1525 17328 : assert(entry.count > 0);
1526 :
1527 17328 : const uint32_t dataTypeSize = tagTypeSize(entry.type);
1528 17328 : if (dataTypeSize == 0)
1529 : {
1530 573 : return;
1531 : }
1532 :
1533 : // There are 2 cases:
1534 : // - either the number of values for the data type can fit
1535 : // in the next DataOrOffsetType bytes
1536 : // - or it cannot, and then the next DataOrOffsetType bytes are an offset
1537 : // to the values
1538 16755 : if (dataTypeSize > sizeof(DataOrOffsetType) / entry.count)
1539 : {
1540 : // Out-of-line values. We read a file offset
1541 3219 : entry.value_offset = m_rc->read<DataOrOffsetType>(offset, ok);
1542 3219 : if (entry.value_offset == 0)
1543 : {
1544 : // value_offset = 0 for a out-of-line tag is obviously
1545 : // wrong and would cause later confusion in readTagAsVector<>,
1546 : // so better reject the file.
1547 16 : ok = false;
1548 16 : return;
1549 : }
1550 6406 : if (dataTypeSize >
1551 3203 : std::numeric_limits<uint64_t>::max() / entry.count)
1552 : {
1553 1 : entry.invalid_value_offset = true;
1554 : }
1555 : else
1556 : {
1557 3202 : const uint64_t byteCount = uint64_t(dataTypeSize) * entry.count;
1558 :
1559 : // Size of tag data beyond which we check the tag position and size
1560 : // w.r.t the file size.
1561 3202 : constexpr uint32_t THRESHOLD_CHECK_FILE_SIZE = 10 * 1000 * 1000;
1562 :
1563 3202 : entry.invalid_value_offset =
1564 3279 : (byteCount > THRESHOLD_CHECK_FILE_SIZE &&
1565 77 : (m_rc->size() < byteCount ||
1566 3 : entry.value_offset > m_rc->size() - byteCount));
1567 : }
1568 : }
1569 13536 : else if (dataTypeSize == sizeof(uint8_t))
1570 : {
1571 : // Read up to 4 (classic) or 8 (BigTIFF) inline bytes
1572 38 : m_rc->read(offset, size_t(entry.count), &entry.uint8Values[0], ok);
1573 38 : if (entry.count == 1 && entry.type == TagType::Byte)
1574 : {
1575 13 : singleValueFitsInUInt32 = true;
1576 13 : singleValue = entry.uint8Values[0];
1577 : }
1578 : }
1579 13498 : else if (dataTypeSize == sizeof(uint16_t))
1580 : {
1581 : // Read up to 2 (classic) or 4 (BigTIFF) inline 16-bit values
1582 22860 : for (uint32_t idx = 0; idx < entry.count; ++idx)
1583 : {
1584 11469 : entry.uint16Values[idx] =
1585 11469 : m_rc->read<uint16_t>(offset + idx * sizeof(uint16_t), ok);
1586 : }
1587 11391 : if (entry.count == 1 && entry.type == TagType::Short)
1588 : {
1589 11321 : singleValueFitsInUInt32 = true;
1590 11321 : singleValue = entry.uint16Values[0];
1591 : }
1592 : }
1593 2107 : else if (dataTypeSize == sizeof(uint32_t))
1594 : {
1595 : // Read up to 1 (classic) or 2 (BigTIFF) inline 32-bit values
1596 2085 : entry.uint32Values[0] = m_rc->read<uint32_t>(offset, ok);
1597 2085 : if (entry.count == 1 && entry.type == TagType::Long)
1598 : {
1599 2077 : singleValueFitsInUInt32 = true;
1600 2077 : singleValue = entry.uint32Values[0];
1601 : }
1602 : if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType,
1603 : uint64_t>::value)
1604 : {
1605 16 : if (entry.count == 2)
1606 : {
1607 8 : entry.uint32Values[1] =
1608 8 : m_rc->read<uint32_t>(offset + sizeof(uint32_t), ok);
1609 : }
1610 : }
1611 : }
1612 : else if LIBERTIFF_CONSTEXPR (std::is_same<DataOrOffsetType,
1613 : uint64_t>::value)
1614 : {
1615 22 : if (dataTypeSize == sizeof(uint64_t))
1616 : {
1617 : // Read one inline 64-bit value
1618 22 : if (entry.type == TagType::Rational)
1619 0 : entry.float64Values[0] = m_rc->readRational(offset, ok);
1620 22 : else if (entry.type == TagType::SRational)
1621 0 : entry.float64Values[0] =
1622 0 : m_rc->readSignedRational(offset, ok);
1623 : else
1624 22 : entry.uint64Values[0] = m_rc->read<uint64_t>(offset, ok);
1625 : }
1626 : else
1627 : {
1628 0 : assert(false);
1629 : }
1630 : }
1631 : else
1632 : {
1633 : // fprintf(stderr, "Unexpected case: tag=%u, dataType=%u, count=%u\n", entry.tag, entry.type, entry.count);
1634 0 : assert(false);
1635 : }
1636 :
1637 16739 : offset += sizeof(DataOrOffsetType);
1638 : }
1639 : };
1640 :
1641 : /** Open a TIFF file and return its first Image File Directory
1642 : */
1643 : template <bool acceptBigTIFF = true>
1644 1338 : std::unique_ptr<const Image> open(const std::shared_ptr<const FileReader> &file)
1645 : {
1646 1338 : unsigned char signature[2] = {0, 0};
1647 1338 : (void)file->read(0, 2, signature);
1648 1338 : const bool littleEndian = signature[0] == 'I' && signature[1] == 'I';
1649 1338 : const bool bigEndian = signature[0] == 'M' && signature[1] == 'M';
1650 1338 : if (!littleEndian && !bigEndian)
1651 0 : return nullptr;
1652 :
1653 1338 : const bool mustByteSwap = littleEndian ^ isHostLittleEndian();
1654 :
1655 2676 : auto rc = std::make_shared<ReadContext>(file, mustByteSwap);
1656 1338 : bool ok = true;
1657 1338 : const int version = rc->read<uint16_t>(2, ok);
1658 1338 : constexpr int CLASSIC_TIFF_VERSION = 42;
1659 1338 : if (version == CLASSIC_TIFF_VERSION)
1660 : {
1661 1309 : const auto firstImageOffset = rc->read<uint32_t>(4, ok);
1662 1309 : return Image::open<false>(rc, firstImageOffset, {});
1663 : }
1664 : else if LIBERTIFF_CONSTEXPR (acceptBigTIFF)
1665 : {
1666 29 : constexpr int BIGTIFF_VERSION = 43;
1667 29 : if (version == BIGTIFF_VERSION)
1668 : {
1669 29 : const auto byteSizeOfOffsets = rc->read<uint16_t>(4, ok);
1670 29 : if (byteSizeOfOffsets != 8)
1671 0 : return nullptr;
1672 29 : const auto zeroWord = rc->read<uint16_t>(6, ok);
1673 29 : if (zeroWord != 0 || !ok)
1674 0 : return nullptr;
1675 29 : const auto firstImageOffset = rc->read<uint64_t>(8, ok);
1676 29 : return Image::open<true>(rc, firstImageOffset, {});
1677 : }
1678 : }
1679 :
1680 0 : return nullptr;
1681 : }
1682 : } // namespace LIBERTIFF_NS
1683 :
1684 : #ifdef LIBERTIFF_C_FILE_READER
1685 : #include <cstdio>
1686 : #include <mutex>
1687 :
1688 : namespace LIBERTIFF_NS
1689 : {
1690 : /** Interface to read from a FILE* handle */
1691 : class CFileReader final : public FileReader
1692 : {
1693 : public:
1694 : explicit CFileReader(FILE *f) : m_f(f)
1695 : {
1696 : }
1697 :
1698 : ~CFileReader() override
1699 : {
1700 : fclose(m_f);
1701 : }
1702 :
1703 : uint64_t size() const override
1704 : {
1705 : std::lock_guard<std::mutex> oLock(m_oMutex);
1706 : fseek(m_f, 0, SEEK_END);
1707 : return ftell(m_f);
1708 : }
1709 :
1710 : size_t read(uint64_t offset, size_t count, void *buffer) const override
1711 : {
1712 : std::lock_guard<std::mutex> oLock(m_oMutex);
1713 : if (fseek(m_f, static_cast<long>(offset), SEEK_SET) != 0)
1714 : return 0;
1715 : return fread(buffer, 1, count, m_f);
1716 : }
1717 :
1718 : private:
1719 : FILE *const m_f;
1720 : mutable std::mutex m_oMutex{};
1721 :
1722 : CFileReader(const CFileReader &) = delete;
1723 : CFileReader &operator=(const CFileReader &) = delete;
1724 : };
1725 : } // namespace LIBERTIFF_NS
1726 : #endif
1727 :
1728 : #endif // LIBERTIFF_HPP_INCLUDED
|