Coverage Report

Created: 2025-12-31 08:30

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