• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 13813968540

12 Mar 2025 02:33PM UTC coverage: 70.43% (-0.02%) from 70.446%
13813968540

Pull #11951

github

web-flow
Merge 0560ed8f8 into 5ab779ac6
Pull Request #11951: Doc: Build docs using CMake

553276 of 785573 relevant lines covered (70.43%)

222076.27 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

91.25
/frmts/gtiff/gtiffdataset_read.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GeoTIFF Driver
4
 * Purpose:  Read/get operations on GTiffDataset
5
 * Author:   Frank Warmerdam, warmerdam@pobox.com
6
 *
7
 ******************************************************************************
8
 * Copyright (c) 1998, 2002, Frank Warmerdam <warmerdam@pobox.com>
9
 * Copyright (c) 2007-2015, Even Rouault <even dot rouault at spatialys dot com>
10
 *
11
 * SPDX-License-Identifier: MIT
12
 ****************************************************************************/
13

14
#include "gtiffdataset.h"
15
#include "gtiffrasterband.h"
16
#include "gtiffjpegoverviewds.h"
17
#include "gtiffrgbaband.h"
18
#include "gtiffbitmapband.h"
19
#include "gtiffsplitband.h"
20
#include "gtiffsplitbitmapband.h"
21

22
#include <algorithm>
23
#include <cassert>
24
#include <limits>
25
#include <memory>
26
#include <mutex>
27
#include <set>
28
#include <string>
29
#include <queue>
30
#include <tuple>
31
#include <utility>
32

33
#include "cpl_error.h"
34
#include "cpl_error_internal.h"  // CPLErrorHandlerAccumulatorStruct
35
#include "cpl_vsi.h"
36
#include "cpl_vsi_virtual.h"
37
#include "cpl_worker_thread_pool.h"
38
#include "fetchbufferdirectio.h"
39
#include "gdal_mdreader.h"    // MD_DOMAIN_RPC
40
#include "geovalues.h"        // RasterPixelIsPoint
41
#include "gt_wkt_srs_priv.h"  // GDALGTIFKeyGetSHORT()
42
#include "tif_jxl.h"
43
#include "tifvsi.h"
44
#include "xtiffio.h"
45

46
#include "tiff_common.h"
47

48
/************************************************************************/
49
/*                        GetJPEGOverviewCount()                        */
50
/************************************************************************/
51

52
int GTiffDataset::GetJPEGOverviewCount()
643,628✔
53
{
54
    if (m_nJPEGOverviewCount >= 0)
643,628✔
55
        return m_nJPEGOverviewCount;
643,341✔
56

57
    m_nJPEGOverviewCount = 0;
287✔
58
    if (m_poBaseDS || eAccess != GA_ReadOnly ||
271✔
59
        m_nCompression != COMPRESSION_JPEG ||
224✔
60
        (nRasterXSize < 256 && nRasterYSize < 256) ||
22✔
61
        !CPLTestBool(CPLGetConfigOption("GTIFF_IMPLICIT_JPEG_OVR", "YES")) ||
580✔
62
        GDALGetDriverByName("JPEG") == nullptr)
22✔
63
    {
64
        return 0;
265✔
65
    }
66
    const char *pszSourceColorSpace =
67
        m_oGTiffMDMD.GetMetadataItem("SOURCE_COLOR_SPACE", "IMAGE_STRUCTURE");
22✔
68
    if (pszSourceColorSpace != nullptr && EQUAL(pszSourceColorSpace, "CMYK"))
22✔
69
    {
70
        // We cannot handle implicit overviews on JPEG CMYK datasets converted
71
        // to RGBA This would imply doing the conversion in
72
        // GTiffJPEGOverviewBand.
73
        return 0;
1✔
74
    }
75

76
    // libjpeg-6b only supports 2, 4 and 8 scale denominators.
77
    // TODO: Later versions support more.
78
    for (signed char i = 2; i >= 0; i--)
24✔
79
    {
80
        if (nRasterXSize >= (256 << i) || nRasterYSize >= (256 << i))
24✔
81
        {
82
            m_nJPEGOverviewCount = i + 1;
21✔
83
            break;
21✔
84
        }
85
    }
86
    if (m_nJPEGOverviewCount == 0)
21✔
87
        return 0;
×
88

89
    // Get JPEG tables.
90
    uint32_t nJPEGTableSize = 0;
21✔
91
    void *pJPEGTable = nullptr;
21✔
92
    GByte abyFFD8[] = {0xFF, 0xD8};
21✔
93
    if (TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable))
21✔
94
    {
95
        if (pJPEGTable == nullptr || nJPEGTableSize < 2 ||
20✔
96
            nJPEGTableSize > INT_MAX ||
20✔
97
            static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 1] != 0xD9)
20✔
98
        {
99
            m_nJPEGOverviewCount = 0;
×
100
            return 0;
×
101
        }
102
        nJPEGTableSize--;  // Remove final 0xD9.
20✔
103
    }
104
    else
105
    {
106
        pJPEGTable = abyFFD8;
1✔
107
        nJPEGTableSize = 2;
1✔
108
    }
109

110
    m_papoJPEGOverviewDS = static_cast<GTiffJPEGOverviewDS **>(
21✔
111
        CPLMalloc(sizeof(GTiffJPEGOverviewDS *) * m_nJPEGOverviewCount));
21✔
112
    for (int i = 0; i < m_nJPEGOverviewCount; ++i)
81✔
113
    {
114
        m_papoJPEGOverviewDS[i] = new GTiffJPEGOverviewDS(
60✔
115
            this, i + 1, pJPEGTable, static_cast<int>(nJPEGTableSize));
60✔
116
    }
117

118
    m_nJPEGOverviewCountOri = m_nJPEGOverviewCount;
21✔
119

120
    return m_nJPEGOverviewCount;
21✔
121
}
122

123
/************************************************************************/
124
/*                       GetCompressionFormats()                        */
125
/************************************************************************/
126

127
CPLStringList GTiffDataset::GetCompressionFormats(int nXOff, int nYOff,
6✔
128
                                                  int nXSize, int nYSize,
129
                                                  int nBandCount,
130
                                                  const int *panBandList)
131
{
132
    if (m_nCompression != COMPRESSION_NONE &&
18✔
133
        IsWholeBlock(nXOff, nYOff, nXSize, nYSize) &&
11✔
134
        ((nBandCount == 1 && (panBandList || nBands == 1) &&
3✔
135
          m_nPlanarConfig == PLANARCONFIG_SEPARATE) ||
3✔
136
         (IsAllBands(nBandCount, panBandList) &&
5✔
137
          m_nPlanarConfig == PLANARCONFIG_CONTIG)))
3✔
138
    {
139
        CPLStringList aosList;
6✔
140
        int nBlockId =
3✔
141
            (nXOff / m_nBlockXSize) + (nYOff / m_nBlockYSize) * m_nBlocksPerRow;
3✔
142
        if (m_nPlanarConfig == PLANARCONFIG_SEPARATE && panBandList != nullptr)
3✔
143
            nBlockId += panBandList[0] * m_nBlocksPerBand;
×
144

145
        vsi_l_offset nOffset = 0;
3✔
146
        vsi_l_offset nSize = 0;
3✔
147
        if (IsBlockAvailable(nBlockId, &nOffset, &nSize, nullptr) &&
6✔
148
            nSize <
3✔
149
                static_cast<vsi_l_offset>(std::numeric_limits<tmsize_t>::max()))
3✔
150
        {
151
            switch (m_nCompression)
3✔
152
            {
153
                case COMPRESSION_JPEG:
3✔
154
                {
155
                    if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands == 4 &&
3✔
156
                        m_nPhotometric == PHOTOMETRIC_RGB &&
7✔
157
                        GetRasterBand(4)->GetColorInterpretation() ==
1✔
158
                            GCI_AlphaBand)
159
                    {
160
                        // as a hint for the JPEG and JPEGXL drivers to not use it!
161
                        aosList.AddString("JPEG;colorspace=RGBA");
1✔
162
                    }
163
                    else
164
                    {
165
                        aosList.AddString("JPEG");
2✔
166
                    }
167
                    break;
3✔
168
                }
169

170
                case COMPRESSION_WEBP:
×
171
                    aosList.AddString("WEBP");
×
172
                    break;
×
173

174
                case COMPRESSION_JXL:
×
175
                    aosList.AddString("JXL");
×
176
                    break;
×
177

178
                default:
×
179
                    break;
×
180
            }
181
        }
182
        return aosList;
3✔
183
    }
184
    return CPLStringList();
3✔
185
}
186

187
/************************************************************************/
188
/*                       ReadCompressedData()                           */
189
/************************************************************************/
190

191
CPLErr GTiffDataset::ReadCompressedData(const char *pszFormat, int nXOff,
76✔
192
                                        int nYOff, int nXSize, int nYSize,
193
                                        int nBandCount, const int *panBandList,
194
                                        void **ppBuffer, size_t *pnBufferSize,
195
                                        char **ppszDetailedFormat)
196
{
197
    if (m_nCompression != COMPRESSION_NONE &&
173✔
198
        IsWholeBlock(nXOff, nYOff, nXSize, nYSize) &&
96✔
199
        ((nBandCount == 1 && (panBandList != nullptr || nBands == 1) &&
8✔
200
          m_nPlanarConfig == PLANARCONFIG_SEPARATE) ||
8✔
201
         (IsAllBands(nBandCount, panBandList) &&
20✔
202
          m_nPlanarConfig == PLANARCONFIG_CONTIG)))
20✔
203
    {
204
        const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
12✔
205
        if (aosTokens.size() != 1)
12✔
206
            return CE_Failure;
×
207

208
        // We don't want to handle CMYK JPEG for now
209
        if ((m_nCompression == COMPRESSION_JPEG &&
35✔
210
             EQUAL(aosTokens[0], "JPEG") &&
11✔
211
             (m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
10✔
212
              m_nPhotometric != PHOTOMETRIC_SEPARATED)) ||
10✔
213
            (m_nCompression == COMPRESSION_WEBP &&
2✔
214
             EQUAL(aosTokens[0], "WEBP")) ||
24✔
215
            ((m_nCompression == COMPRESSION_JXL ||
2✔
216
              m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
2✔
217
             EQUAL(aosTokens[0], "JXL")))
1✔
218
        {
219
            std::string osDetailedFormat = aosTokens[0];
11✔
220

221
            int nBlockId = (nXOff / m_nBlockXSize) +
11✔
222
                           (nYOff / m_nBlockYSize) * m_nBlocksPerRow;
11✔
223
            if (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
11✔
224
                panBandList != nullptr)
225
                nBlockId += panBandList[0] * m_nBlocksPerBand;
×
226

227
            vsi_l_offset nOffset = 0;
11✔
228
            vsi_l_offset nSize = 0;
11✔
229
            if (IsBlockAvailable(nBlockId, &nOffset, &nSize, nullptr) &&
22✔
230
                nSize < static_cast<vsi_l_offset>(
11✔
231
                            std::numeric_limits<tmsize_t>::max()))
11✔
232
            {
233
                uint32_t nJPEGTableSize = 0;
11✔
234
                void *pJPEGTable = nullptr;
11✔
235
                if (m_nCompression == COMPRESSION_JPEG)
11✔
236
                {
237
                    if (TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES,
10✔
238
                                     &nJPEGTableSize, &pJPEGTable) &&
10✔
239
                        pJPEGTable != nullptr && nJPEGTableSize > 4 &&
10✔
240
                        static_cast<GByte *>(pJPEGTable)[0] == 0xFF &&
10✔
241
                        static_cast<GByte *>(pJPEGTable)[1] == 0xD8 &&
10✔
242
                        static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 2] ==
10✔
243
                            0xFF &&
20✔
244
                        static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 1] ==
10✔
245
                            0xD9)
246
                    {
247
                        pJPEGTable = static_cast<GByte *>(pJPEGTable) + 2;
10✔
248
                        nJPEGTableSize -= 4;
10✔
249
                    }
250
                    else
251
                    {
252
                        nJPEGTableSize = 0;
×
253
                    }
254
                }
255

256
                size_t nSizeSize = static_cast<size_t>(nSize + nJPEGTableSize);
11✔
257
                if (ppBuffer)
11✔
258
                {
259
                    if (!pnBufferSize)
9✔
260
                        return CE_Failure;
1✔
261
                    bool bFreeOnError = false;
8✔
262
                    if (*ppBuffer)
8✔
263
                    {
264
                        if (*pnBufferSize < nSizeSize)
3✔
265
                            return CE_Failure;
1✔
266
                    }
267
                    else
268
                    {
269
                        *ppBuffer = VSI_MALLOC_VERBOSE(nSizeSize);
5✔
270
                        if (*ppBuffer == nullptr)
5✔
271
                            return CE_Failure;
×
272
                        bFreeOnError = true;
5✔
273
                    }
274
                    const auto nTileSize = static_cast<tmsize_t>(nSize);
7✔
275
                    bool bOK;
276
                    if (TIFFIsTiled(m_hTIFF))
7✔
277
                    {
278
                        bOK = TIFFReadRawTile(m_hTIFF, nBlockId, *ppBuffer,
3✔
279
                                              nTileSize) == nTileSize;
280
                    }
281
                    else
282
                    {
283
                        bOK = TIFFReadRawStrip(m_hTIFF, nBlockId, *ppBuffer,
4✔
284
                                               nTileSize) == nTileSize;
285
                    }
286
                    if (!bOK)
7✔
287
                    {
288
                        if (bFreeOnError)
×
289
                        {
290
                            VSIFree(*ppBuffer);
×
291
                            *ppBuffer = nullptr;
×
292
                        }
293
                        return CE_Failure;
×
294
                    }
295
                    if (nJPEGTableSize > 0)
7✔
296
                    {
297
                        GByte *pabyBuffer = static_cast<GByte *>(*ppBuffer);
6✔
298
                        memmove(pabyBuffer + 2 + nJPEGTableSize, pabyBuffer + 2,
6✔
299
                                static_cast<size_t>(nSize) - 2);
6✔
300
                        memcpy(pabyBuffer + 2, pJPEGTable, nJPEGTableSize);
6✔
301
                    }
302

303
                    if (m_nCompression == COMPRESSION_JPEG)
7✔
304
                    {
305
                        osDetailedFormat = GDALGetCompressionFormatForJPEG(
12✔
306
                            *ppBuffer, nSizeSize);
6✔
307
                        const CPLStringList aosTokens2(CSLTokenizeString2(
308
                            osDetailedFormat.c_str(), ";", 0));
12✔
309
                        if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
18✔
310
                            nBands == 4 && m_nPhotometric == PHOTOMETRIC_RGB &&
7✔
311
                            GetRasterBand(4)->GetColorInterpretation() ==
1✔
312
                                GCI_AlphaBand)
313
                        {
314
                            osDetailedFormat = aosTokens2[0];
1✔
315
                            for (int i = 1; i < aosTokens2.size(); ++i)
5✔
316
                            {
317
                                if (!STARTS_WITH_CI(aosTokens2[i],
4✔
318
                                                    "colorspace="))
319
                                {
320
                                    osDetailedFormat += ';';
3✔
321
                                    osDetailedFormat += aosTokens2[i];
3✔
322
                                }
323
                            }
324
                            osDetailedFormat += ";colorspace=RGBA";
1✔
325
                        }
326
                    }
327
                }
328
                if (ppszDetailedFormat)
9✔
329
                    *ppszDetailedFormat = VSIStrdup(osDetailedFormat.c_str());
3✔
330
                if (pnBufferSize)
9✔
331
                    *pnBufferSize = nSizeSize;
8✔
332
                return CE_None;
9✔
333
            }
334
        }
335
    }
336
    return CE_Failure;
65✔
337
}
338

339
struct GTiffDecompressContext
340
{
341
    // The mutex must be recursive because ThreadDecompressionFuncErrorHandler()
342
    // which acquires the mutex can be called from a section where the mutex is
343
    // already acquired.
344
    std::recursive_mutex oMutex{};
345
    bool bSuccess = true;
346
    CPLErrorAccumulator oErrorAccumulator{};
347

348
    VSIVirtualHandle *poHandle = nullptr;
349
    GTiffDataset *poDS = nullptr;
350
    GDALDataType eDT = GDT_Unknown;
351
    int nXOff = 0;
352
    int nYOff = 0;
353
    int nXSize = 0;
354
    int nYSize = 0;
355
    int nBlockXStart = 0;
356
    int nBlockYStart = 0;
357
    int nBlockXEnd = 0;
358
    int nBlockYEnd = 0;
359
    GByte *pabyData = nullptr;
360
    GDALDataType eBufType = GDT_Unknown;
361
    int nBufDTSize = 0;
362
    int nBandCount = 0;
363
    const int *panBandMap = nullptr;
364
    GSpacing nPixelSpace = 0;
365
    GSpacing nLineSpace = 0;
366
    GSpacing nBandSpace = 0;
367
    bool bHasPRead = false;
368
    bool bCacheAllBands = false;
369
    bool bSkipBlockCache = false;
370
    bool bUseBIPOptim = false;
371
    bool bUseDeinterleaveOptimNoBlockCache = false;
372
    bool bUseDeinterleaveOptimBlockCache = false;
373
    bool bIsTiled = false;
374
    bool bTIFFIsBigEndian = false;
375
    int nBlocksPerRow = 0;
376

377
    uint16_t nPredictor = 0;
378

379
    uint32_t nJPEGTableSize = 0;
380
    void *pJPEGTable = nullptr;
381
    uint16_t nYCrbCrSubSampling0 = 2;
382
    uint16_t nYCrbCrSubSampling1 = 2;
383

384
    uint16_t *pExtraSamples = nullptr;
385
    uint16_t nExtraSampleCount = 0;
386
};
387

388
struct GTiffDecompressJob
389
{
390
    GTiffDecompressContext *psContext = nullptr;
391
    int iSrcBandIdxSeparate =
392
        0;  // in [0, GetRasterCount()-1] in PLANARCONFIG_SEPARATE, or -1 in PLANARCONFIG_CONTIG
393
    int iDstBandIdxSeparate =
394
        0;  // in [0, nBandCount-1] in PLANARCONFIG_SEPARATE, or -1 in PLANARCONFIG_CONTIG
395
    int nXBlock = 0;
396
    int nYBlock = 0;
397
    vsi_l_offset nOffset = 0;
398
    vsi_l_offset nSize = 0;
399
};
400

401
/************************************************************************/
402
/*                     ThreadDecompressionFunc()                        */
403
/************************************************************************/
404

405
/* static */ void GTiffDataset::ThreadDecompressionFunc(void *pData)
3,735✔
406
{
407
    const auto psJob = static_cast<const GTiffDecompressJob *>(pData);
3,735✔
408
    auto psContext = psJob->psContext;
3,735✔
409
    auto poDS = psContext->poDS;
3,735✔
410

411
    auto oAccumulator = psContext->oErrorAccumulator.InstallForCurrentScope();
3,735✔
412

413
    const int nBandsPerStrile =
3,736✔
414
        poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? poDS->nBands : 1;
3,736✔
415
    const int nBandsToWrite = poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
7,472✔
416
                                  ? psContext->nBandCount
3,736✔
417
                                  : 1;
418

419
    const int nXOffsetInBlock = psJob->nXBlock == psContext->nBlockXStart
7,472✔
420
                                    ? psContext->nXOff % poDS->m_nBlockXSize
3,736✔
421
                                    : 0;
422
    const int nXOffsetInData =
3,736✔
423
        psJob->nXBlock == psContext->nBlockXStart
3,736✔
424
            ? 0
3,736✔
425
            : (psJob->nXBlock - psContext->nBlockXStart) * poDS->m_nBlockXSize -
2,439✔
426
                  (psContext->nXOff % poDS->m_nBlockXSize);
2,439✔
427
    const int nXSize =
3,736✔
428
        psJob->nXBlock == psContext->nBlockXStart
3,736✔
429
            ? (psJob->nXBlock == psContext->nBlockXEnd
7,472✔
430
                   ? psContext->nXSize
1,297✔
431
                   : poDS->m_nBlockXSize -
471✔
432
                         (psContext->nXOff % poDS->m_nBlockXSize))
471✔
433
        : psJob->nXBlock == psContext->nBlockXEnd
2,439✔
434
            ? (((psContext->nXOff + psContext->nXSize) % poDS->m_nBlockXSize) ==
2,910✔
435
                       0
436
                   ? poDS->m_nBlockXSize
471✔
437
                   : ((psContext->nXOff + psContext->nXSize) %
400✔
438
                      poDS->m_nBlockXSize))
400✔
439
            : poDS->m_nBlockXSize;
1,968✔
440

441
    const int nYOffsetInBlock = psJob->nYBlock == psContext->nBlockYStart
7,472✔
442
                                    ? psContext->nYOff % poDS->m_nBlockYSize
3,736✔
443
                                    : 0;
444
    const int nYOffsetInData =
3,736✔
445
        psJob->nYBlock == psContext->nBlockYStart
3,736✔
446
            ? 0
3,736✔
447
            : (psJob->nYBlock - psContext->nBlockYStart) * poDS->m_nBlockYSize -
2,823✔
448
                  (psContext->nYOff % poDS->m_nBlockYSize);
2,823✔
449
    const int nYSize =
3,736✔
450
        psJob->nYBlock == psContext->nBlockYStart
3,736✔
451
            ? (psJob->nYBlock == psContext->nBlockYEnd
7,472✔
452
                   ? psContext->nYSize
911✔
453
                   : poDS->m_nBlockYSize -
911✔
454
                         (psContext->nYOff % poDS->m_nBlockYSize))
911✔
455
        : psJob->nYBlock == psContext->nBlockYEnd
2,825✔
456
            ? (((psContext->nYOff + psContext->nYSize) % poDS->m_nBlockYSize) ==
3,738✔
457
                       0
458
                   ? poDS->m_nBlockYSize
913✔
459
                   : ((psContext->nYOff + psContext->nYSize) %
800✔
460
                      poDS->m_nBlockYSize))
800✔
461
            : poDS->m_nBlockYSize;
1,912✔
462
#if 0
463
    CPLDebug("GTiff",
464
             "nXBlock = %d, nYBlock = %d, "
465
             "nXOffsetInBlock = %d, nXOffsetInData = %d, nXSize = %d, "
466
             "nYOffsetInBlock = %d, nYOffsetInData = %d, nYSize = %d\n",
467
             psJob->nXBlock, psJob->nYBlock,
468
             nXOffsetInBlock, nXOffsetInData, nXSize,
469
             nYOffsetInBlock, nYOffsetInData, nYSize);
470
#endif
471

472
    if (psJob->nSize == 0)
3,736✔
473
    {
474
        {
475
            std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
×
476
            if (!psContext->bSuccess)
×
477
                return;
×
478
        }
479
        const double dfNoDataValue =
×
480
            poDS->m_bNoDataSet ? poDS->m_dfNoDataValue : 0;
×
481
        for (int y = 0; y < nYSize; ++y)
×
482
        {
483
            for (int i = 0; i < nBandsToWrite; ++i)
×
484
            {
485
                const int iDstBandIdx =
×
486
                    poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
×
487
                        ? i
×
488
                        : psJob->iDstBandIdxSeparate;
×
489
                GDALCopyWords64(
×
490
                    &dfNoDataValue, GDT_Float64, 0,
491
                    psContext->pabyData + iDstBandIdx * psContext->nBandSpace +
×
492
                        (y + nYOffsetInData) * psContext->nLineSpace +
×
493
                        nXOffsetInData * psContext->nPixelSpace,
×
494
                    psContext->eBufType,
495
                    static_cast<int>(psContext->nPixelSpace), nXSize);
×
496
            }
497
        }
498
        return;
×
499
    }
500

501
    const int nBandsToCache =
3,736✔
502
        psContext->bCacheAllBands ? poDS->nBands : nBandsToWrite;
3,736✔
503
    std::vector<GDALRasterBlock *> apoBlocks(nBandsToCache);
3,736✔
504
    std::vector<bool> abAlreadyLoadedBlocks(nBandsToCache);
3,729✔
505
    int nAlreadyLoadedBlocks = 0;
3,695✔
506
    std::vector<GByte> abyInput;
3,695✔
507

508
    struct FreeBlocks
509
    {
510
        std::vector<GDALRasterBlock *> &m_apoBlocks;
511

512
        explicit FreeBlocks(std::vector<GDALRasterBlock *> &apoBlocksIn)
3,731✔
513
            : m_apoBlocks(apoBlocksIn)
3,731✔
514
        {
515
        }
3,731✔
516

517
        ~FreeBlocks()
3,735✔
518
        {
3,736✔
519
            for (auto *poBlock : m_apoBlocks)
10,313✔
520
            {
521
                if (poBlock)
6,578✔
522
                    poBlock->DropLock();
3,964✔
523
            }
524
        }
3,736✔
525
    };
526

527
    FreeBlocks oFreeBlocks(apoBlocks);
3,726✔
528

529
    const auto LoadBlocks = [&]()
1,752✔
530
    {
531
        for (int i = 0; i < nBandsToCache; ++i)
5,716✔
532
        {
533
            const int iBand = psContext->bCacheAllBands ? i + 1
6,244✔
534
                              : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
7,256✔
535
                                  ? psContext->panBandMap[i]
2,280✔
536
                                  : psJob->iSrcBandIdxSeparate + 1;
660✔
537
            apoBlocks[i] = poDS->GetRasterBand(iBand)->TryGetLockedBlockRef(
7,928✔
538
                psJob->nXBlock, psJob->nYBlock);
3,964✔
539
            if (apoBlocks[i] == nullptr)
3,964✔
540
            {
541
                // Temporary disabling of dirty block flushing, otherwise
542
                // we can be in a deadlock situation, where the
543
                // GTiffDataset::SubmitCompressionJob() method waits for jobs
544
                // to be finished, that can't finish (actually be started)
545
                // because this task and its siblings are taking all the
546
                // available workers allowed by the global thread pool.
547
                GDALRasterBlock::EnterDisableDirtyBlockFlush();
1,012✔
548
                apoBlocks[i] = poDS->GetRasterBand(iBand)->GetLockedBlockRef(
2,024✔
549
                    psJob->nXBlock, psJob->nYBlock, TRUE);
1,012✔
550
                GDALRasterBlock::LeaveDisableDirtyBlockFlush();
1,012✔
551
                if (apoBlocks[i] == nullptr)
1,012✔
552
                    return false;
×
553
            }
554
            else
555
            {
556
                abAlreadyLoadedBlocks[i] = true;
2,952✔
557
                nAlreadyLoadedBlocks++;
2,952✔
558
            }
559
        }
560
        return true;
1,752✔
561
    };
3,722✔
562

563
    const auto AllocInputBuffer = [&]()
2,516✔
564
    {
565
        bool bError = false;
2,516✔
566
#if SIZEOF_VOIDP == 4
567
        if (psJob->nSize != static_cast<size_t>(psJob->nSize))
568
        {
569
            bError = true;
570
        }
571
        else
572
#endif
573
        {
574
            try
575
            {
576
                abyInput.resize(static_cast<size_t>(psJob->nSize));
2,516✔
577
            }
578
            catch (const std::exception &)
×
579
            {
580
                bError = true;
×
581
            }
582
        }
583
        if (bError)
2,511✔
584
        {
585
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
586
                     "Cannot allocate working buffer of size " CPL_FRMT_GUIB,
587
                     static_cast<GUIntBig>(psJob->nSize));
×
588
            return false;
×
589
        }
590
        return true;
2,511✔
591
    };
3,722✔
592

593
    if (psContext->bHasPRead)
3,722✔
594
    {
595
        {
596
            std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
3,722✔
597
            if (!psContext->bSuccess)
3,736✔
598
                return;
×
599

600
            // Coverity Scan notices that GDALRasterBlock::Internalize() calls
601
            // CPLSleep() in a debug code path, and warns about that while
602
            // holding the above mutex.
603
            // coverity[sleep]
604
            if (!psContext->bSkipBlockCache && !LoadBlocks())
3,736✔
605
            {
606
                psContext->bSuccess = false;
×
607
                return;
×
608
            }
609
        }
610
        if (nAlreadyLoadedBlocks != nBandsToCache)
3,736✔
611
        {
612
            if (!AllocInputBuffer())
2,516✔
613
            {
614
                std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
×
615
                psContext->bSuccess = false;
×
616
                return;
×
617
            }
618
            if (psContext->poHandle->PRead(abyInput.data(), abyInput.size(),
2,511✔
619
                                           psJob->nOffset) != abyInput.size())
5,022✔
620
            {
621
                CPLError(CE_Failure, CPLE_AppDefined,
×
622
                         "Cannot read " CPL_FRMT_GUIB
623
                         " bytes at offset " CPL_FRMT_GUIB,
624
                         static_cast<GUIntBig>(psJob->nSize),
×
625
                         static_cast<GUIntBig>(psJob->nOffset));
×
626

627
                std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
×
628
                psContext->bSuccess = false;
×
629
                return;
×
630
            }
631
        }
632
    }
633
    else
634
    {
635
        std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
×
636
        if (!psContext->bSuccess)
×
637
            return;
×
638

639
        // Coverity Scan notices that GDALRasterBlock::Internalize() calls
640
        // CPLSleep() in a debug code path, and warns about that while
641
        // holding the above mutex.
642
        // coverity[sleep]
643
        if (!psContext->bSkipBlockCache && !LoadBlocks())
×
644
        {
645
            psContext->bSuccess = false;
×
646
            return;
×
647
        }
648

649
        if (nAlreadyLoadedBlocks != nBandsToCache)
×
650
        {
651
            if (!AllocInputBuffer())
×
652
            {
653
                psContext->bSuccess = false;
×
654
                return;
×
655
            }
656
            if (psContext->poHandle->Seek(psJob->nOffset, SEEK_SET) != 0 ||
×
657
                psContext->poHandle->Read(abyInput.data(), abyInput.size(),
×
658
                                          1) != 1)
×
659
            {
660
                CPLError(CE_Failure, CPLE_AppDefined,
×
661
                         "Cannot read " CPL_FRMT_GUIB
662
                         " bytes at offset " CPL_FRMT_GUIB,
663
                         static_cast<GUIntBig>(psJob->nSize),
×
664
                         static_cast<GUIntBig>(psJob->nOffset));
×
665
                psContext->bSuccess = false;
×
666
                return;
×
667
            }
668
        }
669
    }
670

671
    const int nDTSize = GDALGetDataTypeSizeBytes(psContext->eDT);
3,730✔
672
    GByte *pDstPtr = psContext->pabyData +
3,733✔
673
                     nYOffsetInData * psContext->nLineSpace +
3,733✔
674
                     nXOffsetInData * psContext->nPixelSpace;
3,733✔
675

676
    if (nAlreadyLoadedBlocks != nBandsToCache)
3,733✔
677
    {
678
        // Generate a dummy in-memory TIFF file that has all the needed tags
679
        // from the original file
680
        const CPLString osTmpFilename(
681
            VSIMemGenerateHiddenFilename("decompress.tif"));
2,511✔
682
        VSILFILE *fpTmp = VSIFOpenL(osTmpFilename.c_str(), "wb+");
2,511✔
683
        TIFF *hTIFFTmp =
684
            VSI_TIFFOpen(osTmpFilename.c_str(),
2,516✔
685
                         psContext->bTIFFIsBigEndian ? "wb+" : "wl+", fpTmp);
2,516✔
686
        CPLAssert(hTIFFTmp != nullptr);
2,516✔
687
        const int nBlockYSize =
2,516✔
688
            (psContext->bIsTiled ||
2,908✔
689
             psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
392✔
690
                ? poDS->m_nBlockYSize
2,908✔
691
            : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
51✔
692
                ? poDS->m_nBlockYSize
51✔
693
                : poDS->nRasterYSize % poDS->m_nBlockYSize;
42✔
694
        TIFFSetField(hTIFFTmp, TIFFTAG_IMAGEWIDTH, poDS->m_nBlockXSize);
2,516✔
695
        TIFFSetField(hTIFFTmp, TIFFTAG_IMAGELENGTH, nBlockYSize);
2,516✔
696
        TIFFSetField(hTIFFTmp, TIFFTAG_BITSPERSAMPLE, poDS->m_nBitsPerSample);
2,516✔
697
        TIFFSetField(hTIFFTmp, TIFFTAG_COMPRESSION, poDS->m_nCompression);
2,516✔
698
        TIFFSetField(hTIFFTmp, TIFFTAG_PHOTOMETRIC, poDS->m_nPhotometric);
2,516✔
699
        TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLEFORMAT, poDS->m_nSampleFormat);
2,516✔
700
        TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLESPERPIXEL,
2,516✔
701
                     poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
2,516✔
702
                         ? poDS->m_nSamplesPerPixel
696✔
703
                         : 1);
704
        TIFFSetField(hTIFFTmp, TIFFTAG_ROWSPERSTRIP, nBlockYSize);
2,516✔
705
        TIFFSetField(hTIFFTmp, TIFFTAG_PLANARCONFIG, poDS->m_nPlanarConfig);
2,516✔
706
        if (psContext->nPredictor != PREDICTOR_NONE)
2,516✔
707
            TIFFSetField(hTIFFTmp, TIFFTAG_PREDICTOR, psContext->nPredictor);
60✔
708
        if (poDS->m_nCompression == COMPRESSION_LERC)
2,516✔
709
        {
710
            TIFFSetField(hTIFFTmp, TIFFTAG_LERC_PARAMETERS, 2,
30✔
711
                         poDS->m_anLercAddCompressionAndVersion);
30✔
712
        }
713
        else if (poDS->m_nCompression == COMPRESSION_JPEG)
2,486✔
714
        {
715
            if (psContext->pJPEGTable)
14✔
716
            {
717
                TIFFSetField(hTIFFTmp, TIFFTAG_JPEGTABLES,
14✔
718
                             psContext->nJPEGTableSize, psContext->pJPEGTable);
719
            }
720
            if (poDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
14✔
721
            {
722
                TIFFSetField(hTIFFTmp, TIFFTAG_YCBCRSUBSAMPLING,
7✔
723
                             psContext->nYCrbCrSubSampling0,
7✔
724
                             psContext->nYCrbCrSubSampling1);
7✔
725
            }
726
        }
727
        if (poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
2,516✔
728
        {
729
            if (psContext->pExtraSamples)
696✔
730
            {
731
                TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
66✔
732
                             psContext->nExtraSampleCount,
66✔
733
                             psContext->pExtraSamples);
734
            }
735
            else
736
            {
737
                const int nSamplesAccountedFor =
630✔
738
                    poDS->m_nPhotometric == PHOTOMETRIC_RGB          ? 3
788✔
739
                    : poDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ? 1
158✔
740
                                                                     : 0;
741
                if (nSamplesAccountedFor > 0 &&
630✔
742
                    poDS->m_nSamplesPerPixel > nSamplesAccountedFor)
623✔
743
                {
744
                    // If the input image is not compliant regarndig ExtraSamples,
745
                    // generate a synthetic one to avoid gazillons of warnings
746
                    const auto nExtraSampleCount = static_cast<uint16_t>(
×
747
                        poDS->m_nSamplesPerPixel - nSamplesAccountedFor);
×
748
                    std::vector<uint16_t> anExtraSamples(
749
                        nExtraSampleCount, EXTRASAMPLE_UNSPECIFIED);
×
750
                    TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
×
751
                                 nExtraSampleCount, anExtraSamples.data());
752
                }
753
            }
754
        }
755
        TIFFWriteCheck(hTIFFTmp, FALSE, "ThreadDecompressionFunc");
2,516✔
756
        TIFFWriteDirectory(hTIFFTmp);
2,516✔
757
        XTIFFClose(hTIFFTmp);
2,516✔
758

759
        // Re-open file
760
        hTIFFTmp = VSI_TIFFOpen(osTmpFilename.c_str(), "r", fpTmp);
2,516✔
761
        CPLAssert(hTIFFTmp != nullptr);
2,516✔
762
        poDS->RestoreVolatileParameters(hTIFFTmp);
2,516✔
763

764
        bool bRet = true;
2,515✔
765
        // Request m_nBlockYSize line in the block, except on the bottom-most
766
        // tile/strip.
767
        const int nBlockReqYSize =
2,515✔
768
            (psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
2,515✔
769
                ? poDS->m_nBlockYSize
3,101✔
770
            : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
586✔
771
                ? poDS->m_nBlockYSize
586✔
772
                : poDS->nRasterYSize % poDS->m_nBlockYSize;
545✔
773

774
        const size_t nReqSize = static_cast<size_t>(poDS->m_nBlockXSize) *
2,515✔
775
                                nBlockReqYSize * nBandsPerStrile * nDTSize;
2,515✔
776

777
        GByte *pabyOutput;
778
        std::vector<GByte> abyOutput;
2,515✔
779
        if (poDS->m_nCompression == COMPRESSION_NONE &&
5,192✔
780
            !TIFFIsByteSwapped(poDS->m_hTIFF) && abyInput.size() >= nReqSize &&
2,676✔
781
            (psContext->bSkipBlockCache || nBandsPerStrile > 1))
160✔
782
        {
783
            pabyOutput = abyInput.data();
160✔
784
        }
785
        else
786
        {
787
            if (psContext->bSkipBlockCache || nBandsPerStrile > 1)
2,356✔
788
            {
789
                abyOutput.resize(nReqSize);
2,060✔
790
                pabyOutput = abyOutput.data();
2,060✔
791
            }
792
            else
793
            {
794
                pabyOutput = static_cast<GByte *>(apoBlocks[0]->GetDataRef());
296✔
795
            }
796
            if (!TIFFReadFromUserBuffer(hTIFFTmp, 0, abyInput.data(),
2,356✔
797
                                        abyInput.size(), pabyOutput,
2,356✔
798
                                        nReqSize) &&
2,356✔
799
                !poDS->m_bIgnoreReadErrors)
×
800
            {
801
                bRet = false;
×
802
            }
803
        }
804
        XTIFFClose(hTIFFTmp);
2,516✔
805
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpTmp));
2,516✔
806
        VSIUnlink(osTmpFilename.c_str());
2,516✔
807

808
        if (!bRet)
2,516✔
809
        {
810
            std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
×
811
            psContext->bSuccess = false;
×
812
            return;
×
813
        }
814

815
        if (!psContext->bSkipBlockCache && nBandsPerStrile > 1)
2,516✔
816
        {
817
            // Copy pixel-interleaved all-band buffer to cached blocks
818

819
            if (psContext->bUseDeinterleaveOptimBlockCache)
236✔
820
            {
821
                // Optimization
822
                std::vector<void *> ppDestBuffers(poDS->nBands);
232✔
823
                for (int i = 0; i < poDS->nBands; ++i)
464✔
824
                {
825
                    ppDestBuffers[i] = apoBlocks[i]->GetDataRef();
348✔
826
                }
827
                GDALDeinterleave(pabyOutput, psContext->eDT, poDS->nBands,
116✔
828
                                 ppDestBuffers.data(), psContext->eDT,
829
                                 static_cast<size_t>(nBlockReqYSize) *
116✔
830
                                     poDS->m_nBlockXSize);
116✔
831
            }
832
            else
833
            {
834
                // General case
835
                for (int i = 0; i < nBandsToCache; ++i)
488✔
836
                {
837
                    if (!abAlreadyLoadedBlocks[i])
368✔
838
                    {
839
                        const int iBand = psContext->bCacheAllBands
736✔
840
                                              ? i
368✔
841
                                              : psContext->panBandMap[i] - 1;
368✔
842
                        GDALCopyWords64(pabyOutput + iBand * nDTSize,
368✔
843
                                        psContext->eDT, nDTSize * poDS->nBands,
368✔
844
                                        apoBlocks[i]->GetDataRef(),
368✔
845
                                        psContext->eDT, nDTSize,
846
                                        static_cast<size_t>(nBlockReqYSize) *
368✔
847
                                            poDS->m_nBlockXSize);
368✔
848
                    }
849
                }
850
            }
851
        }
852

853
        const GByte *pSrcPtr =
2,516✔
854
            pabyOutput +
855
            (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
2,516✔
856
             nXOffsetInBlock) *
2,516✔
857
                nDTSize * nBandsPerStrile;
2,516✔
858
        const size_t nSrcLineInc = static_cast<size_t>(poDS->m_nBlockXSize) *
2,516✔
859
                                   nDTSize * nBandsPerStrile;
2,516✔
860

861
        // Optimization when writing to BIP buffer.
862
        if (psContext->bUseBIPOptim)
2,516✔
863
        {
864
            for (int y = 0; y < nYSize; ++y)
8,468✔
865
            {
866
                GDALCopyWords64(pSrcPtr, psContext->eDT, nDTSize, pDstPtr,
8,227✔
867
                                psContext->eBufType, psContext->nBufDTSize,
868
                                static_cast<size_t>(nXSize) * poDS->nBands);
8,227✔
869
                pSrcPtr += nSrcLineInc;
8,227✔
870
                pDstPtr += psContext->nLineSpace;
8,227✔
871
            }
872
            return;
241✔
873
        }
874

875
        if (psContext->bSkipBlockCache)
2,275✔
876
        {
877
            // Copy from pixel-interleaved all-band buffer (or temporary buffer
878
            // for single-band/separate case) into final buffer
879
            if (psContext->bUseDeinterleaveOptimNoBlockCache)
1,759✔
880
            {
881
                // Optimization
882
                std::vector<void *> ppDestBuffers(psContext->nBandCount);
215✔
883
                for (int i = 0; i < psContext->nBandCount; ++i)
860✔
884
                {
885
                    ppDestBuffers[i] =
645✔
886
                        pDstPtr +
645✔
887
                        (psContext->panBandMap[i] - 1) * psContext->nBandSpace;
645✔
888
                }
889
                for (int y = 0; y < nYSize; ++y)
12,273✔
890
                {
891
                    GDALDeinterleave(
12,058✔
892
                        pSrcPtr, psContext->eDT, psContext->nBandCount,
893
                        ppDestBuffers.data(), psContext->eDT, nXSize);
894
                    pSrcPtr += nSrcLineInc;
12,058✔
895
                    for (int i = 0; i < psContext->nBandCount; ++i)
48,230✔
896
                    {
897
                        ppDestBuffers[i] =
36,172✔
898
                            static_cast<GByte *>(ppDestBuffers[i]) +
36,172✔
899
                            psContext->nLineSpace;
34,922✔
900
                    }
901
                }
902
                return;
215✔
903
            }
904

905
            // General case
906
            for (int y = 0; y < nYSize; ++y)
40,244✔
907
            {
908
                for (int i = 0; i < nBandsToWrite; ++i)
78,200✔
909
                {
910
                    const int iSrcBandIdx =
39,500✔
911
                        poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
39,500✔
912
                            ? psContext->panBandMap[i] - 1
39,500✔
913
                            : 0;
914
                    const int iDstBandIdx =
39,500✔
915
                        poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
39,500✔
916
                            ? i
39,500✔
917
                            : psJob->iDstBandIdxSeparate;
38,500✔
918
                    GDALCopyWords64(
39,500✔
919
                        pSrcPtr + iSrcBandIdx * nDTSize + y * nSrcLineInc,
39,500✔
920
                        psContext->eDT, nDTSize * nBandsPerStrile,
921
                        pDstPtr + iDstBandIdx * psContext->nBandSpace +
39,500✔
922
                            y * psContext->nLineSpace,
39,500✔
923
                        psContext->eBufType,
924
                        static_cast<int>(psContext->nPixelSpace), nXSize);
39,500✔
925
                }
926
            }
927
            return;
1,544✔
928
        }
929
    }
930

931
    CPLAssert(!psContext->bSkipBlockCache);
1,738✔
932

933
    // Compose cached blocks into final buffer
934
    for (int i = 0; i < nBandsToWrite; ++i)
4,548✔
935
    {
936
        const int iSrcBandIdx =
2,812✔
937
            psContext->bCacheAllBands ? psContext->panBandMap[i] - 1
5,076✔
938
            : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? i
2,264✔
939
                                                           : 0;
940
        assert(iSrcBandIdx >= 0);
2,812✔
941
        const int iDstBandIdx = poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
5,624✔
942
                                    ? i
2,812✔
943
                                    : psJob->iDstBandIdxSeparate;
660✔
944
        const GByte *pSrcPtr =
945
            static_cast<GByte *>(apoBlocks[iSrcBandIdx]->GetDataRef()) +
2,812✔
946
            (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
2,811✔
947
             nXOffsetInBlock) *
2,811✔
948
                nDTSize;
2,811✔
949
        for (int y = 0; y < nYSize; ++y)
68,181✔
950
        {
951
            GDALCopyWords64(pSrcPtr + static_cast<size_t>(y) *
65,371✔
952
                                          poDS->m_nBlockXSize * nDTSize,
65,371✔
953
                            psContext->eDT, nDTSize,
954
                            pDstPtr + iDstBandIdx * psContext->nBandSpace +
65,371✔
955
                                y * psContext->nLineSpace,
65,371✔
956
                            psContext->eBufType,
957
                            static_cast<int>(psContext->nPixelSpace), nXSize);
65,371✔
958
        }
959
    }
960
}
961

962
/************************************************************************/
963
/*                    IsMultiThreadedReadCompatible()                   */
964
/************************************************************************/
965

966
bool GTiffDataset::IsMultiThreadedReadCompatible() const
258✔
967
{
968
    return cpl::down_cast<GTiffRasterBand *>(papoBands[0])
258✔
969
               ->IsBaseGTiffClass() &&
258✔
970
           !m_bStreamingIn && !m_bStreamingOut &&
514✔
971
           (m_nCompression == COMPRESSION_NONE ||
256✔
972
            m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
237✔
973
            m_nCompression == COMPRESSION_LZW ||
221✔
974
            m_nCompression == COMPRESSION_PACKBITS ||
86✔
975
            m_nCompression == COMPRESSION_LZMA ||
72✔
976
            m_nCompression == COMPRESSION_ZSTD ||
58✔
977
            m_nCompression == COMPRESSION_LERC ||
44✔
978
            m_nCompression == COMPRESSION_JXL ||
30✔
979
            m_nCompression == COMPRESSION_JXL_DNG_1_7 ||
30✔
980
            m_nCompression == COMPRESSION_WEBP ||
16✔
981
            m_nCompression == COMPRESSION_JPEG);
260✔
982
}
983

984
/************************************************************************/
985
/*                        MultiThreadedRead()                           */
986
/************************************************************************/
987

988
CPLErr GTiffDataset::MultiThreadedRead(int nXOff, int nYOff, int nXSize,
243✔
989
                                       int nYSize, void *pData,
990
                                       GDALDataType eBufType, int nBandCount,
991
                                       const int *panBandMap,
992
                                       GSpacing nPixelSpace,
993
                                       GSpacing nLineSpace, GSpacing nBandSpace)
994
{
995
    auto poQueue = m_poThreadPool->CreateJobQueue();
486✔
996
    if (poQueue == nullptr)
243✔
997
    {
998
        return CE_Failure;
×
999
    }
1000

1001
    const int nBlockXStart = nXOff / m_nBlockXSize;
243✔
1002
    const int nBlockYStart = nYOff / m_nBlockYSize;
243✔
1003
    const int nBlockXEnd = (nXOff + nXSize - 1) / m_nBlockXSize;
243✔
1004
    const int nBlockYEnd = (nYOff + nYSize - 1) / m_nBlockYSize;
243✔
1005
    const int nXBlocks = nBlockXEnd - nBlockXStart + 1;
243✔
1006
    const int nYBlocks = nBlockYEnd - nBlockYStart + 1;
243✔
1007
    const int nStrilePerBlock =
243✔
1008
        m_nPlanarConfig == PLANARCONFIG_CONTIG ? 1 : nBandCount;
243✔
1009
    const int nBlocks = nXBlocks * nYBlocks * nStrilePerBlock;
243✔
1010

1011
    GTiffDecompressContext sContext;
486✔
1012
    sContext.poHandle = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
243✔
1013
    sContext.bHasPRead =
243✔
1014
        sContext.poHandle->HasPRead()
243✔
1015
#ifdef DEBUG
1016
        && CPLTestBool(CPLGetConfigOption("GTIFF_ALLOW_PREAD", "YES"))
243✔
1017
#endif
1018
        ;
1019
    sContext.poDS = this;
243✔
1020
    sContext.eDT = GetRasterBand(1)->GetRasterDataType();
243✔
1021
    sContext.nXOff = nXOff;
243✔
1022
    sContext.nYOff = nYOff;
243✔
1023
    sContext.nXSize = nXSize;
243✔
1024
    sContext.nYSize = nYSize;
243✔
1025
    sContext.nBlockXStart = nBlockXStart;
243✔
1026
    sContext.nBlockXEnd = nBlockXEnd;
243✔
1027
    sContext.nBlockYStart = nBlockYStart;
243✔
1028
    sContext.nBlockYEnd = nBlockYEnd;
243✔
1029
    sContext.pabyData = static_cast<GByte *>(pData);
243✔
1030
    sContext.eBufType = eBufType;
243✔
1031
    sContext.nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
243✔
1032
    sContext.nBandCount = nBandCount;
243✔
1033
    sContext.panBandMap = panBandMap;
243✔
1034
    sContext.nPixelSpace = nPixelSpace;
243✔
1035
    sContext.nLineSpace = nLineSpace;
243✔
1036
    // Setting nBandSpace to a dummy value when nBandCount == 1 helps detecting
1037
    // bad computations of target buffer address
1038
    // (https://github.com/rasterio/rasterio/issues/2847)
1039
    sContext.nBandSpace = nBandCount == 1 ? 0xDEADBEEF : nBandSpace;
243✔
1040
    sContext.bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
243✔
1041
    sContext.bTIFFIsBigEndian = CPL_TO_BOOL(TIFFIsBigEndian(m_hTIFF));
243✔
1042
    sContext.nPredictor = PREDICTOR_NONE;
243✔
1043
    sContext.nBlocksPerRow = m_nBlocksPerRow;
243✔
1044

1045
    if (m_bDirectIO)
243✔
1046
    {
1047
        sContext.bSkipBlockCache = true;
×
1048
    }
1049
    else if (nXOff == 0 && nYOff == 0 && nXSize == nRasterXSize &&
243✔
1050
             nYSize == nRasterYSize)
187✔
1051
    {
1052
        if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
186✔
1053
        {
1054
            sContext.bSkipBlockCache = true;
40✔
1055
        }
1056
        else if (nBandCount == nBands)
146✔
1057
        {
1058
            sContext.bSkipBlockCache = true;
70✔
1059
            for (int i = 0; i < nBands; ++i)
200✔
1060
            {
1061
                if (panBandMap[i] != i + 1)
154✔
1062
                {
1063
                    sContext.bSkipBlockCache = false;
24✔
1064
                    break;
24✔
1065
                }
1066
            }
1067
        }
1068
    }
1069

1070
    if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount == nBands &&
243✔
1071
        nPixelSpace == nBands * static_cast<GSpacing>(sContext.nBufDTSize))
111✔
1072
    {
1073
        sContext.bUseBIPOptim = true;
33✔
1074
        for (int i = 0; i < nBands; ++i)
118✔
1075
        {
1076
            if (panBandMap[i] != i + 1)
85✔
1077
            {
1078
                sContext.bUseBIPOptim = false;
×
1079
                break;
×
1080
            }
1081
        }
1082
    }
1083

1084
    if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
243✔
1085
        (nBands == 3 || nBands == 4) && nBands == nBandCount &&
187✔
1086
        (sContext.eDT == GDT_Byte || sContext.eDT == GDT_Int16 ||
94✔
1087
         sContext.eDT == GDT_UInt16))
9✔
1088
    {
1089
        if (sContext.bSkipBlockCache)
94✔
1090
        {
1091
            if (sContext.eBufType == sContext.eDT &&
36✔
1092
                nPixelSpace == sContext.nBufDTSize)
35✔
1093
            {
1094
                sContext.bUseDeinterleaveOptimNoBlockCache = true;
24✔
1095
            }
1096
        }
1097
        else
1098
        {
1099
            sContext.bUseDeinterleaveOptimBlockCache = true;
58✔
1100
            for (int i = 0; i < nBands; ++i)
166✔
1101
            {
1102
                if (panBandMap[i] != i + 1)
130✔
1103
                {
1104
                    sContext.bUseDeinterleaveOptimBlockCache = false;
22✔
1105
                    break;
22✔
1106
                }
1107
            }
1108
        }
1109
    }
1110

1111
    // In contig mode, if only one band is requested, check if we have
1112
    // enough cache to cache all bands.
1113
    if (!sContext.bSkipBlockCache && nBands != 1 &&
243✔
1114
        m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount == 1)
151✔
1115
    {
1116
        const GIntBig nRequiredMem = static_cast<GIntBig>(nBands) * nXBlocks *
76✔
1117
                                     nYBlocks * m_nBlockXSize * m_nBlockYSize *
76✔
1118
                                     GDALGetDataTypeSizeBytes(sContext.eDT);
76✔
1119
        if (nRequiredMem > GDALGetCacheMax64())
76✔
1120
        {
1121
            if (!m_bHasWarnedDisableAggressiveBandCaching)
×
1122
            {
1123
                CPLDebug("GTiff",
×
1124
                         "Disable aggressive band caching. "
1125
                         "Cache not big enough. "
1126
                         "At least " CPL_FRMT_GIB " bytes necessary",
1127
                         nRequiredMem);
1128
                m_bHasWarnedDisableAggressiveBandCaching = true;
×
1129
            }
1130
        }
1131
        else
1132
        {
1133
            sContext.bCacheAllBands = true;
76✔
1134
            if ((nBands == 3 || nBands == 4) &&
76✔
1135
                (sContext.eDT == GDT_Byte || sContext.eDT == GDT_Int16 ||
66✔
1136
                 sContext.eDT == GDT_UInt16))
6✔
1137
            {
1138
                sContext.bUseDeinterleaveOptimBlockCache = true;
66✔
1139
            }
1140
        }
1141
    }
1142

1143
    if (eAccess == GA_Update)
243✔
1144
    {
1145
        std::vector<int> anBandsToCheck;
233✔
1146
        if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1)
233✔
1147
        {
1148
            for (int i = 0; i < nBands; ++i)
740✔
1149
            {
1150
                anBandsToCheck.push_back(i);
564✔
1151
            }
176✔
1152
        }
1153
        else
1154
        {
1155
            for (int i = 0; i < nBandCount; ++i)
168✔
1156
            {
1157
                anBandsToCheck.push_back(panBandMap[i] - 1);
111✔
1158
            }
1159
        }
1160
        if (!anBandsToCheck.empty())
233✔
1161
        {
1162
            // If at least one block in the region of intersest is dirty,
1163
            // fallback to normal reading code path to be able to retrieve
1164
            // content partly from the block cache.
1165
            // An alternative that was implemented in GDAL 3.6 to 3.8.0 was
1166
            // to flush dirty blocks, but this could cause many write&read&write
1167
            // cycles in some gdalwarp scenarios.
1168
            // Cf https://github.com/OSGeo/gdal/issues/8729
1169
            bool bUseBaseImplementation = false;
233✔
1170
            for (int y = 0; y < nYBlocks; ++y)
1,222✔
1171
            {
1172
                for (int x = 0; x < nXBlocks; ++x)
3,517✔
1173
                {
1174
                    for (const int iBand : anBandsToCheck)
8,908✔
1175
                    {
1176
                        if (m_nLoadedBlock >= 0 && m_bLoadedBlockDirty &&
6,398✔
1177
                            cpl::down_cast<GTiffRasterBand *>(papoBands[iBand])
×
1178
                                    ->ComputeBlockId(nBlockXStart + x,
×
1179
                                                     nBlockYStart + y) ==
1180
                                m_nLoadedBlock)
×
1181
                        {
1182
                            bUseBaseImplementation = true;
×
1183
                            goto after_loop;
18✔
1184
                        }
1185
                        auto poBlock = papoBands[iBand]->TryGetLockedBlockRef(
12,796✔
1186
                            nBlockXStart + x, nBlockYStart + y);
6,398✔
1187
                        if (poBlock)
6,398✔
1188
                        {
1189
                            if (poBlock->GetDirty())
3,868✔
1190
                            {
1191
                                poBlock->DropLock();
18✔
1192
                                bUseBaseImplementation = true;
18✔
1193
                                goto after_loop;
18✔
1194
                            }
1195
                            poBlock->DropLock();
3,850✔
1196
                        }
1197
                    }
1198
                }
1199
            }
1200
        after_loop:
215✔
1201
            if (bUseBaseImplementation)
233✔
1202
            {
1203
                ++m_nDisableMultiThreadedRead;
18✔
1204
                GDALRasterIOExtraArg sExtraArg;
1205
                INIT_RASTERIO_EXTRA_ARG(sExtraArg);
18✔
1206
                const CPLErr eErr = GDALDataset::IRasterIO(
18✔
1207
                    GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nXSize,
1208
                    nYSize, eBufType, nBandCount, const_cast<int *>(panBandMap),
1209
                    nPixelSpace, nLineSpace, nBandSpace, &sExtraArg);
1210
                --m_nDisableMultiThreadedRead;
18✔
1211
                return eErr;
18✔
1212
            }
1213
        }
1214

1215
        // Make sure that all blocks that we are going to read and that are
1216
        // being written by a worker thread are completed.
1217
        // cppcheck-suppress constVariableReference
1218
        auto &oQueue =
215✔
1219
            m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
215✔
1220
        if (!oQueue.empty())
215✔
1221
        {
1222
            for (int y = 0; y < nYBlocks; ++y)
85✔
1223
            {
1224
                for (int x = 0; x < nXBlocks; ++x)
192✔
1225
                {
1226
                    for (int i = 0; i < nStrilePerBlock; ++i)
296✔
1227
                    {
1228
                        int nBlockId =
176✔
1229
                            nBlockXStart + x +
176✔
1230
                            (nBlockYStart + y) * sContext.nBlocksPerRow;
176✔
1231
                        if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
176✔
1232
                            nBlockId += (panBandMap[i] - 1) * m_nBlocksPerBand;
84✔
1233

1234
                        WaitCompletionForBlock(nBlockId);
176✔
1235
                    }
1236
                }
1237
            }
1238
        }
1239

1240
        // Flush to file, and then to disk if using pread() interface
1241
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
215✔
1242
        if (sContext.bHasPRead)
215✔
1243
            sContext.poHandle->Flush();
215✔
1244
    }
1245

1246
    if (GTIFFSupportsPredictor(m_nCompression))
225✔
1247
    {
1248
        TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &sContext.nPredictor);
146✔
1249
    }
1250
    else if (m_nCompression == COMPRESSION_JPEG)
79✔
1251
    {
1252
        TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &sContext.nJPEGTableSize,
2✔
1253
                     &sContext.pJPEGTable);
1254
        if (m_nPhotometric == PHOTOMETRIC_YCBCR)
2✔
1255
        {
1256
            TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
1✔
1257
                                  &sContext.nYCrbCrSubSampling0,
1258
                                  &sContext.nYCrbCrSubSampling1);
1259
        }
1260
    }
1261
    if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
225✔
1262
    {
1263
        TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &sContext.nExtraSampleCount,
178✔
1264
                     &sContext.pExtraSamples);
1265
    }
1266

1267
    // Create one job per tile/strip
1268
    vsi_l_offset nFileSize = 0;
225✔
1269
    std::vector<GTiffDecompressJob> asJobs(nBlocks);
450✔
1270
    std::vector<vsi_l_offset> anOffsets(nBlocks);
450✔
1271
    std::vector<size_t> anSizes(nBlocks);
450✔
1272
    int iJob = 0;
225✔
1273
    int nAdviseReadRanges = 0;
225✔
1274
    const size_t nAdviseReadTotalBytesLimit =
1275
        sContext.poHandle->GetAdviseReadTotalBytesLimit();
225✔
1276
    size_t nAdviseReadAccBytes = 0;
225✔
1277
    for (int y = 0; y < nYBlocks; ++y)
8,604✔
1278
    {
1279
        for (int x = 0; x < nXBlocks; ++x)
18,308✔
1280
        {
1281
            for (int i = 0; i < nStrilePerBlock; ++i)
20,924✔
1282
            {
1283
                asJobs[iJob].psContext = &sContext;
10,997✔
1284
                asJobs[iJob].iSrcBandIdxSeparate =
10,997✔
1285
                    m_nPlanarConfig == PLANARCONFIG_CONTIG ? -1
10,997✔
1286
                                                           : panBandMap[i] - 1;
2,200✔
1287
                asJobs[iJob].iDstBandIdxSeparate =
10,997✔
1288
                    m_nPlanarConfig == PLANARCONFIG_CONTIG ? -1 : i;
10,997✔
1289
                asJobs[iJob].nXBlock = nBlockXStart + x;
10,997✔
1290
                asJobs[iJob].nYBlock = nBlockYStart + y;
10,997✔
1291

1292
                int nBlockId = asJobs[iJob].nXBlock +
10,997✔
1293
                               asJobs[iJob].nYBlock * sContext.nBlocksPerRow;
10,997✔
1294
                if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
10,997✔
1295
                    nBlockId +=
2,200✔
1296
                        asJobs[iJob].iSrcBandIdxSeparate * m_nBlocksPerBand;
2,200✔
1297

1298
                bool bErrorInIsBlockAvailable = false;
10,997✔
1299
                if (!sContext.bHasPRead)
10,997✔
1300
                {
1301
                    // Taking the mutex here is only needed when bHasPRead ==
1302
                    // false since we could have concurrent uses of the handle,
1303
                    // when when reading the TIFF TileOffsets / TileByteCounts
1304
                    // array
1305
                    std::lock_guard<std::recursive_mutex> oLock(
1306
                        sContext.oMutex);
×
1307

1308
                    CPL_IGNORE_RET_VAL(IsBlockAvailable(
×
1309
                        nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
×
1310
                        &bErrorInIsBlockAvailable));
1311
                }
1312
                else
1313
                {
1314
                    CPL_IGNORE_RET_VAL(IsBlockAvailable(
10,997✔
1315
                        nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
10,997✔
1316
                        &bErrorInIsBlockAvailable));
1317
                }
1318
                if (bErrorInIsBlockAvailable)
10,997✔
1319
                {
1320
                    std::lock_guard<std::recursive_mutex> oLock(
1321
                        sContext.oMutex);
1✔
1322
                    sContext.bSuccess = false;
1✔
1323
                    return CE_Failure;
1✔
1324
                }
1325

1326
                // Sanity check on block size
1327
                if (asJobs[iJob].nSize > 100U * 1024 * 1024)
10,996✔
1328
                {
1329
                    if (nFileSize == 0)
×
1330
                    {
1331
                        std::lock_guard<std::recursive_mutex> oLock(
1332
                            sContext.oMutex);
×
1333
                        sContext.poHandle->Seek(0, SEEK_END);
×
1334
                        nFileSize = sContext.poHandle->Tell();
×
1335
                    }
1336
                    if (asJobs[iJob].nSize > nFileSize)
×
1337
                    {
1338
                        CPLError(CE_Failure, CPLE_AppDefined,
×
1339
                                 "Cannot read " CPL_FRMT_GUIB
1340
                                 " bytes at offset " CPL_FRMT_GUIB,
1341
                                 static_cast<GUIntBig>(asJobs[iJob].nSize),
×
1342
                                 static_cast<GUIntBig>(asJobs[iJob].nOffset));
×
1343

1344
                        std::lock_guard<std::recursive_mutex> oLock(
1345
                            sContext.oMutex);
×
1346
                        sContext.bSuccess = false;
×
1347
                        return CE_Failure;
×
1348
                    }
1349
                }
1350

1351
                // Only request in AdviseRead() ranges for blocks we don't
1352
                // have in cache.
1353
                bool bAddToAdviseRead = true;
10,996✔
1354
                if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
10,996✔
1355
                {
1356
                    auto poBlock =
1357
                        GetRasterBand(panBandMap[i])
2,200✔
1358
                            ->TryGetLockedBlockRef(asJobs[iJob].nXBlock,
2,200✔
1359
                                                   asJobs[iJob].nYBlock);
2,200✔
1360
                    if (poBlock)
2,200✔
1361
                    {
1362
                        poBlock->DropLock();
968✔
1363
                        bAddToAdviseRead = false;
968✔
1364
                    }
1365
                }
1366
                else
1367
                {
1368
                    bool bAllCached = true;
8,796✔
1369
                    for (int iBand = 0; iBand < nBandCount; ++iBand)
10,506✔
1370
                    {
1371
                        auto poBlock =
1372
                            GetRasterBand(panBandMap[iBand])
9,576✔
1373
                                ->TryGetLockedBlockRef(asJobs[iJob].nXBlock,
9,576✔
1374
                                                       asJobs[iJob].nYBlock);
9,576✔
1375
                        if (poBlock)
9,576✔
1376
                        {
1377
                            poBlock->DropLock();
1,710✔
1378
                        }
1379
                        else
1380
                        {
1381
                            bAllCached = false;
7,866✔
1382
                            break;
7,866✔
1383
                        }
1384
                    }
1385
                    if (bAllCached)
8,796✔
1386
                        bAddToAdviseRead = false;
930✔
1387
                }
1388

1389
                if (bAddToAdviseRead)
10,996✔
1390
                {
1391
                    anOffsets[nAdviseReadRanges] = asJobs[iJob].nOffset;
9,098✔
1392
                    anSizes[nAdviseReadRanges] =
18,196✔
1393
                        static_cast<size_t>(std::min<vsi_l_offset>(
9,098✔
1394
                            std::numeric_limits<size_t>::max(),
27,294✔
1395
                            asJobs[iJob].nSize));
9,098✔
1396

1397
                    // If the total number of bytes we must read excess the
1398
                    // capacity of AdviseRead(), then split the RasterIO()
1399
                    // request in 2 halves.
1400
                    if (nAdviseReadTotalBytesLimit > 0 &&
16,502✔
1401
                        anSizes[nAdviseReadRanges] <
7,404✔
1402
                            nAdviseReadTotalBytesLimit &&
7,404✔
1403
                        anSizes[nAdviseReadRanges] >
7,404✔
1404
                            nAdviseReadTotalBytesLimit - nAdviseReadAccBytes &&
16,502✔
1405
                        nYBlocks >= 2)
1406
                    {
1407
                        const int nYOff2 =
1✔
1408
                            (nBlockYStart + nYBlocks / 2) * m_nBlockYSize;
1✔
1409
                        CPLDebugOnly("GTiff",
1✔
1410
                                     "Splitting request (%d,%d,%dx%d) into "
1411
                                     "(%d,%d,%dx%d) and (%d,%d,%dx%d)",
1412
                                     nXOff, nYOff, nXSize, nYSize, nXOff, nYOff,
1413
                                     nXSize, nYOff2 - nYOff, nXOff, nYOff2,
1414
                                     nXSize, nYOff + nYSize - nYOff2);
1415

1416
                        asJobs.clear();
1✔
1417
                        anOffsets.clear();
1✔
1418
                        anSizes.clear();
1✔
1419
                        poQueue.reset();
1✔
1420

1421
                        CPLErr eErr = MultiThreadedRead(
1✔
1422
                            nXOff, nYOff, nXSize, nYOff2 - nYOff, pData,
1423
                            eBufType, nBandCount, panBandMap, nPixelSpace,
1424
                            nLineSpace, nBandSpace);
1425
                        if (eErr == CE_None)
1✔
1426
                        {
1427
                            eErr = MultiThreadedRead(
1✔
1428
                                nXOff, nYOff2, nXSize, nYOff + nYSize - nYOff2,
1✔
1429
                                static_cast<GByte *>(pData) +
1430
                                    (nYOff2 - nYOff) * nLineSpace,
1✔
1431
                                eBufType, nBandCount, panBandMap, nPixelSpace,
1432
                                nLineSpace, nBandSpace);
1433
                        }
1434
                        return eErr;
1✔
1435
                    }
1436
                    nAdviseReadAccBytes += anSizes[nAdviseReadRanges];
9,097✔
1437

1438
                    ++nAdviseReadRanges;
9,097✔
1439
                }
1440

1441
                ++iJob;
10,995✔
1442
            }
1443
        }
1444
    }
1445

1446
    if (sContext.bSuccess)
223✔
1447
    {
1448
        // Potentially start asynchronous fetching of ranges depending on file
1449
        // implementation
1450
        if (nAdviseReadRanges > 0)
223✔
1451
        {
1452
            sContext.poHandle->AdviseRead(nAdviseReadRanges, anOffsets.data(),
96✔
1453
                                          anSizes.data());
96✔
1454
        }
1455

1456
        // We need to do that as threads will access the block cache
1457
        TemporarilyDropReadWriteLock();
223✔
1458

1459
        for (auto &sJob : asJobs)
3,959✔
1460
        {
1461
            poQueue->SubmitJob(ThreadDecompressionFunc, &sJob);
3,736✔
1462
        }
1463

1464
        // Wait for all jobs to have been completed
1465
        poQueue->WaitCompletion();
223✔
1466

1467
        // Undo effect of above TemporarilyDropReadWriteLock()
1468
        ReacquireReadWriteLock();
223✔
1469

1470
        sContext.oErrorAccumulator.ReplayErrors();
223✔
1471
    }
1472

1473
    return sContext.bSuccess ? CE_None : CE_Failure;
223✔
1474
}
1475

1476
/************************************************************************/
1477
/*                        FetchBufferVirtualMemIO                       */
1478
/************************************************************************/
1479

1480
class FetchBufferVirtualMemIO final
1481
{
1482
    const GByte *pabySrcData;
1483
    size_t nMappingSize;
1484
    GByte *pTempBuffer;
1485

1486
  public:
1487
    FetchBufferVirtualMemIO(const GByte *pabySrcDataIn, size_t nMappingSizeIn,
971✔
1488
                            GByte *pTempBufferIn)
1489
        : pabySrcData(pabySrcDataIn), nMappingSize(nMappingSizeIn),
971✔
1490
          pTempBuffer(pTempBufferIn)
971✔
1491
    {
1492
    }
971✔
1493

1494
    const GByte *FetchBytes(vsi_l_offset nOffset, int nPixels, int nDTSize,
893,621✔
1495
                            bool bIsByteSwapped, bool bIsComplex, int nBlockId)
1496
    {
1497
        if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
893,621✔
1498
        {
1499
            CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
28✔
1500
                     nBlockId);
1501
            return nullptr;
28✔
1502
        }
1503
        if (!bIsByteSwapped)
893,593✔
1504
            return pabySrcData + nOffset;
572,847✔
1505
        memcpy(pTempBuffer, pabySrcData + nOffset,
320,746✔
1506
               static_cast<size_t>(nPixels) * nDTSize);
320,746✔
1507
        if (bIsComplex)
320,746✔
1508
            GDALSwapWords(pTempBuffer, nDTSize / 2, 2 * nPixels, nDTSize / 2);
160,400✔
1509
        else
1510
            GDALSwapWords(pTempBuffer, nDTSize, nPixels, nDTSize);
160,346✔
1511
        return pTempBuffer;
320,746✔
1512
    }
1513

1514
    bool FetchBytes(GByte *pabyDstBuffer, vsi_l_offset nOffset, int nPixels,
77,084✔
1515
                    int nDTSize, bool bIsByteSwapped, bool bIsComplex,
1516
                    int nBlockId)
1517
    {
1518
        if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
77,084✔
1519
        {
1520
            CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
11✔
1521
                     nBlockId);
1522
            return false;
11✔
1523
        }
1524
        memcpy(pabyDstBuffer, pabySrcData + nOffset,
77,073✔
1525
               static_cast<size_t>(nPixels) * nDTSize);
77,073✔
1526
        if (bIsByteSwapped)
77,073✔
1527
        {
1528
            if (bIsComplex)
10,120✔
1529
                GDALSwapWords(pabyDstBuffer, nDTSize / 2, 2 * nPixels,
5,060✔
1530
                              nDTSize / 2);
1531
            else
1532
                GDALSwapWords(pabyDstBuffer, nDTSize, nPixels, nDTSize);
5,060✔
1533
        }
1534
        return true;
77,073✔
1535
    }
1536

1537
    // cppcheck-suppress unusedStructMember
1538
    static const bool bMinimizeIO = false;
1539
};
1540

1541
/************************************************************************/
1542
/*                         VirtualMemIO()                               */
1543
/************************************************************************/
1544

1545
int GTiffDataset::VirtualMemIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
1,101✔
1546
                               int nXSize, int nYSize, void *pData,
1547
                               int nBufXSize, int nBufYSize,
1548
                               GDALDataType eBufType, int nBandCount,
1549
                               const int *panBandMap, GSpacing nPixelSpace,
1550
                               GSpacing nLineSpace, GSpacing nBandSpace,
1551
                               GDALRasterIOExtraArg *psExtraArg)
1552
{
1553
    if (eAccess == GA_Update || eRWFlag == GF_Write || m_bStreamingIn)
1,101✔
1554
        return -1;
×
1555

1556
    // Only know how to deal with nearest neighbour in this optimized routine.
1557
    if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
1,101✔
1558
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
417✔
1559
    {
1560
        return -1;
130✔
1561
    }
1562

1563
    const GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType();
971✔
1564
    const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
971✔
1565
    if (!(m_nCompression == COMPRESSION_NONE &&
971✔
1566
          (m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
971✔
1567
           m_nPhotometric == PHOTOMETRIC_RGB ||
392✔
1568
           m_nPhotometric == PHOTOMETRIC_PALETTE) &&
×
1569
          m_nBitsPerSample == nDTSizeBits))
971✔
1570
    {
1571
        m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
×
1572
        return -1;
×
1573
    }
1574

1575
    size_t nMappingSize = 0;
971✔
1576
    GByte *pabySrcData = nullptr;
971✔
1577
    if (STARTS_WITH(m_pszFilename, "/vsimem/"))
971✔
1578
    {
1579
        vsi_l_offset nDataLength = 0;
708✔
1580
        pabySrcData = VSIGetMemFileBuffer(m_pszFilename, &nDataLength, FALSE);
708✔
1581
        nMappingSize = static_cast<size_t>(nDataLength);
708✔
1582
        if (pabySrcData == nullptr)
708✔
1583
            return -1;
×
1584
    }
1585
    else if (m_psVirtualMemIOMapping == nullptr)
263✔
1586
    {
1587
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
11✔
1588
        if (!CPLIsVirtualMemFileMapAvailable() ||
22✔
1589
            VSIFGetNativeFileDescriptorL(fp) == nullptr)
11✔
1590
        {
1591
            m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
×
1592
            return -1;
×
1593
        }
1594
        if (VSIFSeekL(fp, 0, SEEK_END) != 0)
11✔
1595
        {
1596
            m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
×
1597
            return -1;
×
1598
        }
1599
        const vsi_l_offset nLength = VSIFTellL(fp);
11✔
1600
        if (static_cast<size_t>(nLength) != nLength)
1601
        {
1602
            m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
1603
            return -1;
1604
        }
1605
        if (m_eVirtualMemIOUsage == VirtualMemIOEnum::IF_ENOUGH_RAM)
11✔
1606
        {
1607
            GIntBig nRAM = CPLGetUsablePhysicalRAM();
×
1608
            if (static_cast<GIntBig>(nLength) > nRAM)
×
1609
            {
1610
                CPLDebug("GTiff",
×
1611
                         "Not enough RAM to map whole file into memory.");
1612
                m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
×
1613
                return -1;
×
1614
            }
1615
        }
1616
        m_psVirtualMemIOMapping = CPLVirtualMemFileMapNew(
11✔
1617
            fp, 0, nLength, VIRTUALMEM_READONLY, nullptr, nullptr);
1618
        if (m_psVirtualMemIOMapping == nullptr)
11✔
1619
        {
1620
            m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
×
1621
            return -1;
×
1622
        }
1623
        m_eVirtualMemIOUsage = VirtualMemIOEnum::YES;
11✔
1624
    }
1625

1626
    if (m_psVirtualMemIOMapping)
971✔
1627
    {
1628
#ifdef DEBUG
1629
        CPLDebug("GTiff", "Using VirtualMemIO");
263✔
1630
#endif
1631
        nMappingSize = CPLVirtualMemGetSize(m_psVirtualMemIOMapping);
263✔
1632
        pabySrcData =
1633
            static_cast<GByte *>(CPLVirtualMemGetAddr(m_psVirtualMemIOMapping));
263✔
1634
    }
1635

1636
    if (TIFFIsByteSwapped(m_hTIFF) && m_pTempBufferForCommonDirectIO == nullptr)
971✔
1637
    {
1638
        const int nDTSize = nDTSizeBits / 8;
12✔
1639
        size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
12✔
1640
            m_nBlockXSize * nDTSize *
24✔
1641
            (m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1));
12✔
1642
        if (TIFFIsTiled(m_hTIFF))
12✔
1643
            nTempBufferForCommonDirectIOSize *= m_nBlockYSize;
6✔
1644

1645
        m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
12✔
1646
            VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
12✔
1647
        if (m_pTempBufferForCommonDirectIO == nullptr)
12✔
1648
            return CE_Failure;
×
1649
    }
1650
    FetchBufferVirtualMemIO oFetcher(pabySrcData, nMappingSize,
1651
                                     m_pTempBufferForCommonDirectIO);
971✔
1652

1653
    return CommonDirectIO(oFetcher, nXOff, nYOff, nXSize, nYSize, pData,
971✔
1654
                          nBufXSize, nBufYSize, eBufType, nBandCount,
1655
                          panBandMap, nPixelSpace, nLineSpace, nBandSpace);
971✔
1656
}
1657

1658
/************************************************************************/
1659
/*                   CopyContigByteMultiBand()                          */
1660
/************************************************************************/
1661

1662
static inline void CopyContigByteMultiBand(const GByte *CPL_RESTRICT pabySrc,
2,754✔
1663
                                           int nSrcStride,
1664
                                           GByte *CPL_RESTRICT pabyDest,
1665
                                           int nDestStride, int nIters,
1666
                                           int nBandCount)
1667
{
1668
    if (nBandCount == 3)
2,754✔
1669
    {
1670
        if (nSrcStride == 3 && nDestStride == 4)
1,620✔
1671
        {
1672
            while (nIters >= 8)
2,106✔
1673
            {
1674
                pabyDest[4 * 0 + 0] = pabySrc[3 * 0 + 0];
1,620✔
1675
                pabyDest[4 * 0 + 1] = pabySrc[3 * 0 + 1];
1,620✔
1676
                pabyDest[4 * 0 + 2] = pabySrc[3 * 0 + 2];
1,620✔
1677
                pabyDest[4 * 1 + 0] = pabySrc[3 * 1 + 0];
1,620✔
1678
                pabyDest[4 * 1 + 1] = pabySrc[3 * 1 + 1];
1,620✔
1679
                pabyDest[4 * 1 + 2] = pabySrc[3 * 1 + 2];
1,620✔
1680
                pabyDest[4 * 2 + 0] = pabySrc[3 * 2 + 0];
1,620✔
1681
                pabyDest[4 * 2 + 1] = pabySrc[3 * 2 + 1];
1,620✔
1682
                pabyDest[4 * 2 + 2] = pabySrc[3 * 2 + 2];
1,620✔
1683
                pabyDest[4 * 3 + 0] = pabySrc[3 * 3 + 0];
1,620✔
1684
                pabyDest[4 * 3 + 1] = pabySrc[3 * 3 + 1];
1,620✔
1685
                pabyDest[4 * 3 + 2] = pabySrc[3 * 3 + 2];
1,620✔
1686
                pabyDest[4 * 4 + 0] = pabySrc[3 * 4 + 0];
1,620✔
1687
                pabyDest[4 * 4 + 1] = pabySrc[3 * 4 + 1];
1,620✔
1688
                pabyDest[4 * 4 + 2] = pabySrc[3 * 4 + 2];
1,620✔
1689
                pabyDest[4 * 5 + 0] = pabySrc[3 * 5 + 0];
1,620✔
1690
                pabyDest[4 * 5 + 1] = pabySrc[3 * 5 + 1];
1,620✔
1691
                pabyDest[4 * 5 + 2] = pabySrc[3 * 5 + 2];
1,620✔
1692
                pabyDest[4 * 6 + 0] = pabySrc[3 * 6 + 0];
1,620✔
1693
                pabyDest[4 * 6 + 1] = pabySrc[3 * 6 + 1];
1,620✔
1694
                pabyDest[4 * 6 + 2] = pabySrc[3 * 6 + 2];
1,620✔
1695
                pabyDest[4 * 7 + 0] = pabySrc[3 * 7 + 0];
1,620✔
1696
                pabyDest[4 * 7 + 1] = pabySrc[3 * 7 + 1];
1,620✔
1697
                pabyDest[4 * 7 + 2] = pabySrc[3 * 7 + 2];
1,620✔
1698
                pabySrc += 3 * 8;
1,620✔
1699
                pabyDest += 4 * 8;
1,620✔
1700
                nIters -= 8;
1,620✔
1701
            }
1702
            while (nIters-- > 0)
648✔
1703
            {
1704
                pabyDest[0] = pabySrc[0];
162✔
1705
                pabyDest[1] = pabySrc[1];
162✔
1706
                pabyDest[2] = pabySrc[2];
162✔
1707
                pabySrc += 3;
162✔
1708
                pabyDest += 4;
162✔
1709
            }
1710
        }
1711
        else
1712
        {
1713
            while (nIters-- > 0)
53,622✔
1714
            {
1715
                pabyDest[0] = pabySrc[0];
52,488✔
1716
                pabyDest[1] = pabySrc[1];
52,488✔
1717
                pabyDest[2] = pabySrc[2];
52,488✔
1718
                pabySrc += nSrcStride;
52,488✔
1719
                pabyDest += nDestStride;
52,488✔
1720
            }
1721
        }
1722
    }
1723
    else
1724
    {
1725
        while (nIters-- > 0)
53,622✔
1726
        {
1727
            for (int iBand = 0; iBand < nBandCount; ++iBand)
236,196✔
1728
                pabyDest[iBand] = pabySrc[iBand];
183,708✔
1729
            pabySrc += nSrcStride;
52,488✔
1730
            pabyDest += nDestStride;
52,488✔
1731
        }
1732
    }
1733
}
2,754✔
1734

1735
/************************************************************************/
1736
/*                         CommonDirectIO()                             */
1737
/************************************************************************/
1738

1739
// #define DEBUG_REACHED_VIRTUAL_MEM_IO
1740
#ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
1741
static int anReachedVirtualMemIO[52] = {0};
1742
#define REACHED(x) anReachedVirtualMemIO[x] = 1
1743
#else
1744
#define REACHED(x)
1745
#endif
1746

1747
template <class FetchBuffer>
1748
CPLErr GTiffDataset::CommonDirectIO(FetchBuffer &oFetcher, int nXOff, int nYOff,
1,584✔
1749
                                    int nXSize, int nYSize, void *pData,
1750
                                    int nBufXSize, int nBufYSize,
1751
                                    GDALDataType eBufType, int nBandCount,
1752
                                    const int *panBandMap, GSpacing nPixelSpace,
1753
                                    GSpacing nLineSpace, GSpacing nBandSpace)
1754
{
1755
    const auto poFirstBand =
1756
        cpl::down_cast<GTiffRasterBand *>(GetRasterBand(1));
1,584✔
1757
    const GDALDataType eDataType = poFirstBand->GetRasterDataType();
1,584✔
1758
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
1,584✔
1759
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
1,584✔
1760
    const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
1,584✔
1761

1762
    // Get strip offsets.
1763
    toff_t *panOffsets = nullptr;
1,584✔
1764
    if (!TIFFGetField(m_hTIFF,
1,584✔
1765
                      (TIFFIsTiled(m_hTIFF)) ? TIFFTAG_TILEOFFSETS
1,584✔
1766
                                             : TIFFTAG_STRIPOFFSETS,
1767
                      &panOffsets) ||
3,168✔
1768
        panOffsets == nullptr)
1,584✔
1769
    {
1770
        return CE_Failure;
×
1771
    }
1772

1773
    bool bUseContigImplementation = m_nPlanarConfig == PLANARCONFIG_CONTIG &&
736✔
1774
                                    nBandCount > 1 && nBandSpace == nBufDTSize;
2,320✔
1775
    if (bUseContigImplementation)
1,584✔
1776
    {
1777
        for (int iBand = 0; iBand < nBandCount; ++iBand)
1,002✔
1778
        {
1779
            const int nBand = panBandMap[iBand];
786✔
1780
            if (nBand != iBand + 1)
786✔
1781
            {
1782
                bUseContigImplementation = false;
×
1783
                break;
×
1784
            }
1785
        }
1786
    }
1787

1788
    const int nBandsPerBlock =
1,584✔
1789
        m_nPlanarConfig == PLANARCONFIG_SEPARATE ? 1 : nBands;
1,584✔
1790
    const int nBandsPerBlockDTSize = nBandsPerBlock * nDTSize;
1,584✔
1791
    const bool bNoTypeChange = (eDataType == eBufType);
1,584✔
1792
    const bool bNoXResampling = (nXSize == nBufXSize);
1,584✔
1793
    const bool bNoXResamplingNoTypeChange = (bNoTypeChange && bNoXResampling);
1,584✔
1794
    const bool bByteOnly = (bNoTypeChange && nDTSize == 1);
1,584✔
1795
    const bool bByteNoXResampling = (bByteOnly && bNoXResamplingNoTypeChange);
1,584✔
1796
    const bool bIsByteSwapped = CPL_TO_BOOL(TIFFIsByteSwapped(m_hTIFF));
1,584✔
1797
    const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
1,584✔
1798
    const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
1,584✔
1799

1800
    int bNoDataSetIn = FALSE;
1,584✔
1801
    double dfNoData = poFirstBand->GetNoDataValue(&bNoDataSetIn);
1,584✔
1802
    GByte abyNoData = 0;
1,584✔
1803
    if (!bNoDataSetIn)
1,584✔
1804
        dfNoData = 0;
1,584✔
1805
    else if (dfNoData >= 0 && dfNoData <= 255)
×
1806
        abyNoData = static_cast<GByte>(dfNoData + 0.5);
×
1807

1808
    // cppcheck-suppress knownConditionTrueFalse
1809
    if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) && bNoXResampling &&
1,226✔
1810
        (nYSize == nBufYSize) && m_nPlanarConfig == PLANARCONFIG_CONTIG &&
1,226✔
1811
        nBandCount > 1)
1812
    {
1813
        GByte *pabyData = static_cast<GByte *>(pData);
69✔
1814
        for (int y = 0; y < nBufYSize;)
541✔
1815
        {
1816
            const int nSrcLine = nYOff + y;
478✔
1817
            const int nBlockYOff = nSrcLine / m_nBlockYSize;
478✔
1818
            const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
478✔
1819
            const int nUsedBlockHeight =
478✔
1820
                std::min(nBufYSize - y, m_nBlockYSize - nYOffsetInBlock);
478✔
1821

1822
            int nBlockXOff = nXOff / m_nBlockXSize;
478✔
1823
            int nXOffsetInBlock = nXOff % m_nBlockXSize;
478✔
1824
            int nBlockId = poFirstBand->ComputeBlockId(nBlockXOff, nBlockYOff);
478✔
1825

1826
            int x = 0;
478✔
1827
            while (x < nBufXSize)
2,368✔
1828
            {
1829
                const toff_t nCurOffset = panOffsets[nBlockId];
1,896✔
1830
                const int nUsedBlockWidth =
1,896✔
1831
                    std::min(m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
1,896✔
1832

1833
                if (nCurOffset == 0)
1,896✔
1834
                {
1835
                    REACHED(30);
1836
                    for (int k = 0; k < nUsedBlockHeight; ++k)
7,287✔
1837
                    {
1838
                        GByte *pabyLocalData =
6,813✔
1839
                            pabyData + (y + k) * nLineSpace + x * nPixelSpace;
6,813✔
1840
                        for (int iBand = 0; iBand < nBandCount; ++iBand)
33,573✔
1841
                        {
1842
                            GByte *pabyLocalDataBand =
26,760✔
1843
                                pabyLocalData + iBand * nBandSpace;
26,760✔
1844

1845
                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
26,760✔
1846
                                          pabyLocalDataBand, eBufType,
1847
                                          static_cast<int>(nPixelSpace),
1848
                                          nUsedBlockWidth);
1849
                        }
1850
                    }
1851
                }
1852
                else
1853
                {
1854
                    const int nByteOffsetInBlock =
1,422✔
1855
                        nYOffsetInBlock * m_nBlockXSize * nBandsPerBlockDTSize;
1,422✔
1856
                    const GByte *pabyLocalSrcDataK0 = oFetcher.FetchBytes(
2,844✔
1857
                        nCurOffset + nByteOffsetInBlock,
1,422✔
1858
                        m_nBlockXSize * nUsedBlockHeight * nBandsPerBlock,
1,422✔
1859
                        nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
1860
                    if (pabyLocalSrcDataK0 == nullptr)
1,422✔
1861
                        return CE_Failure;
6✔
1862

1863
                    for (int k = 0; k < nUsedBlockHeight; ++k)
21,852✔
1864
                    {
1865
                        GByte *pabyLocalData =
20,436✔
1866
                            pabyData + (y + k) * nLineSpace + x * nPixelSpace;
20,436✔
1867
                        const GByte *pabyLocalSrcData =
20,436✔
1868
                            pabyLocalSrcDataK0 +
1869
                            (k * m_nBlockXSize + nXOffsetInBlock) *
20,436✔
1870
                                nBandsPerBlockDTSize;
1871

1872
                        if (bUseContigImplementation && nBands == nBandCount &&
20,436✔
1873
                            nPixelSpace == nBandsPerBlockDTSize)
9,702✔
1874
                        {
1875
                            REACHED(31);
1876
                            GDALCopyWords(pabyLocalSrcData, eDataType, nDTSize,
7,272✔
1877
                                          pabyLocalData, eBufType, nBufDTSize,
1878
                                          nUsedBlockWidth * nBands);
7,272✔
1879
                        }
1880
                        else
1881
                        {
1882
                            REACHED(32);
1883
                            for (int iBand = 0; iBand < nBandCount; ++iBand)
63,846✔
1884
                            {
1885
                                GByte *pabyLocalDataBand =
50,682✔
1886
                                    pabyLocalData + iBand * nBandSpace;
50,682✔
1887
                                const GByte *pabyLocalSrcDataBand =
50,682✔
1888
                                    pabyLocalSrcData +
1889
                                    (panBandMap[iBand] - 1) * nDTSize;
50,682✔
1890

1891
                                GDALCopyWords(pabyLocalSrcDataBand, eDataType,
50,682✔
1892
                                              nBandsPerBlockDTSize,
1893
                                              pabyLocalDataBand, eBufType,
1894
                                              static_cast<int>(nPixelSpace),
1895
                                              nUsedBlockWidth);
1896
                            }
1897
                        }
1898
                    }
1899
                }
1900

1901
                nXOffsetInBlock = 0;
1,890✔
1902
                ++nBlockXOff;
1,890✔
1903
                ++nBlockId;
1,890✔
1904
                x += nUsedBlockWidth;
1,890✔
1905
            }
1906

1907
            y += nUsedBlockHeight;
472✔
1908
        }
1909
    }
1910
    // cppcheck-suppress knownConditionTrueFalse
1911
    else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
1,088✔
1912
             bNoXResampling && (nYSize == nBufYSize))
1,088✔
1913
    // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
1914
    {
1915
        for (int iBand = 0; iBand < nBandCount; ++iBand)
705✔
1916
        {
1917
            GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
356✔
1918
            const int nBand = panBandMap[iBand];
356✔
1919
            auto poCurBand =
1920
                cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
356✔
1921
            for (int y = 0; y < nBufYSize;)
2,733✔
1922
            {
1923
                const int nSrcLine = nYOff + y;
2,384✔
1924
                const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2,384✔
1925
                const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2,384✔
1926
                const int nUsedBlockHeight =
2,384✔
1927
                    std::min(nBufYSize - y, m_nBlockYSize - nYOffsetIm_nBlock);
2,384✔
1928

1929
                int nBlockXOff = nXOff / m_nBlockXSize;
2,384✔
1930
                int nXOffsetInBlock = nXOff % m_nBlockXSize;
2,384✔
1931
                int nBlockId =
1932
                    poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2,384✔
1933

1934
                int x = 0;
2,384✔
1935
                while (x < nBufXSize)
11,368✔
1936
                {
1937
                    const toff_t nCurOffset = panOffsets[nBlockId];
8,991✔
1938
                    const int nUsedBlockWidth = std::min(
8,991✔
1939
                        m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
8,991✔
1940

1941
                    if (nCurOffset == 0)
8,991✔
1942
                    {
1943
                        REACHED(35);
1944
                        for (int k = 0; k < nUsedBlockHeight; ++k)
42,642✔
1945
                        {
1946
                            GByte *pabyLocalData = pabyData +
39,858✔
1947
                                                   (y + k) * nLineSpace +
39,858✔
1948
                                                   x * nPixelSpace;
39,858✔
1949

1950
                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
39,858✔
1951
                                          pabyLocalData, eBufType,
1952
                                          static_cast<int>(nPixelSpace),
1953
                                          nUsedBlockWidth);
1954
                        }
1955
                    }
1956
                    else
1957
                    {
1958
                        const int nByteOffsetIm_nBlock = nYOffsetIm_nBlock *
6,207✔
1959
                                                         m_nBlockXSize *
6,207✔
1960
                                                         nBandsPerBlockDTSize;
1961
                        const GByte *pabyLocalSrcDataK0 = oFetcher.FetchBytes(
12,414✔
1962
                            nCurOffset + nByteOffsetIm_nBlock,
6,207✔
1963
                            m_nBlockXSize * nUsedBlockHeight * nBandsPerBlock,
6,207✔
1964
                            nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
1965
                        if (pabyLocalSrcDataK0 == nullptr)
6,207✔
1966
                            return CE_Failure;
7✔
1967

1968
                        if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
6,200✔
1969
                        {
1970
                            REACHED(36);
1971
                            pabyLocalSrcDataK0 += (nBand - 1) * nDTSize;
1,464✔
1972
                        }
1973
                        else
1974
                        {
1975
                            REACHED(37);
1976
                        }
1977

1978
                        for (int k = 0; k < nUsedBlockHeight; ++k)
94,580✔
1979
                        {
1980
                            GByte *pabyLocalData = pabyData +
88,380✔
1981
                                                   (y + k) * nLineSpace +
88,380✔
1982
                                                   x * nPixelSpace;
88,380✔
1983
                            const GByte *pabyLocalSrcData =
88,380✔
1984
                                pabyLocalSrcDataK0 +
1985
                                (k * m_nBlockXSize + nXOffsetInBlock) *
88,380✔
1986
                                    nBandsPerBlockDTSize;
1987

1988
                            GDALCopyWords(
88,380✔
1989
                                pabyLocalSrcData, eDataType,
1990
                                nBandsPerBlockDTSize, pabyLocalData, eBufType,
1991
                                static_cast<int>(nPixelSpace), nUsedBlockWidth);
1992
                        }
1993
                    }
1994

1995
                    nXOffsetInBlock = 0;
8,984✔
1996
                    ++nBlockXOff;
8,984✔
1997
                    ++nBlockId;
8,984✔
1998
                    x += nUsedBlockWidth;
8,984✔
1999
                }
2000

2001
                y += nUsedBlockHeight;
2,377✔
2002
            }
2003
        }
2004
    }
2005
    // cppcheck-suppress knownConditionTrueFalse
2006
    else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
188✔
2007
             m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount > 1)
188✔
2008
    {
2009
        GByte *pabyData = static_cast<GByte *>(pData);
40✔
2010
        int anSrcYOffset[256] = {0};
40✔
2011
        for (int y = 0; y < nBufYSize;)
237✔
2012
        {
2013
            const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
200✔
2014
            const int nSrcLine = static_cast<int>(dfYOffStart);
200✔
2015
            const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
200✔
2016
            const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
200✔
2017
            const int nBaseByteOffsetIm_nBlock =
200✔
2018
                nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
200✔
2019
            int ychunk = 1;
200✔
2020
            int nLastSrcLineK = nSrcLine;
200✔
2021
            anSrcYOffset[0] = 0;
200✔
2022
            for (int k = 1; k < nBufYSize - y; ++k)
24,052✔
2023
            {
2024
                int nSrcLineK =
24,012✔
2025
                    nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
24,012✔
2026
                const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
24,012✔
2027
                if (k < 256)
24,012✔
2028
                    anSrcYOffset[k] =
15,012✔
2029
                        ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
15,012✔
2030
                        m_nBlockXSize * nBandsPerBlockDTSize;
15,012✔
2031
                if (nBlockYOffK != m_nBlockYOff)
24,012✔
2032
                {
2033
                    break;
160✔
2034
                }
2035
                ++ychunk;
23,852✔
2036
                nLastSrcLineK = nSrcLineK;
23,852✔
2037
            }
2038
            const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
200✔
2039
            // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
2040

2041
            double dfSrcX = nXOff + 0.5 * dfSrcXInc;
200✔
2042
            int nCurBlockXOff = 0;
200✔
2043
            int nNextBlockXOff = 0;
200✔
2044
            toff_t nCurOffset = 0;
200✔
2045
            const GByte *pabyLocalSrcDataStartLine = nullptr;
200✔
2046
            for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
21,601✔
2047
            {
2048
                const int nSrcPixel = static_cast<int>(dfSrcX);
21,404✔
2049
                if (nSrcPixel >= nNextBlockXOff)
21,404✔
2050
                {
2051
                    const int nBlockXOff = nSrcPixel / m_nBlockXSize;
584✔
2052
                    nCurBlockXOff = nBlockXOff * m_nBlockXSize;
584✔
2053
                    nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
584✔
2054
                    const int nBlockId =
2055
                        poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
584✔
2056
                    nCurOffset = panOffsets[nBlockId];
584✔
2057
                    if (nCurOffset != 0)
584✔
2058
                    {
2059
                        pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
876✔
2060
                            nCurOffset + nBaseByteOffsetIm_nBlock,
438✔
2061
                            m_nBlockXSize * nBandsPerBlock * nUsedBlockHeight,
438✔
2062
                            nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
2063
                        if (pabyLocalSrcDataStartLine == nullptr)
438✔
2064
                            return CE_Failure;
3✔
2065
                    }
2066
                }
2067

2068
                if (nCurOffset == 0)
21,401✔
2069
                {
2070
                    REACHED(38);
2071

2072
                    for (int k = 0; k < ychunk; ++k)
442,476✔
2073
                    {
2074
                        GByte *const pabyLocalData =
437,062✔
2075
                            pabyData + (y + k) * nLineSpace + x * nPixelSpace;
437,062✔
2076
                        for (int iBand = 0; iBand < nBandCount; ++iBand)
2,185,310✔
2077
                        {
2078
                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
1,748,250✔
2079
                                          pabyLocalData + nBandSpace * iBand,
1,748,250✔
2080
                                          eBufType, 0, 1);
2081
                        }
2082
                    }
2083
                }
2084
                else
2085
                {
2086
                    const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
15,987✔
2087
                    double dfYOff = dfYOffStart;
15,987✔
2088
                    const GByte *const pabyLocalSrcDataK0 =
15,987✔
2089
                        pabyLocalSrcDataStartLine +
2090
                        nXOffsetInBlock * nBandsPerBlockDTSize;
15,987✔
2091
                    GByte *pabyLocalData =
15,987✔
2092
                        pabyData + y * nLineSpace + x * nPixelSpace;
15,987✔
2093
                    for (int k = 0; k < ychunk;
1,287,130✔
2094
                         ++k, pabyLocalData += nLineSpace)
1,271,140✔
2095
                    {
2096
                        const GByte *pabyLocalSrcData = nullptr;
1,271,140✔
2097
                        if (ychunk <= 256)
1,271,140✔
2098
                        {
2099
                            REACHED(39);
2100
                            pabyLocalSrcData =
695,139✔
2101
                                pabyLocalSrcDataK0 + anSrcYOffset[k];
695,139✔
2102
                        }
2103
                        else
2104
                        {
2105
                            REACHED(40);
2106
                            const int nYOffsetIm_nBlockK =
576,000✔
2107
                                static_cast<int>(dfYOff) % m_nBlockYSize;
576,000✔
2108
                            // CPLAssert(
2109
                            //     nYOffsetIm_nBlockK - nYOffsetIm_nBlock <=
2110
                            //     nUsedBlockHeight);
2111
                            pabyLocalSrcData =
576,000✔
2112
                                pabyLocalSrcDataK0 +
2113
                                (nYOffsetIm_nBlockK - nYOffsetIm_nBlock) *
576,000✔
2114
                                    m_nBlockXSize * nBandsPerBlockDTSize;
576,000✔
2115
                            dfYOff += dfSrcYInc;
576,000✔
2116
                        }
2117

2118
                        if (bByteOnly)
1,271,140✔
2119
                        {
2120
                            REACHED(41);
2121
                            for (int iBand = 0; iBand < nBandCount; ++iBand)
2,118,560✔
2122
                            {
2123
                                GByte *pabyLocalDataBand =
1,694,850✔
2124
                                    pabyLocalData + iBand * nBandSpace;
1,694,850✔
2125
                                const GByte *pabyLocalSrcDataBand =
1,694,850✔
2126
                                    pabyLocalSrcData + (panBandMap[iBand] - 1);
1,694,850✔
2127
                                *pabyLocalDataBand = *pabyLocalSrcDataBand;
1,694,850✔
2128
                            }
2129
                        }
2130
                        else
2131
                        {
2132
                            REACHED(42);
2133
                            for (int iBand = 0; iBand < nBandCount; ++iBand)
4,237,130✔
2134
                            {
2135
                                GByte *pabyLocalDataBand =
3,389,700✔
2136
                                    pabyLocalData + iBand * nBandSpace;
3,389,700✔
2137
                                const GByte *pabyLocalSrcDataBand =
3,389,700✔
2138
                                    pabyLocalSrcData +
2139
                                    (panBandMap[iBand] - 1) * nDTSize;
3,389,700✔
2140

2141
                                GDALCopyWords(pabyLocalSrcDataBand, eDataType,
3,389,700✔
2142
                                              0, pabyLocalDataBand, eBufType, 0,
2143
                                              1);
2144
                            }
2145
                        }
2146
                    }
2147
                }
2148
            }
2149

2150
            y += ychunk;
197✔
2151
        }
2152
    }
2153
    // cppcheck-suppress knownConditionTrueFalse
2154
    else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
148✔
2155
    // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
2156
    {
2157
        for (int iBand = 0; iBand < nBandCount; ++iBand)
294✔
2158
        {
2159
            GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
148✔
2160
            const int nBand = panBandMap[iBand];
148✔
2161
            auto poCurBand =
2162
                cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
148✔
2163
            int anSrcYOffset[256] = {0};
148✔
2164
            for (int y = 0; y < nBufYSize;)
914✔
2165
            {
2166
                const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
768✔
2167
                const int nSrcLine = static_cast<int>(dfYOffStart);
768✔
2168
                const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
768✔
2169
                const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
768✔
2170
                const int nBaseByteOffsetIm_nBlock =
768✔
2171
                    nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
768✔
2172
                int ychunk = 1;
768✔
2173
                int nLastSrcLineK = nSrcLine;
768✔
2174
                anSrcYOffset[0] = 0;
768✔
2175
                for (int k = 1; k < nBufYSize - y; ++k)
77,348✔
2176
                {
2177
                    const int nSrcLineK =
77,200✔
2178
                        nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
77,200✔
2179
                    const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
77,200✔
2180
                    if (k < 256)
77,200✔
2181
                        anSrcYOffset[k] =
50,200✔
2182
                            ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
50,200✔
2183
                            m_nBlockXSize * nBandsPerBlockDTSize;
50,200✔
2184
                    if (nBlockYOffK != m_nBlockYOff)
77,200✔
2185
                    {
2186
                        break;
620✔
2187
                    }
2188
                    ++ychunk;
76,580✔
2189
                    nLastSrcLineK = nSrcLineK;
76,580✔
2190
                }
2191
                const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
768✔
2192
                // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
2193

2194
                double dfSrcX = nXOff + 0.5 * dfSrcXInc;
768✔
2195
                int nCurBlockXOff = 0;
768✔
2196
                int nNextBlockXOff = 0;
768✔
2197
                toff_t nCurOffset = 0;
768✔
2198
                const GByte *pabyLocalSrcDataStartLine = nullptr;
768✔
2199
                for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
95,758✔
2200
                {
2201
                    int nSrcPixel = static_cast<int>(dfSrcX);
94,992✔
2202
                    if (nSrcPixel >= nNextBlockXOff)
94,992✔
2203
                    {
2204
                        const int nBlockXOff = nSrcPixel / m_nBlockXSize;
2,256✔
2205
                        nCurBlockXOff = nBlockXOff * m_nBlockXSize;
2,256✔
2206
                        nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
2,256✔
2207
                        const int nBlockId =
2208
                            poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2,256✔
2209
                        nCurOffset = panOffsets[nBlockId];
2,256✔
2210
                        if (nCurOffset != 0)
2,256✔
2211
                        {
2212
                            pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
3,056✔
2213
                                nCurOffset + nBaseByteOffsetIm_nBlock,
1,528✔
2214
                                m_nBlockXSize * nBandsPerBlock *
1,528✔
2215
                                    nUsedBlockHeight,
2216
                                nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
2217
                            if (pabyLocalSrcDataStartLine == nullptr)
1,528✔
2218
                                return CE_Failure;
2✔
2219

2220
                            if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
1,526✔
2221
                            {
2222
                                REACHED(45);
2223
                                pabyLocalSrcDataStartLine +=
216✔
2224
                                    (nBand - 1) * nDTSize;
216✔
2225
                            }
2226
                            else
2227
                            {
2228
                                REACHED(46);
2229
                            }
2230
                        }
2231
                    }
2232

2233
                    if (nCurOffset == 0)
94,990✔
2234
                    {
2235
                        REACHED(47);
2236

2237
                        for (int k = 0; k < ychunk; ++k)
2,215,820✔
2238
                        {
2239
                            GByte *const pabyLocalData = pabyData +
2,185,310✔
2240
                                                         (y + k) * nLineSpace +
2,185,310✔
2241
                                                         x * nPixelSpace;
2,185,310✔
2242

2243
                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
2,185,310✔
2244
                                          pabyLocalData, eBufType, 0, 1);
2245
                        }
2246
                    }
2247
                    else
2248
                    {
2249
                        const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
64,478✔
2250
                        double dfYOff = dfYOffStart;
64,478✔
2251
                        const GByte *const pabyLocalSrcDataK0 =
64,478✔
2252
                            pabyLocalSrcDataStartLine +
2253
                            nXOffsetInBlock * nBandsPerBlockDTSize;
64,478✔
2254
                        GByte *pabyLocalData =
64,478✔
2255
                            pabyData + y * nLineSpace + x * nPixelSpace;
64,478✔
2256
                        for (int k = 0; k < ychunk;
4,519,950✔
2257
                             ++k, pabyLocalData += nLineSpace)
4,455,470✔
2258
                        {
2259
                            const GByte *pabyLocalSrcData = nullptr;
4,455,470✔
2260
                            if (ychunk <= 256)
4,455,470✔
2261
                            {
2262
                                REACHED(48);
2263
                                pabyLocalSrcData =
2,919,470✔
2264
                                    pabyLocalSrcDataK0 + anSrcYOffset[k];
2,919,470✔
2265
                            }
2266
                            else
2267
                            {
2268
                                REACHED(49);
2269
                                const int nYOffsetIm_nBlockK =
1,536,000✔
2270
                                    static_cast<int>(dfYOff) % m_nBlockYSize;
1,536,000✔
2271
                                // CPLAssert(
2272
                                //     nYOffsetIm_nBlockK - nYOffsetIm_nBlock <=
2273
                                //     nUsedBlockHeight);
2274
                                pabyLocalSrcData =
1,536,000✔
2275
                                    pabyLocalSrcDataK0 +
2276
                                    (nYOffsetIm_nBlockK - nYOffsetIm_nBlock) *
1,536,000✔
2277
                                        m_nBlockXSize * nBandsPerBlockDTSize;
1,536,000✔
2278
                                dfYOff += dfSrcYInc;
1,536,000✔
2279
                            }
2280

2281
                            if (bByteOnly)
4,455,470✔
2282
                            {
2283
                                REACHED(50);
2284

2285
                                *pabyLocalData = *pabyLocalSrcData;
2,121,160✔
2286
                            }
2287
                            else
2288
                            {
2289
                                REACHED(51);
2290

2291
                                GDALCopyWords(pabyLocalSrcData, eDataType, 0,
2,334,310✔
2292
                                              pabyLocalData, eBufType, 0, 1);
2293
                            }
2294
                        }
2295
                    }
2296
                }
2297

2298
                y += ychunk;
766✔
2299
            }
2300
        }
2301
    }
2302
    else if (bUseContigImplementation)
971✔
2303
    {
2304
        // cppcheck-suppress knownConditionTrueFalse
2305
        if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
160✔
2306
        {
2307
            GByte *pabyData = static_cast<GByte *>(pData);
83✔
2308
            for (int y = 0; y < nBufYSize; ++y)
6,223✔
2309
            {
2310
                const int nSrcLine =
6,146✔
2311
                    nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
6,146✔
2312
                const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
6,146✔
2313
                const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
6,146✔
2314
                const int nBaseByteOffsetIm_nBlock =
6,146✔
2315
                    nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
6,146✔
2316

2317
                if (bNoXResampling)
6,146✔
2318
                {
2319
                    GByte *pabyLocalData = pabyData + y * nLineSpace;
5,693✔
2320
                    int nBlockXOff = nXOff / m_nBlockXSize;
5,693✔
2321
                    int nXOffsetInBlock = nXOff % m_nBlockXSize;
5,693✔
2322
                    int nBlockId =
2323
                        poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
5,693✔
2324

2325
                    int x = 0;
5,693✔
2326
                    while (x < nBufXSize)
27,668✔
2327
                    {
2328
                        const int nByteOffsetIm_nBlock =
21,978✔
2329
                            nBaseByteOffsetIm_nBlock +
2330
                            nXOffsetInBlock * nBandsPerBlockDTSize;
21,978✔
2331
                        const toff_t nCurOffset = panOffsets[nBlockId];
21,978✔
2332
                        const int nUsedBlockWidth = std::min(
21,978✔
2333
                            m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
21,978✔
2334

2335
                        int nIters = nUsedBlockWidth;
21,978✔
2336
                        if (nCurOffset == 0)
21,978✔
2337
                        {
2338
                            if (bByteNoXResampling)
3,768✔
2339
                            {
2340
                                REACHED(0);
2341
                                while (nIters-- > 0)
46,560✔
2342
                                {
2343
                                    for (int iBand = 0; iBand < nBandCount;
217,886✔
2344
                                         ++iBand)
2345
                                    {
2346
                                        pabyLocalData[iBand] = abyNoData;
172,964✔
2347
                                    }
2348
                                    pabyLocalData += nPixelSpace;
44,922✔
2349
                                }
2350
                            }
2351
                            else
2352
                            {
2353
                                REACHED(1);
2354
                                while (nIters-- > 0)
60,500✔
2355
                                {
2356
                                    GDALCopyWords(&dfNoData, GDT_Float64, 0,
58,370✔
2357
                                                  pabyLocalData, eBufType,
2358
                                                  static_cast<int>(nBandSpace),
2359
                                                  nBandCount);
2360
                                    pabyLocalData += nPixelSpace;
58,370✔
2361
                                }
2362
                            }
2363
                        }
2364
                        else
2365
                        {
2366
                            if (bNoTypeChange && nBands == nBandCount &&
18,210✔
2367
                                nPixelSpace == nBandsPerBlockDTSize)
13,836✔
2368
                            {
2369
                                REACHED(2);
2370
                                if (!oFetcher.FetchBytes(
10,191✔
2371
                                        pabyLocalData,
2372
                                        nCurOffset + nByteOffsetIm_nBlock,
10,191✔
2373
                                        nIters * nBandsPerBlock, nDTSize,
2374
                                        bIsByteSwapped, bIsComplex, nBlockId))
2375
                                {
2376
                                    return CE_Failure;
3✔
2377
                                }
2378
                                pabyLocalData +=
10,188✔
2379
                                    nIters * nBandsPerBlock * nDTSize;
10,188✔
2380
                            }
2381
                            else
2382
                            {
2383
                                const GByte *pabyLocalSrcData =
16,038✔
2384
                                    oFetcher.FetchBytes(
2385
                                        nCurOffset + nByteOffsetIm_nBlock,
8,019✔
2386
                                        nIters * nBandsPerBlock, nDTSize,
2387
                                        bIsByteSwapped, bIsComplex, nBlockId);
2388
                                if (pabyLocalSrcData == nullptr)
8,019✔
2389
                                    return CE_Failure;
×
2390
                                if (bByteNoXResampling)
8,019✔
2391
                                {
2392
                                    REACHED(3);
2393
                                    CopyContigByteMultiBand(
1,944✔
2394
                                        pabyLocalSrcData, nBandsPerBlockDTSize,
2395
                                        pabyLocalData,
2396
                                        static_cast<int>(nPixelSpace), nIters,
2397
                                        nBandCount);
2398
                                    pabyLocalData += nIters * nPixelSpace;
1,944✔
2399
                                }
2400
                                else
2401
                                {
2402
                                    REACHED(4);
2403
                                    while (nIters-- > 0)
170,100✔
2404
                                    {
2405
                                        GDALCopyWords(
164,025✔
2406
                                            pabyLocalSrcData, eDataType,
2407
                                            nDTSize, pabyLocalData, eBufType,
2408
                                            static_cast<int>(nBandSpace),
2409
                                            nBandCount);
2410
                                        pabyLocalSrcData +=
164,025✔
2411
                                            nBandsPerBlockDTSize;
164,025✔
2412
                                        pabyLocalData += nPixelSpace;
164,025✔
2413
                                    }
2414
                                }
2415
                            }
2416
                        }
2417

2418
                        nXOffsetInBlock = 0;
21,975✔
2419
                        ++nBlockXOff;
21,975✔
2420
                        ++nBlockId;
21,975✔
2421
                        x += nUsedBlockWidth;
21,975✔
2422
                    }
2423
                }
2424
                else  // Contig, tiled, potential resampling & data type change.
2425
                {
2426
                    const GByte *pabyLocalSrcDataStartLine = nullptr;
453✔
2427
                    GByte *pabyLocalData = pabyData + y * nLineSpace;
453✔
2428
                    double dfSrcX = nXOff + 0.5 * dfSrcXInc;
453✔
2429
                    int nCurBlockXOff = 0;
453✔
2430
                    int nNextBlockXOff = 0;
453✔
2431
                    toff_t nCurOffset = 0;
453✔
2432
                    for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
18,223✔
2433
                    {
2434
                        int nSrcPixel = static_cast<int>(dfSrcX);
17,773✔
2435
                        if (nSrcPixel >= nNextBlockXOff)
17,773✔
2436
                        {
2437
                            const int nBlockXOff = nSrcPixel / m_nBlockXSize;
1,337✔
2438
                            nCurBlockXOff = nBlockXOff * m_nBlockXSize;
1,337✔
2439
                            nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
1,337✔
2440
                            const int nBlockId = poFirstBand->ComputeBlockId(
1,337✔
2441
                                nBlockXOff, m_nBlockYOff);
2442
                            nCurOffset = panOffsets[nBlockId];
1,337✔
2443
                            if (nCurOffset != 0)
1,337✔
2444
                            {
2445
                                pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
2,178✔
2446
                                    nCurOffset + nBaseByteOffsetIm_nBlock,
1,089✔
2447
                                    m_nBlockXSize * nBandsPerBlock, nDTSize,
1,089✔
2448
                                    bIsByteSwapped, bIsComplex, nBlockId);
2449
                                if (pabyLocalSrcDataStartLine == nullptr)
1,089✔
2450
                                    return CE_Failure;
3✔
2451
                            }
2452
                        }
2453
                        const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
17,770✔
2454

2455
                        if (nCurOffset == 0)
17,770✔
2456
                        {
2457
                            REACHED(5);
2458
                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
3,364✔
2459
                                          pabyLocalData, eBufType,
2460
                                          static_cast<int>(nBandSpace),
2461
                                          nBandCount);
2462
                            pabyLocalData += nPixelSpace;
3,364✔
2463
                        }
2464
                        else
2465
                        {
2466
                            const GByte *pabyLocalSrcData =
14,406✔
2467
                                pabyLocalSrcDataStartLine +
2468
                                nXOffsetInBlock * nBandsPerBlockDTSize;
14,406✔
2469

2470
                            REACHED(6);
2471
                            if (bByteOnly)
14,406✔
2472
                            {
2473
                                for (int iBand = 0; iBand < nBands; ++iBand)
20,809✔
2474
                                    pabyLocalData[iBand] =
16,007✔
2475
                                        pabyLocalSrcData[iBand];
16,007✔
2476
                            }
2477
                            else
2478
                            {
2479
                                GDALCopyWords(pabyLocalSrcData, eDataType,
9,604✔
2480
                                              nDTSize, pabyLocalData, eBufType,
2481
                                              static_cast<int>(nBandSpace),
2482
                                              nBandCount);
2483
                            }
2484
                            pabyLocalData += nPixelSpace;
14,406✔
2485
                        }
2486
                    }
2487
                }
2488
            }
2489
        }
2490
        else  // Contig, striped organized.
2491
        {
2492
            GByte *pabyData = static_cast<GByte *>(pData);
77✔
2493
            for (int y = 0; y < nBufYSize; ++y)
5,746✔
2494
            {
2495
                const int nSrcLine =
5,675✔
2496
                    nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
5,675✔
2497
                const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
5,675✔
2498
                const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
5,675✔
2499
                const int nBlockId = m_nBlockYOff;
5,675✔
2500
                const toff_t nCurOffset = panOffsets[nBlockId];
5,675✔
2501
                if (nCurOffset == 0)
5,675✔
2502
                {
2503
                    REACHED(7);
2504
                    for (int x = 0; x < nBufXSize; ++x)
107,696✔
2505
                    {
2506
                        GDALCopyWords(
106,656✔
2507
                            &dfNoData, GDT_Float64, 0,
2508
                            pabyData + y * nLineSpace + x * nPixelSpace,
106,656✔
2509
                            eBufType, static_cast<int>(nBandSpace), nBandCount);
2510
                    }
2511
                }
2512
                else
2513
                {
2514
                    GByte *pabyLocalData = pabyData + y * nLineSpace;
4,635✔
2515
                    const int nBaseByteOffsetIm_nBlock =
4,635✔
2516
                        (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
4,635✔
2517
                        nBandsPerBlockDTSize;
2518

2519
                    if (bNoXResamplingNoTypeChange && nBands == nBandCount &&
4,635✔
2520
                        nPixelSpace == nBandsPerBlockDTSize)
2,808✔
2521
                    {
2522
                        REACHED(8);
2523
                        if (!oFetcher.FetchBytes(
2,079✔
2524
                                pabyLocalData,
2525
                                nCurOffset + nBaseByteOffsetIm_nBlock,
2,079✔
2526
                                nXSize * nBandsPerBlock, nDTSize,
2527
                                bIsByteSwapped, bIsComplex, nBlockId))
2528
                        {
2529
                            return CE_Failure;
3✔
2530
                        }
2531
                    }
2532
                    else
2533
                    {
2534
                        const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
5,112✔
2535
                            nCurOffset + nBaseByteOffsetIm_nBlock,
2,556✔
2536
                            nXSize * nBandsPerBlock, nDTSize, bIsByteSwapped,
2537
                            bIsComplex, nBlockId);
2538
                        if (pabyLocalSrcData == nullptr)
2,556✔
2539
                            return CE_Failure;
3✔
2540

2541
                        if (bByteNoXResampling)
2,553✔
2542
                        {
2543
                            REACHED(9);
2544
                            CopyContigByteMultiBand(
486✔
2545
                                pabyLocalSrcData, nBandsPerBlockDTSize,
2546
                                pabyLocalData, static_cast<int>(nPixelSpace),
2547
                                nBufXSize, nBandCount);
2548
                        }
2549
                        else if (bByteOnly)
2,067✔
2550
                        {
2551
                            REACHED(10);
2552
                            double dfSrcX = 0.5 * dfSrcXInc;
122✔
2553
                            for (int x = 0; x < nBufXSize;
4,924✔
2554
                                 ++x, dfSrcX += dfSrcXInc)
2555
                            {
2556
                                const int nSrcPixelMinusXOff =
4,802✔
2557
                                    static_cast<int>(dfSrcX);
2558
                                for (int iBand = 0; iBand < nBandCount; ++iBand)
24,010✔
2559
                                {
2560
                                    pabyLocalData[x * nPixelSpace + iBand] =
19,208✔
2561
                                        pabyLocalSrcData
2562
                                            [nSrcPixelMinusXOff *
19,208✔
2563
                                                 nBandsPerBlockDTSize +
19,208✔
2564
                                             iBand];
2565
                                }
2566
                            }
2567
                        }
2568
                        else
2569
                        {
2570
                            REACHED(11);
2571
                            double dfSrcX = 0.5 * dfSrcXInc;
1,945✔
2572
                            for (int x = 0; x < nBufXSize;
149,330✔
2573
                                 ++x, dfSrcX += dfSrcXInc)
2574
                            {
2575
                                int nSrcPixelMinusXOff =
147,385✔
2576
                                    static_cast<int>(dfSrcX);
2577
                                GDALCopyWords(
147,385✔
2578
                                    pabyLocalSrcData + nSrcPixelMinusXOff *
147,385✔
2579
                                                           nBandsPerBlockDTSize,
2580
                                    eDataType, nDTSize,
2581
                                    pabyLocalData + x * nPixelSpace, eBufType,
147,385✔
2582
                                    static_cast<int>(nBandSpace), nBandCount);
2583
                            }
2584
                        }
2585
                    }
2586
                }
2587
            }
2588
        }
2589
    }
2590
    else  // Non-contig reading case.
2591
    {
2592
        // cppcheck-suppress knownConditionTrueFalse
2593
        if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
811✔
2594
        {
2595
            for (int iBand = 0; iBand < nBandCount; ++iBand)
1,261✔
2596
            {
2597
                const int nBand = panBandMap[iBand];
909✔
2598
                auto poCurBand =
2599
                    cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
909✔
2600
                GByte *const pabyData =
909✔
2601
                    static_cast<GByte *>(pData) + iBand * nBandSpace;
909✔
2602
                for (int y = 0; y < nBufYSize; ++y)
273,017✔
2603
                {
2604
                    const int nSrcLine =
272,120✔
2605
                        nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
272,120✔
2606
                    const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
272,120✔
2607
                    const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
272,120✔
2608

2609
                    int nBaseByteOffsetIm_nBlock = nYOffsetIm_nBlock *
272,120✔
2610
                                                   m_nBlockXSize *
272,120✔
2611
                                                   nBandsPerBlockDTSize;
2612
                    if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
272,120✔
2613
                    {
2614
                        REACHED(12);
2615
                        nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
138,831✔
2616
                    }
2617
                    else
2618
                    {
2619
                        REACHED(13);
2620
                    }
2621

2622
                    if (bNoXResampling)
272,120✔
2623
                    {
2624
                        GByte *pabyLocalData = pabyData + y * nLineSpace;
56,838✔
2625
                        int nBlockXOff = nXOff / m_nBlockXSize;
56,838✔
2626
                        int nBlockId =
2627
                            poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
56,838✔
2628
                        int nXOffsetInBlock = nXOff % m_nBlockXSize;
56,838✔
2629

2630
                        int x = 0;
56,838✔
2631
                        while (x < nBufXSize)
278,922✔
2632
                        {
2633
                            const int nByteOffsetIm_nBlock =
222,094✔
2634
                                nBaseByteOffsetIm_nBlock +
2635
                                nXOffsetInBlock * nBandsPerBlockDTSize;
222,094✔
2636
                            const toff_t nCurOffset = panOffsets[nBlockId];
222,094✔
2637
                            const int nUsedBlockWidth = std::min(
222,094✔
2638
                                m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
222,094✔
2639
                            int nIters = nUsedBlockWidth;
222,094✔
2640

2641
                            if (nCurOffset == 0)
222,094✔
2642
                            {
2643
                                REACHED(16);
2644
                                GDALCopyWords(&dfNoData, GDT_Float64, 0,
52,038✔
2645
                                              pabyLocalData, eBufType,
2646
                                              static_cast<int>(nPixelSpace),
2647
                                              nIters);
2648
                                pabyLocalData += nIters * nPixelSpace;
52,038✔
2649
                            }
2650
                            else
2651
                            {
2652
                                if (bNoTypeChange &&
170,056✔
2653
                                    nPixelSpace == nBandsPerBlockDTSize)
140,233✔
2654
                                {
2655
                                    REACHED(17);
2656
                                    if (!oFetcher.FetchBytes(
47,663✔
2657
                                            pabyLocalData,
2658
                                            nCurOffset + nByteOffsetIm_nBlock,
47,663✔
2659
                                            (nIters - 1) * nBandsPerBlock + 1,
47,663✔
2660
                                            nDTSize, bIsByteSwapped, bIsComplex,
2661
                                            nBlockId))
2662
                                    {
2663
                                        return CE_Failure;
2✔
2664
                                    }
2665
                                    pabyLocalData += nIters * nPixelSpace;
47,661✔
2666
                                }
2667
                                else
2668
                                {
2669
                                    const GByte *pabyLocalSrcData =
244,786✔
2670
                                        oFetcher.FetchBytes(
2671
                                            nCurOffset + nByteOffsetIm_nBlock,
122,393✔
2672
                                            (nIters - 1) * nBandsPerBlock + 1,
122,393✔
2673
                                            nDTSize, bIsByteSwapped, bIsComplex,
2674
                                            nBlockId);
2675
                                    if (pabyLocalSrcData == nullptr)
122,393✔
2676
                                        return CE_Failure;
8✔
2677

2678
                                    REACHED(18);
2679
                                    GDALCopyWords(pabyLocalSrcData, eDataType,
122,385✔
2680
                                                  nBandsPerBlockDTSize,
2681
                                                  pabyLocalData, eBufType,
2682
                                                  static_cast<int>(nPixelSpace),
2683
                                                  nIters);
2684
                                    pabyLocalData += nIters * nPixelSpace;
122,385✔
2685
                                }
2686
                            }
2687

2688
                            nXOffsetInBlock = 0;
222,084✔
2689
                            ++nBlockXOff;
222,084✔
2690
                            ++nBlockId;
222,084✔
2691
                            x += nUsedBlockWidth;
222,084✔
2692
                        }
2693
                    }
2694
                    else
2695
                    {
2696
                        // Non-contig reading, tiled, potential resampling and
2697
                        // data type change.
2698

2699
                        const GByte *pabyLocalSrcDataStartLine = nullptr;
215,282✔
2700
                        GByte *pabyLocalData = pabyData + y * nLineSpace;
215,282✔
2701
                        double dfSrcX = nXOff + 0.5 * dfSrcXInc;
215,282✔
2702
                        int nCurBlockXOff = 0;
215,282✔
2703
                        int nNextBlockXOff = 0;
215,282✔
2704
                        toff_t nCurOffset = 0;
215,282✔
2705
                        for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
16,850,700✔
2706
                        {
2707
                            const int nSrcPixel = static_cast<int>(dfSrcX);
16,635,400✔
2708
                            if (nSrcPixel >= nNextBlockXOff)
16,635,400✔
2709
                            {
2710
                                const int nBlockXOff =
645,782✔
2711
                                    nSrcPixel / m_nBlockXSize;
645,782✔
2712
                                nCurBlockXOff = nBlockXOff * m_nBlockXSize;
645,782✔
2713
                                nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
645,782✔
2714
                                const int nBlockId = poCurBand->ComputeBlockId(
645,782✔
2715
                                    nBlockXOff, m_nBlockYOff);
2716
                                nCurOffset = panOffsets[nBlockId];
645,782✔
2717
                                if (nCurOffset != 0)
645,782✔
2718
                                {
2719
                                    pabyLocalSrcDataStartLine =
993,396✔
2720
                                        oFetcher.FetchBytes(
2721
                                            nCurOffset +
496,698✔
2722
                                                nBaseByteOffsetIm_nBlock,
496,698✔
2723
                                            m_nBlockXSize * nBandsPerBlock,
496,698✔
2724
                                            nDTSize, bIsByteSwapped, bIsComplex,
2725
                                            nBlockId);
2726
                                    if (pabyLocalSrcDataStartLine == nullptr)
496,698✔
2727
                                        return CE_Failure;
2✔
2728
                                }
2729
                            }
2730
                            const int nXOffsetInBlock =
16,635,400✔
2731
                                nSrcPixel - nCurBlockXOff;
2732

2733
                            if (nCurOffset == 0)
16,635,400✔
2734
                            {
2735
                                REACHED(21);
2736
                                GDALCopyWords(&dfNoData, GDT_Float64, 0,
3,920,100✔
2737
                                              pabyLocalData, eBufType, 0, 1);
2738
                                pabyLocalData += nPixelSpace;
3,920,100✔
2739
                            }
2740
                            else
2741
                            {
2742
                                const GByte *pabyLocalSrcData =
12,715,300✔
2743
                                    pabyLocalSrcDataStartLine +
2744
                                    nXOffsetInBlock * nBandsPerBlockDTSize;
12,715,300✔
2745

2746
                                REACHED(22);
2747
                                if (bByteOnly)
12,715,300✔
2748
                                {
2749
                                    *pabyLocalData = *pabyLocalSrcData;
5,192,440✔
2750
                                }
2751
                                else
2752
                                {
2753
                                    GDALCopyWords(pabyLocalSrcData, eDataType,
7,522,880✔
2754
                                                  0, pabyLocalData, eBufType, 0,
2755
                                                  1);
2756
                                }
2757
                                pabyLocalData += nPixelSpace;
12,715,300✔
2758
                            }
2759
                        }
2760
                    }
2761
                }
2762
            }
2763
        }
2764
        else  // Non-contig reading, striped.
2765
        {
2766
            for (int iBand = 0; iBand < nBandCount; ++iBand)
1,588✔
2767
            {
2768
                const int nBand = panBandMap[iBand];
1,156✔
2769
                GByte *pabyData =
1,156✔
2770
                    static_cast<GByte *>(pData) + iBand * nBandSpace;
1,156✔
2771
                for (int y = 0; y < nBufYSize; ++y)
344,004✔
2772
                {
2773
                    const int nSrcLine =
342,863✔
2774
                        nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
342,863✔
2775
                    const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
342,863✔
2776
                    const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
342,863✔
2777
                    int nBlockId = m_nBlockYOff;
342,863✔
2778
                    if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
342,863✔
2779
                    {
2780
                        REACHED(23);
2781
                        nBlockId += m_nBlocksPerBand * (nBand - 1);
183,010✔
2782
                    }
2783
                    else
2784
                    {
2785
                        REACHED(24);
2786
                    }
2787
                    const toff_t nCurOffset = panOffsets[nBlockId];
342,863✔
2788
                    if (nCurOffset == 0)
342,863✔
2789
                    {
2790
                        REACHED(25);
2791
                        GDALCopyWords(&dfNoData, GDT_Float64, 0,
62,846✔
2792
                                      pabyData + y * nLineSpace, eBufType,
62,846✔
2793
                                      static_cast<int>(nPixelSpace), nBufXSize);
2794
                    }
2795
                    else
2796
                    {
2797
                        int nBaseByteOffsetIm_nBlock =
280,017✔
2798
                            (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
280,017✔
2799
                            nBandsPerBlockDTSize;
2800
                        if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
280,017✔
2801
                            nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
130,428✔
2802

2803
                        GByte *pabyLocalData = pabyData + y * nLineSpace;
280,017✔
2804
                        if (bNoXResamplingNoTypeChange &&
280,017✔
2805
                            nPixelSpace == nBandsPerBlockDTSize)
46,371✔
2806
                        {
2807
                            REACHED(26);
2808
                            if (!oFetcher.FetchBytes(
17,151✔
2809
                                    pabyLocalData,
2810
                                    nCurOffset + nBaseByteOffsetIm_nBlock,
17,151✔
2811
                                    (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
17,151✔
2812
                                    bIsByteSwapped, bIsComplex, nBlockId))
2813
                            {
2814
                                return CE_Failure;
3✔
2815
                            }
2816
                        }
2817
                        else
2818
                        {
2819
                            const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
525,732✔
2820
                                nCurOffset + nBaseByteOffsetIm_nBlock,
262,866✔
2821
                                (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
262,866✔
2822
                                bIsByteSwapped, bIsComplex, nBlockId);
2823
                            if (pabyLocalSrcData == nullptr)
262,866✔
2824
                                return CE_Failure;
12✔
2825

2826
                            if (bNoXResamplingNoTypeChange)
262,854✔
2827
                            {
2828
                                REACHED(27);
2829
                                GDALCopyWords(pabyLocalSrcData, eDataType,
29,211✔
2830
                                              nBandsPerBlockDTSize,
2831
                                              pabyLocalData, eBufType,
2832
                                              static_cast<int>(nPixelSpace),
2833
                                              nBufXSize);
2834
                            }
2835
                            else if (bByteOnly)
233,643✔
2836
                            {
2837
                                REACHED(28);
2838
                                double dfSrcX = 0.5 * dfSrcXInc;
73,619✔
2839
                                for (int x = 0; x < nBufXSize;
5,778,430✔
2840
                                     ++x, dfSrcX += dfSrcXInc)
2841
                                {
2842
                                    const int nSrcPixelMinusXOff =
5,704,810✔
2843
                                        static_cast<int>(dfSrcX);
2844
                                    pabyLocalData[x * nPixelSpace] =
5,704,810✔
2845
                                        pabyLocalSrcData[nSrcPixelMinusXOff *
5,704,810✔
2846
                                                         nBandsPerBlockDTSize];
2847
                                }
2848
                            }
2849
                            else
2850
                            {
2851
                                REACHED(29);
2852
                                double dfSrcX = 0.5 * dfSrcXInc;
160,024✔
2853
                                for (int x = 0; x < nBufXSize;
12,618,200✔
2854
                                     ++x, dfSrcX += dfSrcXInc)
2855
                                {
2856
                                    const int nSrcPixelMinusXOff =
12,458,200✔
2857
                                        static_cast<int>(dfSrcX);
2858
                                    GDALCopyWords(pabyLocalSrcData +
12,458,200✔
2859
                                                      nSrcPixelMinusXOff *
12,458,200✔
2860
                                                          nBandsPerBlockDTSize,
2861
                                                  eDataType, 0,
2862
                                                  pabyLocalData +
12,458,200✔
2863
                                                      x * nPixelSpace,
12,458,200✔
2864
                                                  eBufType, 0, 1);
2865
                                }
2866
                            }
2867
                        }
2868
                    }
2869
                }
2870
            }
2871
        }
2872
    }
2873

2874
    return CE_None;
1,527✔
2875
}
2876

2877
/************************************************************************/
2878
/*                           DirectIO()                                 */
2879
/************************************************************************/
2880

2881
CPLErr GTiffDataset::CommonDirectIOClassic(
613✔
2882
    FetchBufferDirectIO &oFetcher, int nXOff, int nYOff, int nXSize, int nYSize,
2883
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2884
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
2885
    GSpacing nLineSpace, GSpacing nBandSpace)
2886
{
2887
    return CommonDirectIO<FetchBufferDirectIO>(
613✔
2888
        oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
2889
        eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace);
613✔
2890
}
2891

2892
/************************************************************************/
2893
/*                           DirectIO()                                 */
2894
/************************************************************************/
2895

2896
// Reads directly bytes from the file using ReadMultiRange(), and by-pass
2897
// block reading. Restricted to simple TIFF configurations
2898
// (uncompressed data, standard data types). Particularly useful to extract
2899
// sub-windows of data on a large /vsicurl dataset).
2900
// Returns -1 if DirectIO() can't be supported on that file.
2901

2902
int GTiffDataset::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
471✔
2903
                           int nYSize, void *pData, int nBufXSize,
2904
                           int nBufYSize, GDALDataType eBufType, int nBandCount,
2905
                           const int *panBandMap, GSpacing nPixelSpace,
2906
                           GSpacing nLineSpace, GSpacing nBandSpace,
2907
                           GDALRasterIOExtraArg *psExtraArg)
2908
{
2909
    auto poProtoBand = cpl::down_cast<GTiffRasterBand *>(papoBands[0]);
471✔
2910
    const GDALDataType eDataType = poProtoBand->GetRasterDataType();
471✔
2911
    const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
471✔
2912
    if (!(eRWFlag == GF_Read && m_nCompression == COMPRESSION_NONE &&
942✔
2913
          (m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
471✔
2914
           m_nPhotometric == PHOTOMETRIC_RGB ||
188✔
2915
           m_nPhotometric == PHOTOMETRIC_PALETTE) &&
×
2916
          poProtoBand->IsBaseGTiffClass()))
471✔
2917
    {
2918
        return -1;
×
2919
    }
2920
    Crystalize();
471✔
2921

2922
    // Only know how to deal with nearest neighbour in this optimized routine.
2923
    if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
471✔
2924
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
181✔
2925
    {
2926
        return -1;
30✔
2927
    }
2928

2929
    // If the file is band interleave or only one band is requested, then
2930
    // fallback to band DirectIO.
2931
    bool bUseBandRasterIO = false;
441✔
2932
    if (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1)
441✔
2933
    {
2934
        bUseBandRasterIO = true;
207✔
2935
    }
2936
    else
2937
    {
2938
        // For simplicity, only deals with "naturally ordered" bands.
2939
        for (int iBand = 0; iBand < nBandCount; ++iBand)
1,086✔
2940
        {
2941
            if (panBandMap[iBand] != iBand + 1)
868✔
2942
            {
2943
                bUseBandRasterIO = true;
16✔
2944
                break;
16✔
2945
            }
2946
        }
2947
    }
2948
    if (bUseBandRasterIO)
441✔
2949
    {
2950
        CPLErr eErr = CE_None;
223✔
2951
        for (int iBand = 0; eErr == CE_None && iBand < nBandCount; ++iBand)
1,094✔
2952
        {
2953
            eErr =
2954
                GetRasterBand(panBandMap[iBand])
871✔
2955
                    ->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1,742✔
2956
                               static_cast<GByte *>(pData) + iBand * nBandSpace,
871✔
2957
                               nBufXSize, nBufYSize, eBufType, nPixelSpace,
2958
                               nLineSpace, psExtraArg);
2959
        }
2960
        return eErr;
223✔
2961
    }
2962

2963
#if DEBUG_VERBOSE
2964
    CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
2965
             nYSize, nBufXSize, nBufYSize);
2966
#endif
2967

2968
    // No need to look if overviews can satisfy the request as it has already */
2969
    // been done in GTiffDataset::IRasterIO().
2970

2971
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
2972
    if (eAccess == GA_Update)
218✔
2973
    {
2974
        FlushCache(false);
×
2975
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
×
2976
    }
2977

2978
    if (TIFFIsTiled(m_hTIFF))
218✔
2979
    {
2980
        const int nDTSize = nDTSizeBits / 8;
109✔
2981
        const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
109✔
2982
            static_cast<GPtrDiff_t>(m_nBlockXSize) * m_nBlockYSize * nDTSize *
218✔
2983
            ((m_nPlanarConfig == PLANARCONFIG_CONTIG) ? nBands : 1));
109✔
2984
        if (m_pTempBufferForCommonDirectIO == nullptr)
109✔
2985
        {
2986
            m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
×
2987
                VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
×
2988
            if (m_pTempBufferForCommonDirectIO == nullptr)
×
2989
                return CE_Failure;
×
2990
        }
2991

2992
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
109✔
2993
        FetchBufferDirectIO oFetcher(fp, m_pTempBufferForCommonDirectIO,
2994
                                     nTempBufferForCommonDirectIOSize);
109✔
2995

2996
        return CommonDirectIOClassic(oFetcher, nXOff, nYOff, nXSize, nYSize,
109✔
2997
                                     pData, nBufXSize, nBufYSize, eBufType,
2998
                                     nBandCount, panBandMap, nPixelSpace,
2999
                                     nLineSpace, nBandSpace);
109✔
3000
    }
3001

3002
    // Get strip offsets.
3003
    toff_t *panTIFFOffsets = nullptr;
109✔
3004
    if (!TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets) ||
218✔
3005
        panTIFFOffsets == nullptr)
109✔
3006
    {
3007
        return CE_Failure;
×
3008
    }
3009

3010
    // Sub-sampling or over-sampling can only be done at last stage.
3011
    int nReqXSize = nXSize;
109✔
3012
    // Can do sub-sampling at the extraction stage.
3013
    const int nReqYSize = std::min(nBufYSize, nYSize);
109✔
3014
    void **ppData =
3015
        static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
109✔
3016
    vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
3017
        VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
109✔
3018
    size_t *panSizes =
3019
        static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
109✔
3020
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
109✔
3021
    void *pTmpBuffer = nullptr;
109✔
3022
    int eErr = CE_None;
109✔
3023
    int nContigBands = nBands;
109✔
3024
    const int nSrcPixelSize = nDTSize * nContigBands;
109✔
3025

3026
    if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
109✔
3027
    {
3028
        eErr = CE_Failure;
×
3029
    }
3030
    // For now we always allocate a temp buffer as it is easier.
3031
    else
3032
    // if( nXSize != nBufXSize || nYSize != nBufYSize ||
3033
    //   eBufType != eDataType ||
3034
    //   nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
3035
    //   check if the user buffer is large enough )
3036
    {
3037
        // We need a temporary buffer for over-sampling/sub-sampling
3038
        // and/or data type conversion.
3039
        pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
109✔
3040
        if (pTmpBuffer == nullptr)
109✔
3041
            eErr = CE_Failure;
×
3042
    }
3043

3044
    // Prepare data extraction.
3045
    const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
109✔
3046

3047
    for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
6,654✔
3048
    {
3049
        ppData[iLine] = static_cast<GByte *>(pTmpBuffer) +
6,545✔
3050
                        static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
6,545✔
3051
        int nSrcLine = 0;
6,545✔
3052
        if (nBufYSize < nYSize)  // Sub-sampling in y.
6,545✔
3053
            nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
484✔
3054
        else
3055
            nSrcLine = nYOff + iLine;
6,061✔
3056

3057
        const int nBlockXOff = 0;
6,545✔
3058
        const int nBlockYOff = nSrcLine / m_nBlockYSize;
6,545✔
3059
        const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
6,545✔
3060
        const int nBlockId =
3061
            poProtoBand->ComputeBlockId(nBlockXOff, nBlockYOff);
6,545✔
3062

3063
        panOffsets[iLine] = panTIFFOffsets[nBlockId];
6,545✔
3064
        if (panOffsets[iLine] == 0)  // We don't support sparse files.
6,545✔
3065
            eErr = -1;
27✔
3066

3067
        panOffsets[iLine] +=
6,545✔
3068
            (nXOff +
6,545✔
3069
             static_cast<vsi_l_offset>(nYOffsetInBlock) * m_nBlockXSize) *
6,545✔
3070
            nSrcPixelSize;
6,545✔
3071
        panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
6,545✔
3072
    }
3073

3074
    // Extract data from the file.
3075
    if (eErr == CE_None)
109✔
3076
    {
3077
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
82✔
3078
        const int nRet =
3079
            VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
82✔
3080
        if (nRet != 0)
82✔
3081
            eErr = CE_Failure;
9✔
3082
    }
3083

3084
    // Byte-swap if necessary.
3085
    if (eErr == CE_None && TIFFIsByteSwapped(m_hTIFF))
109✔
3086
    {
3087
        for (int iLine = 0; iLine < nReqYSize; ++iLine)
3,734✔
3088
        {
3089
            if (GDALDataTypeIsComplex(eDataType))
3,686✔
3090
                GDALSwapWords(ppData[iLine], nDTSize / 2,
1,757✔
3091
                              2 * nReqXSize * nContigBands, nDTSize / 2);
1,757✔
3092
            else
3093
                GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
1,929✔
3094
                              nDTSize);
3095
        }
3096
    }
3097

3098
    // Over-sampling/sub-sampling and/or data type conversion.
3099
    const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
109✔
3100
    if (eErr == CE_None && pTmpBuffer != nullptr)
109✔
3101
    {
3102
        for (int iY = 0; iY < nBufYSize; ++iY)
22,212✔
3103
        {
3104
            const int iSrcY = nBufYSize <= nYSize
44,278✔
3105
                                  ? iY
22,139✔
3106
                                  : static_cast<int>((iY + 0.5) * dfSrcYInc);
17,496✔
3107
            // Optimization: no resampling, no data type change, number of
3108
            // bands requested == number of bands and buffer is packed
3109
            // pixel-interleaved.
3110
            if (nBufXSize == nXSize && nContigBands == nBandCount &&
22,139✔
3111
                eDataType == eBufType && nBandSpace == nDTSize &&
2,358✔
3112
                nPixelSpace == nBandCount * nBandSpace)
1,422✔
3113
            {
3114
                memcpy(static_cast<GByte *>(pData) + iY * nLineSpace,
936✔
3115
                       ppData[iSrcY],
936✔
3116
                       static_cast<size_t>(nReqXSize * nPixelSpace));
936✔
3117
            }
3118
            // Other optimization: no resampling, no data type change,
3119
            // data type is Byte/Int8.
3120
            else if (nBufXSize == nXSize && eDataType == eBufType &&
21,203✔
3121
                     (eDataType == GDT_Byte || eDataType == GDT_Int8))
1,272✔
3122
            {
3123
                GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]);
808✔
3124
                GByte *pabyDstData =
808✔
3125
                    static_cast<GByte *>(pData) + iY * nLineSpace;
808✔
3126
                if (nBandSpace == 1 && nPixelSpace > nBandCount)
808✔
3127
                {
3128
                    // Buffer is pixel-interleaved (with some stridding
3129
                    // between pixels).
3130
                    CopyContigByteMultiBand(
324✔
3131
                        pabySrcData, nSrcPixelSize, pabyDstData,
3132
                        static_cast<int>(nPixelSpace), nBufXSize, nBandCount);
3133
                }
3134
                else
3135
                {
3136
                    for (int iBand = 0; iBand < nBandCount; ++iBand)
2,248✔
3137
                    {
3138
                        GDALCopyWords(
1,764✔
3139
                            pabySrcData + iBand, GDT_Byte, nSrcPixelSize,
1,764✔
3140
                            pabyDstData + iBand * nBandSpace, GDT_Byte,
1,764✔
3141
                            static_cast<int>(nPixelSpace), nBufXSize);
3142
                    }
3143
                }
808✔
3144
            }
3145
            else  // General case.
3146
            {
3147
                for (int iBand = 0; iBand < nBandCount; ++iBand)
101,651✔
3148
                {
3149
                    GByte *pabySrcData =
81,256✔
3150
                        static_cast<GByte *>(ppData[iSrcY]) + iBand * nDTSize;
81,256✔
3151
                    GByte *pabyDstData = static_cast<GByte *>(pData) +
81,256✔
3152
                                         iBand * nBandSpace + iY * nLineSpace;
81,256✔
3153
                    if ((eDataType == GDT_Byte && eBufType == GDT_Byte) ||
81,256✔
3154
                        (eDataType == GDT_Int8 && eBufType == GDT_Int8))
×
3155
                    {
3156
                        double dfSrcX = 0.5 * dfSrcXInc;
23,972✔
3157
                        for (int iX = 0; iX < nBufXSize;
1,718,820✔
3158
                             ++iX, dfSrcX += dfSrcXInc)
1,694,850✔
3159
                        {
3160
                            int iSrcX = static_cast<int>(dfSrcX);
1,694,850✔
3161
                            pabyDstData[iX * nPixelSpace] =
1,694,850✔
3162
                                pabySrcData[iSrcX * nSrcPixelSize];
1,694,850✔
3163
                        }
23,972✔
3164
                    }
3165
                    else
3166
                    {
3167
                        double dfSrcX = 0.5 * dfSrcXInc;
57,284✔
3168
                        for (int iX = 0; iX < nBufXSize;
4,304,170✔
3169
                             ++iX, dfSrcX += dfSrcXInc)
4,246,880✔
3170
                        {
3171
                            int iSrcX = static_cast<int>(dfSrcX);
4,246,880✔
3172
                            GDALCopyWords(pabySrcData + iSrcX * nSrcPixelSize,
4,246,880✔
3173
                                          eDataType, 0,
3174
                                          pabyDstData + iX * nPixelSpace,
4,246,880✔
3175
                                          eBufType, 0, 1);
3176
                        }
3177
                    }
3178
                }
3179
            }
3180
        }
3181
    }
3182

3183
    CPLFree(pTmpBuffer);
109✔
3184
    CPLFree(ppData);
109✔
3185
    CPLFree(panOffsets);
109✔
3186
    CPLFree(panSizes);
109✔
3187

3188
    return eErr;
109✔
3189
}
3190

3191
/************************************************************************/
3192
/*                             ReadStrile()                             */
3193
/************************************************************************/
3194

3195
bool GTiffDataset::ReadStrile(int nBlockId, void *pOutputBuffer,
2,118,140✔
3196
                              GPtrDiff_t nBlockReqSize)
3197
{
3198
    // Optimization by which we can save some libtiff buffer copy
3199
    std::pair<vsi_l_offset, vsi_l_offset> oPair;
2,118,140✔
3200
    if (
2,118,090✔
3201
#if TIFFLIB_VERSION <= 20220520 && !defined(INTERNAL_LIBTIFF)
3202
        // There's a bug, up to libtiff 4.4.0, in TIFFReadFromUserBuffer()
3203
        // which clears the TIFF_CODERSETUP flag of tif->tif_flags, which
3204
        // causes the codec SetupDecode method to be called for each strile,
3205
        // whereas it should normally be called only for the first decoded one.
3206
        // For JPEG, that causes TIFFjpeg_read_header() to be called. Most
3207
        // of the time, that works. But for some files, at some point, the
3208
        // libjpeg machinery is not in the appropriate state for that.
3209
        m_nCompression != COMPRESSION_JPEG &&
3210
#endif
3211
        m_oCacheStrileToOffsetByteCount.tryGet(nBlockId, oPair))
2,118,140✔
3212
    {
3213
        // For the mask, use the parent TIFF handle to get cached ranges
3214
        auto th = TIFFClientdata(m_poImageryDS && m_bMaskInterleavedWithImagery
336✔
3215
                                     ? m_poImageryDS->m_hTIFF
94✔
3216
                                     : m_hTIFF);
3217
        void *pInputBuffer = VSI_TIFFGetCachedRange(
484✔
3218
            th, oPair.first, static_cast<size_t>(oPair.second));
242✔
3219
        if (pInputBuffer &&
484✔
3220
            TIFFReadFromUserBuffer(m_hTIFF, nBlockId, pInputBuffer,
242✔
3221
                                   static_cast<size_t>(oPair.second),
242✔
3222
                                   pOutputBuffer, nBlockReqSize))
3223
        {
3224
            return true;
242✔
3225
        }
3226
    }
3227

3228
    // For debugging
3229
    if (m_poBaseDS)
2,117,850✔
3230
        m_poBaseDS->m_bHasUsedReadEncodedAPI = true;
3,432✔
3231
    else
3232
        m_bHasUsedReadEncodedAPI = true;
2,114,410✔
3233

3234
#if 0
3235
    // Can be useful to test TIFFReadFromUserBuffer() for local files
3236
    VSILFILE* fpTIF = VSI_TIFFGetVSILFile(TIFFClientdata( m_hTIFF ));
3237
    std::vector<GByte> tmp(TIFFGetStrileByteCount(m_hTIFF, nBlockId));
3238
    VSIFSeekL(fpTIF, TIFFGetStrileOffset(m_hTIFF, nBlockId), SEEK_SET);
3239
    VSIFReadL(&tmp[0], 1, TIFFGetStrileByteCount(m_hTIFF, nBlockId), fpTIF);
3240
    if( !TIFFReadFromUserBuffer( m_hTIFF, nBlockId,
3241
                                &tmp[0], tmp.size(),
3242
                                pOutputBuffer, nBlockReqSize ) )
3243
    {
3244
        return false;
3245
    }
3246
#else
3247
    // Set to 1 to allow GTiffErrorHandler to implement limitation on error
3248
    // messages
3249
    GTIFFGetThreadLocalLibtiffError() = 1;
2,117,850✔
3250
    if (TIFFIsTiled(m_hTIFF))
2,117,820✔
3251
    {
3252
        if (TIFFReadEncodedTile(m_hTIFF, nBlockId, pOutputBuffer,
27,496✔
3253
                                nBlockReqSize) == -1 &&
27,532✔
3254
            !m_bIgnoreReadErrors)
34✔
3255
        {
3256
            CPLError(CE_Failure, CPLE_AppDefined,
34✔
3257
                     "TIFFReadEncodedTile() failed.");
3258
            GTIFFGetThreadLocalLibtiffError() = 0;
34✔
3259
            return false;
34✔
3260
        }
3261
    }
3262
    else
3263
    {
3264
        if (TIFFReadEncodedStrip(m_hTIFF, nBlockId, pOutputBuffer,
2,090,210✔
3265
                                 nBlockReqSize) == -1 &&
2,090,410✔
3266
            !m_bIgnoreReadErrors)
71✔
3267
        {
3268
            CPLError(CE_Failure, CPLE_AppDefined,
70✔
3269
                     "TIFFReadEncodedStrip() failed.");
3270
            GTIFFGetThreadLocalLibtiffError() = 0;
70✔
3271
            return false;
70✔
3272
        }
3273
    }
3274
    GTIFFGetThreadLocalLibtiffError() = 0;
2,117,740✔
3275
#endif
3276
    return true;
2,117,720✔
3277
}
3278

3279
/************************************************************************/
3280
/*                            LoadBlockBuf()                            */
3281
/*                                                                      */
3282
/*      Load working block buffer with request block (tile/strip).      */
3283
/************************************************************************/
3284

3285
CPLErr GTiffDataset::LoadBlockBuf(int nBlockId, bool bReadFromDisk)
142,205✔
3286

3287
{
3288
    if (m_nLoadedBlock == nBlockId && m_pabyBlockBuf != nullptr)
142,205✔
3289
        return CE_None;
41,221✔
3290

3291
    /* -------------------------------------------------------------------- */
3292
    /*      If we have a dirty loaded block, flush it out first.            */
3293
    /* -------------------------------------------------------------------- */
3294
    if (m_nLoadedBlock != -1 && m_bLoadedBlockDirty)
100,984✔
3295
    {
3296
        const CPLErr eErr = FlushBlockBuf();
4,636✔
3297
        if (eErr != CE_None)
4,636✔
3298
            return eErr;
×
3299
    }
3300

3301
    /* -------------------------------------------------------------------- */
3302
    /*      Get block size.                                                 */
3303
    /* -------------------------------------------------------------------- */
3304
    const GPtrDiff_t nBlockBufSize = static_cast<GPtrDiff_t>(
100,956✔
3305
        TIFFIsTiled(m_hTIFF) ? TIFFTileSize(m_hTIFF) : TIFFStripSize(m_hTIFF));
100,984✔
3306
    if (!nBlockBufSize)
100,970✔
3307
    {
3308
        ReportError(CE_Failure, CPLE_AppDefined,
×
3309
                    "Bogus block size; unable to allocate a buffer.");
3310
        return CE_Failure;
×
3311
    }
3312

3313
    /* -------------------------------------------------------------------- */
3314
    /*      Allocate a temporary buffer for this strip.                     */
3315
    /* -------------------------------------------------------------------- */
3316
    if (m_pabyBlockBuf == nullptr)
100,970✔
3317
    {
3318
        m_pabyBlockBuf =
5,423✔
3319
            static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockBufSize));
5,421✔
3320
        if (m_pabyBlockBuf == nullptr)
5,423✔
3321
        {
3322
            return CE_Failure;
×
3323
        }
3324
    }
3325

3326
    if (m_nLoadedBlock == nBlockId)
100,972✔
3327
        return CE_None;
3,024✔
3328

3329
    /* -------------------------------------------------------------------- */
3330
    /*  When called from ::IWriteBlock in separate cases (or in single band */
3331
    /*  geotiffs), the ::IWriteBlock will override the content of the buffer*/
3332
    /*  with pImage, so we don't need to read data from disk                */
3333
    /* -------------------------------------------------------------------- */
3334
    if (!bReadFromDisk || m_bStreamingOut)
97,948✔
3335
    {
3336
        m_nLoadedBlock = nBlockId;
35,172✔
3337
        return CE_None;
35,172✔
3338
    }
3339

3340
    // libtiff 3.X doesn't like mixing read&write of JPEG compressed blocks
3341
    // The below hack is necessary due to another hack that consist in
3342
    // writing zero block to force creation of JPEG tables.
3343
    if (nBlockId == 0 && m_bDontReloadFirstBlock)
62,776✔
3344
    {
3345
        m_bDontReloadFirstBlock = false;
×
3346
        memset(m_pabyBlockBuf, 0, nBlockBufSize);
×
3347
        m_nLoadedBlock = nBlockId;
×
3348
        return CE_None;
×
3349
    }
3350

3351
    /* -------------------------------------------------------------------- */
3352
    /*      The bottom most partial tiles and strips are sometimes only     */
3353
    /*      partially encoded.  This code reduces the requested data so     */
3354
    /*      an error won't be reported in this case. (#1179)                */
3355
    /*      We exclude tiled WEBP, because as it is a new codec, whole tiles*/
3356
    /*      are written by libtiff. This helps avoiding creating a temporary*/
3357
    /*      decode buffer.                                                  */
3358
    /* -------------------------------------------------------------------- */
3359
    auto nBlockReqSize = nBlockBufSize;
62,776✔
3360
    const int nBlockYOff = (nBlockId % m_nBlocksPerBand) / m_nBlocksPerRow;
62,776✔
3361

3362
    if (nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize &&
64,482✔
3363
        !(m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF)))
1,706✔
3364
    {
3365
        nBlockReqSize =
1,703✔
3366
            (nBlockBufSize / m_nBlockYSize) *
1,703✔
3367
            (m_nBlockYSize -
1,703✔
3368
             static_cast<int>(
3369
                 (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
1,703✔
3370
                 nRasterYSize));
1,703✔
3371
        memset(m_pabyBlockBuf, 0, nBlockBufSize);
1,703✔
3372
    }
3373

3374
    /* -------------------------------------------------------------------- */
3375
    /*      If we don't have this block already loaded, and we know it      */
3376
    /*      doesn't yet exist on disk, just zero the memory buffer and      */
3377
    /*      pretend we loaded it.                                           */
3378
    /* -------------------------------------------------------------------- */
3379
    bool bErrOccurred = false;
62,776✔
3380
    if (!IsBlockAvailable(nBlockId, nullptr, nullptr, &bErrOccurred))
62,776✔
3381
    {
3382
        memset(m_pabyBlockBuf, 0, nBlockBufSize);
791✔
3383
        m_nLoadedBlock = nBlockId;
791✔
3384
        if (bErrOccurred)
791✔
3385
            return CE_Failure;
×
3386
        return CE_None;
791✔
3387
    }
3388

3389
    /* -------------------------------------------------------------------- */
3390
    /*      Load the block, if it isn't our current block.                  */
3391
    /* -------------------------------------------------------------------- */
3392
    CPLErr eErr = CE_None;
61,988✔
3393

3394
    if (!ReadStrile(nBlockId, m_pabyBlockBuf, nBlockReqSize))
61,988✔
3395
    {
3396
        memset(m_pabyBlockBuf, 0, nBlockBufSize);
42✔
3397
        eErr = CE_Failure;
42✔
3398
    }
3399

3400
    if (eErr == CE_None)
61,981✔
3401
    {
3402
        if (m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF) &&
62,589✔
3403
            nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize)
652✔
3404
        {
3405
            const auto nValidBytes =
3✔
3406
                (nBlockBufSize / m_nBlockYSize) *
3✔
3407
                (m_nBlockYSize -
3✔
3408
                 static_cast<int>(
3409
                     (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
3✔
3410
                     nRasterYSize));
3✔
3411
            // Zero-out unused area
3412
            memset(m_pabyBlockBuf + nValidBytes, 0,
3✔
3413
                   nBlockBufSize - nValidBytes);
3✔
3414
        }
3415

3416
        m_nLoadedBlock = nBlockId;
61,937✔
3417
    }
3418
    else
3419
    {
3420
        m_nLoadedBlock = -1;
44✔
3421
    }
3422
    m_bLoadedBlockDirty = false;
61,981✔
3423

3424
    return eErr;
61,981✔
3425
}
3426

3427
/************************************************************************/
3428
/*                              Identify()                              */
3429
/************************************************************************/
3430

3431
int GTiffDataset::Identify(GDALOpenInfo *poOpenInfo)
98,311✔
3432

3433
{
3434
    const char *pszFilename = poOpenInfo->pszFilename;
98,311✔
3435
    if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
98,311✔
3436
    {
3437
        pszFilename += strlen("GTIFF_RAW:");
20✔
3438
        GDALOpenInfo oOpenInfo(pszFilename, poOpenInfo->eAccess);
40✔
3439
        return Identify(&oOpenInfo);
20✔
3440
    }
3441

3442
    /* -------------------------------------------------------------------- */
3443
    /*      We have a special hook for handling opening a specific          */
3444
    /*      directory of a TIFF file.                                       */
3445
    /* -------------------------------------------------------------------- */
3446
    if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
98,291✔
3447
        return TRUE;
50✔
3448

3449
    /* -------------------------------------------------------------------- */
3450
    /*      First we check to see if the file has the expected header       */
3451
    /*      bytes.                                                          */
3452
    /* -------------------------------------------------------------------- */
3453
    if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 2)
98,241✔
3454
        return FALSE;
49,413✔
3455

3456
    if ((poOpenInfo->pabyHeader[0] != 'I' ||
48,828✔
3457
         poOpenInfo->pabyHeader[1] != 'I') &&
40,097✔
3458
        (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
8,749✔
3459
        return FALSE;
8,593✔
3460

3461
    if ((poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0) &&
40,235✔
3462
        (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0) &&
446✔
3463
        (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0) &&
200✔
3464
        (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
×
3465
        return FALSE;
×
3466

3467
    return TRUE;
40,235✔
3468
}
3469

3470
/************************************************************************/
3471
/*                          GTIFFExtendMemoryFile()                     */
3472
/************************************************************************/
3473

3474
static bool GTIFFExtendMemoryFile(const CPLString &osTmpFilename,
14✔
3475
                                  VSILFILE *fpTemp, VSILFILE *fpL,
3476
                                  int nNewLength, GByte *&pabyBuffer,
3477
                                  vsi_l_offset &nDataLength)
3478
{
3479
    if (nNewLength <= static_cast<int>(nDataLength))
14✔
3480
        return true;
10✔
3481
    if (VSIFSeekL(fpTemp, nNewLength - 1, SEEK_SET) != 0)
4✔
3482
        return false;
×
3483
    char ch = 0;
4✔
3484
    if (VSIFWriteL(&ch, 1, 1, fpTemp) != 1)
4✔
3485
        return false;
×
3486
    const int nOldDataLength = static_cast<int>(nDataLength);
4✔
3487
    pabyBuffer = static_cast<GByte *>(
4✔
3488
        VSIGetMemFileBuffer(osTmpFilename, &nDataLength, FALSE));
4✔
3489
    const int nToRead = nNewLength - nOldDataLength;
4✔
3490
    const int nRead = static_cast<int>(
3491
        VSIFReadL(pabyBuffer + nOldDataLength, 1, nToRead, fpL));
4✔
3492
    if (nRead != nToRead)
4✔
3493
    {
3494
        CPLError(CE_Failure, CPLE_FileIO,
×
3495
                 "Needed to read %d bytes. Only %d got", nToRead, nRead);
3496
        return false;
×
3497
    }
3498
    return true;
4✔
3499
}
3500

3501
/************************************************************************/
3502
/*                         GTIFFMakeBufferedStream()                    */
3503
/************************************************************************/
3504

3505
static bool GTIFFMakeBufferedStream(GDALOpenInfo *poOpenInfo)
9✔
3506
{
3507
    const CPLString osTmpFilename(
3508
        VSIMemGenerateHiddenFilename("GTIFFMakeBufferedStream.tif"));
18✔
3509
    VSILFILE *fpTemp = VSIFOpenL(osTmpFilename, "wb+");
9✔
3510
    if (fpTemp == nullptr)
9✔
3511
        return false;
×
3512
    // The seek is needed for /vsistdin/ that has some rewind capabilities.
3513
    if (VSIFSeekL(poOpenInfo->fpL, poOpenInfo->nHeaderBytes, SEEK_SET) != 0)
9✔
3514
    {
3515
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3516
        return false;
×
3517
    }
3518
    CPLAssert(static_cast<int>(VSIFTellL(poOpenInfo->fpL)) ==
9✔
3519
              poOpenInfo->nHeaderBytes);
3520
    if (VSIFWriteL(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes, 1,
9✔
3521
                   fpTemp) != 1)
9✔
3522
    {
3523
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3524
        return false;
×
3525
    }
3526
    vsi_l_offset nDataLength = 0;
9✔
3527
    GByte *pabyBuffer = static_cast<GByte *>(
3528
        VSIGetMemFileBuffer(osTmpFilename, &nDataLength, FALSE));
9✔
3529
    const bool bLittleEndian = (pabyBuffer[0] == 'I');
9✔
3530
#if CPL_IS_LSB
3531
    const bool bSwap = !bLittleEndian;
9✔
3532
#else
3533
    const bool bSwap = bLittleEndian;
3534
#endif
3535
    const bool bBigTIFF = pabyBuffer[2] == 43 || pabyBuffer[3] == 43;
9✔
3536
    vsi_l_offset nMaxOffset = 0;
9✔
3537
    if (bBigTIFF)
9✔
3538
    {
3539
        GUInt64 nTmp = 0;
2✔
3540
        memcpy(&nTmp, pabyBuffer + 8, 8);
2✔
3541
        if (bSwap)
2✔
3542
            CPL_SWAP64PTR(&nTmp);
×
3543
        if (nTmp != 16)
2✔
3544
        {
3545
            CPLError(CE_Failure, CPLE_NotSupported,
1✔
3546
                     "IFD start should be at offset 16 for a streamed BigTIFF");
3547
            CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
1✔
3548
            VSIUnlink(osTmpFilename);
1✔
3549
            return false;
1✔
3550
        }
3551
        memcpy(&nTmp, pabyBuffer + 16, 8);
1✔
3552
        if (bSwap)
1✔
3553
            CPL_SWAP64PTR(&nTmp);
×
3554
        if (nTmp > 1024)
1✔
3555
        {
3556
            CPLError(CE_Failure, CPLE_NotSupported,
×
3557
                     "Too many tags : " CPL_FRMT_GIB, nTmp);
3558
            CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3559
            VSIUnlink(osTmpFilename);
×
3560
            return false;
×
3561
        }
3562
        const int nTags = static_cast<int>(nTmp);
1✔
3563
        const int nSpaceForTags = nTags * 20;
1✔
3564
        if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
1✔
3565
                                   24 + nSpaceForTags, pabyBuffer, nDataLength))
3566
        {
3567
            CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3568
            VSIUnlink(osTmpFilename);
×
3569
            return false;
×
3570
        }
3571
        nMaxOffset = 24 + nSpaceForTags + 8;
1✔
3572
        for (int i = 0; i < nTags; ++i)
18✔
3573
        {
3574
            GUInt16 nTmp16 = 0;
17✔
3575
            memcpy(&nTmp16, pabyBuffer + 24 + i * 20, 2);
17✔
3576
            if (bSwap)
17✔
3577
                CPL_SWAP16PTR(&nTmp16);
×
3578
            const int nTag = nTmp16;
17✔
3579
            memcpy(&nTmp16, pabyBuffer + 24 + i * 20 + 2, 2);
17✔
3580
            if (bSwap)
17✔
3581
                CPL_SWAP16PTR(&nTmp16);
×
3582
            const int nDataType = nTmp16;
17✔
3583
            memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 4, 8);
17✔
3584
            if (bSwap)
17✔
3585
                CPL_SWAP64PTR(&nTmp);
×
3586
            if (nTmp >= 16 * 1024 * 1024)
17✔
3587
            {
3588
                CPLError(CE_Failure, CPLE_NotSupported,
×
3589
                         "Too many elements for tag %d : " CPL_FRMT_GUIB, nTag,
3590
                         nTmp);
3591
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3592
                VSIUnlink(osTmpFilename);
×
3593
                return false;
×
3594
            }
3595
            const GUInt32 nCount = static_cast<GUInt32>(nTmp);
17✔
3596
            const GUInt32 nTagSize =
3597
                TIFFDataWidth(static_cast<TIFFDataType>(nDataType)) * nCount;
17✔
3598
            if (nTagSize > 8)
17✔
3599
            {
3600
                memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 12, 8);
7✔
3601
                if (bSwap)
7✔
3602
                    CPL_SWAP64PTR(&nTmp);
×
3603
                if (nTmp > GUINT64_MAX - nTagSize)
7✔
3604
                {
3605
                    CPLError(CE_Failure, CPLE_NotSupported,
×
3606
                             "Overflow with tag %d", nTag);
3607
                    CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3608
                    VSIUnlink(osTmpFilename);
×
3609
                    return false;
×
3610
                }
3611
                if (static_cast<vsi_l_offset>(nTmp + nTagSize) > nMaxOffset)
7✔
3612
                    nMaxOffset = nTmp + nTagSize;
6✔
3613
            }
3614
        }
3615
    }
3616
    else
3617
    {
3618
        GUInt32 nTmp = 0;
7✔
3619
        memcpy(&nTmp, pabyBuffer + 4, 4);
7✔
3620
        if (bSwap)
7✔
3621
            CPL_SWAP32PTR(&nTmp);
×
3622
        if (nTmp != 8)
7✔
3623
        {
3624
            CPLError(CE_Failure, CPLE_NotSupported,
1✔
3625
                     "IFD start should be at offset 8 for a streamed TIFF");
3626
            CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
1✔
3627
            VSIUnlink(osTmpFilename);
1✔
3628
            return false;
1✔
3629
        }
3630
        GUInt16 nTmp16 = 0;
6✔
3631
        memcpy(&nTmp16, pabyBuffer + 8, 2);
6✔
3632
        if (bSwap)
6✔
3633
            CPL_SWAP16PTR(&nTmp16);
×
3634
        if (nTmp16 > 1024)
6✔
3635
        {
3636
            CPLError(CE_Failure, CPLE_NotSupported, "Too many tags : %d",
×
3637
                     nTmp16);
3638
            CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3639
            VSIUnlink(osTmpFilename);
×
3640
            return false;
×
3641
        }
3642
        const int nTags = nTmp16;
6✔
3643
        const int nSpaceForTags = nTags * 12;
6✔
3644
        if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
6✔
3645
                                   10 + nSpaceForTags, pabyBuffer, nDataLength))
3646
        {
3647
            CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3648
            VSIUnlink(osTmpFilename);
×
3649
            return false;
×
3650
        }
3651
        nMaxOffset = 10 + nSpaceForTags + 4;
6✔
3652
        for (int i = 0; i < nTags; ++i)
95✔
3653
        {
3654
            memcpy(&nTmp16, pabyBuffer + 10 + i * 12, 2);
89✔
3655
            if (bSwap)
89✔
3656
                CPL_SWAP16PTR(&nTmp16);
×
3657
            const int nTag = nTmp16;
89✔
3658
            memcpy(&nTmp16, pabyBuffer + 10 + i * 12 + 2, 2);
89✔
3659
            if (bSwap)
89✔
3660
                CPL_SWAP16PTR(&nTmp16);
×
3661
            const int nDataType = nTmp16;
89✔
3662
            memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 4, 4);
89✔
3663
            if (bSwap)
89✔
3664
                CPL_SWAP32PTR(&nTmp);
×
3665
            if (nTmp >= 16 * 1024 * 1024)
89✔
3666
            {
3667
                CPLError(CE_Failure, CPLE_NotSupported,
×
3668
                         "Too many elements for tag %d : %u", nTag, nTmp);
3669
                CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3670
                VSIUnlink(osTmpFilename);
×
3671
                return false;
×
3672
            }
3673
            const GUInt32 nCount = nTmp;
89✔
3674
            const GUInt32 nTagSize =
3675
                TIFFDataWidth(static_cast<TIFFDataType>(nDataType)) * nCount;
89✔
3676
            if (nTagSize > 4)
89✔
3677
            {
3678
                memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 8, 4);
37✔
3679
                if (bSwap)
37✔
3680
                    CPL_SWAP32PTR(&nTmp);
×
3681
                if (nTmp > static_cast<GUInt32>(UINT_MAX - nTagSize))
37✔
3682
                {
3683
                    CPLError(CE_Failure, CPLE_NotSupported,
×
3684
                             "Overflow with tag %d", nTag);
3685
                    CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3686
                    VSIUnlink(osTmpFilename);
×
3687
                    return false;
×
3688
                }
3689
                if (nTmp + nTagSize > nMaxOffset)
37✔
3690
                    nMaxOffset = nTmp + nTagSize;
32✔
3691
            }
3692
        }
3693
    }
3694
    if (nMaxOffset > 10 * 1024 * 1024)
7✔
3695
    {
3696
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3697
        VSIUnlink(osTmpFilename);
×
3698
        return false;
×
3699
    }
3700
    if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
7✔
3701
                               static_cast<int>(nMaxOffset), pabyBuffer,
3702
                               nDataLength))
3703
    {
3704
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
×
3705
        VSIUnlink(osTmpFilename);
×
3706
        return false;
×
3707
    }
3708
    CPLAssert(nDataLength == VSIFTellL(poOpenInfo->fpL));
7✔
3709
    poOpenInfo->fpL = VSICreateBufferedReaderHandle(
7✔
3710
        poOpenInfo->fpL, pabyBuffer, static_cast<vsi_l_offset>(INT_MAX) << 32);
3711
    if (VSIFCloseL(fpTemp) != 0)
7✔
3712
        return false;
×
3713
    VSIUnlink(osTmpFilename);
7✔
3714

3715
    return true;
7✔
3716
}
3717

3718
/************************************************************************/
3719
/*                       AssociateExternalMask()                        */
3720
/************************************************************************/
3721

3722
// Used by GTIFFBuildOverviewsEx() for the COG driver
3723
bool GTiffDataset::AssociateExternalMask()
9✔
3724
{
3725
    if (m_poMaskExtOvrDS->GetRasterBand(1)->GetOverviewCount() !=
9✔
3726
        GetRasterBand(1)->GetOverviewCount())
9✔
3727
        return false;
×
3728
    if (m_papoOverviewDS == nullptr)
9✔
3729
        return false;
×
3730
    if (m_poMaskDS)
9✔
3731
        return false;
×
3732
    if (m_poMaskExtOvrDS->GetRasterXSize() != nRasterXSize ||
18✔
3733
        m_poMaskExtOvrDS->GetRasterYSize() != nRasterYSize)
9✔
3734
        return false;
×
3735
    m_poExternalMaskDS = m_poMaskExtOvrDS.get();
9✔
3736
    for (int i = 0; i < m_nOverviewCount; i++)
21✔
3737
    {
3738
        if (m_papoOverviewDS[i]->m_poMaskDS)
12✔
3739
            return false;
×
3740
        m_papoOverviewDS[i]->m_poExternalMaskDS =
24✔
3741
            m_poMaskExtOvrDS->GetRasterBand(1)->GetOverview(i)->GetDataset();
12✔
3742
        if (!m_papoOverviewDS[i]->m_poExternalMaskDS)
12✔
3743
            return false;
×
3744
        auto poOvrBand = m_papoOverviewDS[i]->GetRasterBand(1);
12✔
3745
        if (m_papoOverviewDS[i]->m_poExternalMaskDS->GetRasterXSize() !=
12✔
3746
                poOvrBand->GetXSize() ||
24✔
3747
            m_papoOverviewDS[i]->m_poExternalMaskDS->GetRasterYSize() !=
12✔
3748
                poOvrBand->GetYSize())
12✔
3749
            return false;
×
3750
    }
3751
    return true;
9✔
3752
}
3753

3754
/************************************************************************/
3755
/*                                Open()                                */
3756
/************************************************************************/
3757

3758
GDALDataset *GTiffDataset::Open(GDALOpenInfo *poOpenInfo)
20,022✔
3759

3760
{
3761
    const char *pszFilename = poOpenInfo->pszFilename;
20,022✔
3762

3763
    /* -------------------------------------------------------------------- */
3764
    /*      Check if it looks like a TIFF file.                             */
3765
    /* -------------------------------------------------------------------- */
3766
    if (!Identify(poOpenInfo))
20,022✔
3767
        return nullptr;
×
3768

3769
    bool bAllowRGBAInterface = true;
19,987✔
3770
    if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
19,987✔
3771
    {
3772
        bAllowRGBAInterface = false;
10✔
3773
        pszFilename += strlen("GTIFF_RAW:");
10✔
3774
    }
3775

3776
    /* -------------------------------------------------------------------- */
3777
    /*      We have a special hook for handling opening a specific          */
3778
    /*      directory of a TIFF file.                                       */
3779
    /* -------------------------------------------------------------------- */
3780
    if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
19,987✔
3781
        return OpenDir(poOpenInfo);
25✔
3782

3783
    GTiffOneTimeInit();
19,962✔
3784

3785
    /* -------------------------------------------------------------------- */
3786
    /*      Try opening the dataset.                                        */
3787
    /* -------------------------------------------------------------------- */
3788
    bool bStreaming = false;
20,053✔
3789
    const char *pszReadStreaming =
3790
        CPLGetConfigOption("TIFF_READ_STREAMING", nullptr);
20,053✔
3791
    if (poOpenInfo->fpL == nullptr)
20,053✔
3792
    {
3793
        poOpenInfo->fpL = VSIFOpenL(
9✔
3794
            pszFilename, poOpenInfo->eAccess == GA_ReadOnly ? "rb" : "r+b");
9✔
3795
        if (poOpenInfo->fpL == nullptr)
9✔
3796
            return nullptr;
×
3797
    }
3798
    else if (!(pszReadStreaming && !CPLTestBool(pszReadStreaming)) &&
7✔
3799
             poOpenInfo->nHeaderBytes >= 24 &&
40,094✔
3800
             // A pipe has no seeking capability, so its position is 0 despite
3801
             // having read bytes.
3802
             (static_cast<int>(VSIFTellL(poOpenInfo->fpL)) ==
20,043✔
3803
                  poOpenInfo->nHeaderBytes ||
20,043✔
3804
              strcmp(pszFilename, "/vsistdin/") == 0 ||
20,043✔
3805
              // STARTS_WITH(pszFilename, "/vsicurl_streaming/") ||
3806
              (pszReadStreaming && CPLTestBool(pszReadStreaming))))
7✔
3807
    {
3808
        bStreaming = true;
9✔
3809
        if (!GTIFFMakeBufferedStream(poOpenInfo))
9✔
3810
            return nullptr;
2✔
3811
    }
3812

3813
    // Store errors/warnings and emit them later.
3814
    TIFF *l_hTIFF;
3815
    CPLErrorAccumulator oErrorAccumulator;
40,102✔
3816
    {
3817
        auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
19,839✔
3818
        CPL_IGNORE_RET_VAL(oAccumulator);
19,987✔
3819
        CPLSetCurrentErrorHandlerCatchDebug(FALSE);
19,906✔
3820
        const bool bDeferStrileLoading = CPLTestBool(
19,829✔
3821
            CPLGetConfigOption("GTIFF_USE_DEFER_STRILE_LOADING", "YES"));
3822
        l_hTIFF = VSI_TIFFOpen(
20,051✔
3823
            pszFilename,
3824
            poOpenInfo->eAccess == GA_ReadOnly
20,051✔
3825
                ? ((bStreaming || !bDeferStrileLoading) ? "rC" : "rDOC")
19,329✔
3826
                : (!bDeferStrileLoading ? "r+C" : "r+DC"),
722✔
3827
            poOpenInfo->fpL);
3828
    };
3829

3830
    // Now emit errors and change their criticality if needed
3831
    // We only emit failures if we didn't manage to open the file.
3832
    // Otherwise it makes Python bindings unhappy (#5616).
3833
    for (const auto &oError : oErrorAccumulator.GetErrors())
19,935✔
3834
    {
3835
        ReportError(pszFilename,
76✔
3836
                    (l_hTIFF == nullptr && oError.type == CE_Failure)
1✔
3837
                        ? CE_Failure
3838
                        : CE_Warning,
3839
                    oError.no, "%s", oError.msg.c_str());
38✔
3840
    }
3841

3842
    if (l_hTIFF == nullptr)
19,788✔
3843
        return nullptr;
2✔
3844

3845
    uint32_t nXSize = 0;
19,786✔
3846
    TIFFGetField(l_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
19,786✔
3847
    uint32_t nYSize = 0;
19,888✔
3848
    TIFFGetField(l_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
19,888✔
3849

3850
    if (nXSize > INT_MAX || nYSize > INT_MAX)
19,909✔
3851
    {
3852
        // GDAL only supports signed 32bit dimensions.
3853
        ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
122✔
3854
                    "Too large image size: %u x %u", nXSize, nYSize);
3855
        XTIFFClose(l_hTIFF);
1✔
3856
        return nullptr;
1✔
3857
    }
3858

3859
    uint16_t l_nCompression = 0;
19,787✔
3860
    if (!TIFFGetField(l_hTIFF, TIFFTAG_COMPRESSION, &(l_nCompression)))
19,787✔
3861
        l_nCompression = COMPRESSION_NONE;
×
3862

3863
    /* -------------------------------------------------------------------- */
3864
    /*      Create a corresponding GDALDataset.                             */
3865
    /* -------------------------------------------------------------------- */
3866
    GTiffDataset *poDS = new GTiffDataset();
19,882✔
3867
    poDS->SetDescription(pszFilename);
19,984✔
3868
    poDS->m_pszFilename = CPLStrdup(pszFilename);
19,970✔
3869
    poDS->m_fpL = poOpenInfo->fpL;
19,972✔
3870
    poOpenInfo->fpL = nullptr;
19,972✔
3871
    poDS->m_bStreamingIn = bStreaming;
19,972✔
3872
    poDS->m_nCompression = l_nCompression;
19,972✔
3873

3874
    // Check structural metadata (for COG)
3875
    const int nOffsetOfStructuralMetadata =
19,972✔
3876
        poOpenInfo->nHeaderBytes && ((poOpenInfo->pabyHeader[2] == 0x2B ||
19,938✔
3877
                                      poOpenInfo->pabyHeader[3] == 0x2B))
19,784✔
3878
            ? 16
39,910✔
3879
            : 8;
3880
    if (poOpenInfo->nHeaderBytes >
19,972✔
3881
            nOffsetOfStructuralMetadata +
19,972✔
3882
                static_cast<int>(strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) &&
19,905✔
3883
        memcmp(poOpenInfo->pabyHeader + nOffsetOfStructuralMetadata,
19,905✔
3884
               "GDAL_STRUCTURAL_METADATA_SIZE=",
3885
               strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) == 0)
3886
    {
3887
        const char *pszStructuralMD = reinterpret_cast<const char *>(
237✔
3888
            poOpenInfo->pabyHeader + nOffsetOfStructuralMetadata);
237✔
3889
        poDS->m_bLayoutIFDSBeforeData =
237✔
3890
            strstr(pszStructuralMD, "LAYOUT=IFDS_BEFORE_DATA") != nullptr;
237✔
3891
        poDS->m_bBlockOrderRowMajor =
237✔
3892
            strstr(pszStructuralMD, "BLOCK_ORDER=ROW_MAJOR") != nullptr;
237✔
3893
        poDS->m_bLeaderSizeAsUInt4 =
237✔
3894
            strstr(pszStructuralMD, "BLOCK_LEADER=SIZE_AS_UINT4") != nullptr &&
474✔
3895
            (strstr(pszStructuralMD, "INTERLEAVE=") == nullptr ||
237✔
3896
             strstr(pszStructuralMD, "INTERLEAVE=BAND") != nullptr ||
23✔
3897
             strstr(pszStructuralMD, "INTERLEAVE=TILE") != nullptr);
×
3898
        poDS->m_bTrailerRepeatedLast4BytesRepeated =
237✔
3899
            strstr(pszStructuralMD, "BLOCK_TRAILER=LAST_4_BYTES_REPEATED") !=
237✔
3900
                nullptr &&
474✔
3901
            (strstr(pszStructuralMD, "INTERLEAVE=") == nullptr ||
237✔
3902
             strstr(pszStructuralMD, "INTERLEAVE=BAND") != nullptr ||
23✔
3903
             strstr(pszStructuralMD, "INTERLEAVE=TILE") != nullptr);
×
3904
        poDS->m_bMaskInterleavedWithImagery =
237✔
3905
            strstr(pszStructuralMD, "MASK_INTERLEAVED_WITH_IMAGERY=YES") !=
237✔
3906
                nullptr &&
279✔
3907
            strstr(pszStructuralMD, "INTERLEAVE=") == nullptr;
42✔
3908
        poDS->m_bKnownIncompatibleEdition =
237✔
3909
            strstr(pszStructuralMD, "KNOWN_INCOMPATIBLE_EDITION=YES") !=
237✔
3910
            nullptr;
3911
        if (poDS->m_bKnownIncompatibleEdition)
237✔
3912
        {
3913
            poDS->ReportError(
6✔
3914
                CE_Warning, CPLE_AppDefined,
3915
                "This file used to have optimizations in its layout, "
3916
                "but those have been, at least partly, invalidated by "
3917
                "later changes");
3918
        }
3919
        else if (poDS->m_bLayoutIFDSBeforeData && poDS->m_bBlockOrderRowMajor &&
231✔
3920
                 poDS->m_bLeaderSizeAsUInt4 &&
231✔
3921
                 poDS->m_bTrailerRepeatedLast4BytesRepeated)
231✔
3922
        {
3923
            if (poOpenInfo->eAccess == GA_Update &&
236✔
3924
                !CPLTestBool(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
5✔
3925
                                                  "IGNORE_COG_LAYOUT_BREAK",
3926
                                                  "FALSE")))
3927
            {
3928
                CPLError(CE_Failure, CPLE_AppDefined,
1✔
3929
                         "File %s has C(loud) O(ptimized) G(eoTIFF) layout. "
3930
                         "Updating it will generally result in losing part of "
3931
                         "the optimizations (but will still produce a valid "
3932
                         "GeoTIFF file). If this is acceptable, open the file "
3933
                         "with the IGNORE_COG_LAYOUT_BREAK open option set "
3934
                         "to YES.",
3935
                         pszFilename);
3936
                XTIFFClose(l_hTIFF);
1✔
3937
                delete poDS;
1✔
3938
                return nullptr;
1✔
3939
            }
3940
            poDS->m_oGTiffMDMD.SetMetadataItem("LAYOUT", "COG",
230✔
3941
                                               "IMAGE_STRUCTURE");
3942
        }
3943
    }
3944

3945
    // In the case of GDAL_DISABLE_READDIR_ON_OPEN = NO / EMPTY_DIR
3946
    if (poOpenInfo->AreSiblingFilesLoaded() &&
20,127✔
3947
        CSLCount(poOpenInfo->GetSiblingFiles()) <= 1)
156✔
3948
    {
3949
        poDS->oOvManager.TransferSiblingFiles(
59✔
3950
            CSLDuplicate(poOpenInfo->GetSiblingFiles()));
59✔
3951
        poDS->m_bHasGotSiblingFiles = true;
59✔
3952
    }
3953

3954
    // Should be capped by 257, to avoid 65535 / m_nColorTableMultiplier to overflow 255
3955
    poDS->m_nColorTableMultiplier = std::max(
19,703✔
3956
        0, std::min(257,
59,168✔
3957
                    atoi(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
19,863✔
3958
                                              "COLOR_TABLE_MULTIPLIER", "0"))));
19,716✔
3959

3960
    if (poDS->OpenOffset(l_hTIFF, TIFFCurrentDirOffset(l_hTIFF),
19,703✔
3961
                         poOpenInfo->eAccess, bAllowRGBAInterface,
3962
                         true) != CE_None)
19,854✔
3963
    {
3964
        delete poDS;
9✔
3965
        return nullptr;
9✔
3966
    }
3967

3968
    // Do we want blocks that are set to zero and that haven't yet being
3969
    // allocated as tile/strip to remain implicit?
3970
    if (CPLFetchBool(poOpenInfo->papszOpenOptions, "SPARSE_OK", false))
19,845✔
3971
        poDS->m_bWriteEmptyTiles = false;
52✔
3972

3973
    poDS->InitCreationOrOpenOptions(poOpenInfo->eAccess == GA_Update,
19,786✔
3974
                                    poOpenInfo->papszOpenOptions);
19,786✔
3975

3976
    poDS->m_bLoadPam = true;
19,755✔
3977
    poDS->m_bColorProfileMetadataChanged = false;
19,755✔
3978
    poDS->m_bMetadataChanged = false;
19,755✔
3979
    poDS->m_bGeoTIFFInfoChanged = false;
19,755✔
3980
    poDS->m_bNoDataChanged = false;
19,755✔
3981
    poDS->m_bForceUnsetGTOrGCPs = false;
19,755✔
3982
    poDS->m_bForceUnsetProjection = false;
19,755✔
3983

3984
    // Used by GTIFFBuildOverviewsEx() for the COG driver
3985
    const char *pszMaskOverviewDS = CSLFetchNameValue(
39,604✔
3986
        poOpenInfo->papszOpenOptions, "MASK_OVERVIEW_DATASET");
19,755✔
3987
    if (pszMaskOverviewDS)
19,849✔
3988
    {
3989
        poDS->m_poMaskExtOvrDS.reset(GDALDataset::Open(
9✔
3990
            pszMaskOverviewDS, GDAL_OF_RASTER | GDAL_OF_INTERNAL));
3991
        if (!poDS->m_poMaskExtOvrDS || !poDS->AssociateExternalMask())
9✔
3992
        {
3993
            CPLDebug("GTiff",
×
3994
                     "Association with external mask overview file failed");
3995
        }
3996
    }
3997

3998
    /* -------------------------------------------------------------------- */
3999
    /*      Initialize info for external overviews.                         */
4000
    /* -------------------------------------------------------------------- */
4001
    poDS->oOvManager.Initialize(poDS, poOpenInfo, pszFilename);
19,849✔
4002

4003
    // For backward compatibility, in case GTIFF_POINT_GEO_IGNORE is defined
4004
    // load georeferencing right now so as to not require it to be defined
4005
    // at the GetGeoTransform() time.
4006
    if (CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE", nullptr) != nullptr)
19,849✔
4007
    {
4008
        poDS->LoadGeoreferencingAndPamIfNeeded();
14✔
4009
    }
4010

4011
    return poDS;
20,038✔
4012
}
4013

4014
/************************************************************************/
4015
/*                      GTiffDatasetSetAreaOrPointMD()                  */
4016
/************************************************************************/
4017

4018
static void GTiffDatasetSetAreaOrPointMD(GTIF *hGTIF,
10,551✔
4019
                                         GDALMultiDomainMetadata &m_oGTiffMDMD)
4020
{
4021
    // Is this a pixel-is-point dataset?
4022
    unsigned short nRasterType = 0;
10,551✔
4023

4024
    if (GDALGTIFKeyGetSHORT(hGTIF, GTRasterTypeGeoKey, &nRasterType, 0, 1) == 1)
10,551✔
4025
    {
4026
        if (nRasterType == static_cast<short>(RasterPixelIsPoint))
7,460✔
4027
            m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT,
145✔
4028
                                         GDALMD_AOP_POINT);
4029
        else
4030
            m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA);
7,315✔
4031
    }
4032
}
10,550✔
4033

4034
/************************************************************************/
4035
/*                         LoadMDAreaOrPoint()                          */
4036
/************************************************************************/
4037

4038
// This is a light version of LookForProjection(), which saves the
4039
// potential costly cost of GTIFGetOGISDefn(), since we just need to
4040
// access to a raw GeoTIFF key, and not build the full projection object.
4041

4042
void GTiffDataset::LoadMDAreaOrPoint()
13,144✔
4043
{
4044
    if (m_bLookedForProjection || m_bLookedForMDAreaOrPoint ||
14,098✔
4045
        m_oGTiffMDMD.GetMetadataItem(GDALMD_AREA_OR_POINT) != nullptr)
954✔
4046
        return;
12,190✔
4047

4048
    m_bLookedForMDAreaOrPoint = true;
954✔
4049

4050
    GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
954✔
4051

4052
    if (!hGTIF)
954✔
4053
    {
4054
        ReportError(CE_Warning, CPLE_AppDefined,
×
4055
                    "GeoTIFF tags apparently corrupt, they are being ignored.");
4056
    }
4057
    else
4058
    {
4059
        GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
954✔
4060

4061
        GTIFFree(hGTIF);
954✔
4062
    }
4063
}
4064

4065
/************************************************************************/
4066
/*                         LookForProjection()                          */
4067
/************************************************************************/
4068

4069
void GTiffDataset::LookForProjection()
225,458✔
4070

4071
{
4072
    if (m_bLookedForProjection)
225,458✔
4073
        return;
215,854✔
4074

4075
    m_bLookedForProjection = true;
9,604✔
4076

4077
    IdentifyAuthorizedGeoreferencingSources();
9,604✔
4078

4079
    m_oSRS.Clear();
9,604✔
4080

4081
    std::set<signed char> aoSetPriorities;
19,209✔
4082
    if (m_nINTERNALGeorefSrcIndex >= 0)
9,603✔
4083
        aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
9,597✔
4084
    if (m_nXMLGeorefSrcIndex >= 0)
9,603✔
4085
        aoSetPriorities.insert(m_nXMLGeorefSrcIndex);
9,567✔
4086
    for (const auto nIndex : aoSetPriorities)
28,764✔
4087
    {
4088
        if (m_nINTERNALGeorefSrcIndex == nIndex)
19,160✔
4089
        {
4090
            LookForProjectionFromGeoTIFF();
9,596✔
4091
        }
4092
        else if (m_nXMLGeorefSrcIndex == nIndex)
9,564✔
4093
        {
4094
            LookForProjectionFromXML();
9,563✔
4095
        }
4096
    }
4097
}
4098

4099
/************************************************************************/
4100
/*                      LookForProjectionFromGeoTIFF()                  */
4101
/************************************************************************/
4102

4103
void GTiffDataset::LookForProjectionFromGeoTIFF()
9,597✔
4104
{
4105
    /* -------------------------------------------------------------------- */
4106
    /*      Capture the GeoTIFF projection, if available.                   */
4107
    /* -------------------------------------------------------------------- */
4108

4109
    GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
9,597✔
4110

4111
    if (!hGTIF)
9,597✔
4112
    {
4113
        ReportError(CE_Warning, CPLE_AppDefined,
×
4114
                    "GeoTIFF tags apparently corrupt, they are being ignored.");
4115
    }
4116
    else
4117
    {
4118
        GTIFDefn *psGTIFDefn = GTIFAllocDefn();
9,597✔
4119

4120
        bool bHasErrorBefore = CPLGetLastErrorType() != 0;
9,597✔
4121
        // Collect (PROJ) error messages and remit them later as warnings
4122
        int ret;
4123
        CPLErrorAccumulator oErrorAccumulator;
19,191✔
4124
        {
4125
            auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
9,597✔
4126
            ret = GTIFGetDefn(hGTIF, psGTIFDefn);
9,597✔
4127
        }
4128

4129
        bool bWarnAboutEllipsoid = true;
9,597✔
4130

4131
        if (ret)
9,597✔
4132
        {
4133
            auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
14,126✔
4134

4135
            if (psGTIFDefn->Ellipsoid == 4326 &&
7,063✔
4136
                psGTIFDefn->SemiMajor == 6378137 &&
1✔
4137
                psGTIFDefn->SemiMinor == 6356752.314245)
1✔
4138
            {
4139
                // Buggy Sentinel1 geotiff files use a wrong 4326 code for the
4140
                // ellipsoid instead of 7030.
4141
                psGTIFDefn->Ellipsoid = 7030;
1✔
4142
                bWarnAboutEllipsoid = false;
1✔
4143
            }
4144

4145
            OGRSpatialReferenceH hSRS = GTIFGetOGISDefnAsOSR(hGTIF, psGTIFDefn);
7,063✔
4146

4147
            if (hSRS)
7,063✔
4148
            {
4149
                CPLFree(m_pszXMLFilename);
7,062✔
4150
                m_pszXMLFilename = nullptr;
7,062✔
4151

4152
                m_oSRS = *(OGRSpatialReference::FromHandle(hSRS));
7,062✔
4153
                OSRDestroySpatialReference(hSRS);
7,063✔
4154
            }
4155
        }
4156

4157
        std::set<std::string> oSetErrorMsg;
19,192✔
4158
        for (const auto &oError : oErrorAccumulator.GetErrors())
9,606✔
4159
        {
4160
            if (!bWarnAboutEllipsoid &&
13✔
4161
                oError.msg.find("ellipsoid not found") != std::string::npos)
1✔
4162
            {
4163
                continue;
1✔
4164
            }
4165

4166
            // Some error messages might be duplicated in GTIFGetDefn()
4167
            // and GTIFGetOGISDefnAsOSR(). Emit them just once.
4168
            if (oSetErrorMsg.find(oError.msg) == oSetErrorMsg.end())
11✔
4169
            {
4170
                oSetErrorMsg.insert(oError.msg);
8✔
4171
                CPLError(oError.type == CE_Failure ? CE_Warning : oError.type,
16✔
4172
                         oError.no, "%s", oError.msg.c_str());
8✔
4173
            }
4174
        }
4175

4176
        if (!bHasErrorBefore && oSetErrorMsg.empty())
9,596✔
4177
        {
4178
            CPLErrorReset();
9,537✔
4179
        }
4180

4181
        if (ret && m_oSRS.IsCompound())
9,590✔
4182
        {
4183
            const char *pszVertUnit = nullptr;
35✔
4184
            m_oSRS.GetTargetLinearUnits("COMPD_CS|VERT_CS", &pszVertUnit);
35✔
4185
            if (pszVertUnit && !EQUAL(pszVertUnit, "unknown"))
35✔
4186
            {
4187
                CPLFree(m_pszVertUnit);
35✔
4188
                m_pszVertUnit = CPLStrdup(pszVertUnit);
35✔
4189
            }
4190

4191
            int versions[3];
4192
            GTIFDirectoryInfo(hGTIF, versions, nullptr);
35✔
4193

4194
            // If GeoTIFF 1.0, strip vertical by default
4195
            const char *pszDefaultReportCompdCS =
35✔
4196
                (versions[0] == 1 && versions[1] == 1 && versions[2] == 0)
35✔
4197
                    ? "NO"
70✔
4198
                    : "YES";
4199

4200
            // Should we simplify away vertical CS stuff?
4201
            if (!CPLTestBool(CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
35✔
4202
                                                pszDefaultReportCompdCS)))
4203
            {
4204
                CPLDebug("GTiff", "Got COMPD_CS, but stripping it.");
10✔
4205

4206
                m_oSRS.StripVertical();
10✔
4207
            }
4208
        }
4209

4210
        GTIFFreeDefn(psGTIFDefn);
9,594✔
4211

4212
        GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
9,595✔
4213

4214
        GTIFFree(hGTIF);
9,597✔
4215
    }
4216
}
9,593✔
4217

4218
/************************************************************************/
4219
/*                      LookForProjectionFromXML()                      */
4220
/************************************************************************/
4221

4222
void GTiffDataset::LookForProjectionFromXML()
9,567✔
4223
{
4224
    CSLConstList papszSiblingFiles = GetSiblingFiles();
9,567✔
4225

4226
    if (!GDALCanFileAcceptSidecarFile(m_pszFilename))
9,565✔
4227
        return;
9,565✔
4228

4229
    const std::string osXMLFilenameLowerCase =
4230
        CPLResetExtensionSafe(m_pszFilename, "xml");
9,563✔
4231

4232
    CPLString osXMLFilename;
9,566✔
4233
    if (papszSiblingFiles &&
19,100✔
4234
        GDALCanReliablyUseSiblingFileList(osXMLFilenameLowerCase.c_str()))
9,536✔
4235
    {
4236
        const int iSibling = CSLFindString(
9,534✔
4237
            papszSiblingFiles, CPLGetFilename(osXMLFilenameLowerCase.c_str()));
4238
        if (iSibling >= 0)
9,537✔
4239
        {
4240
            osXMLFilename = m_pszFilename;
4✔
4241
            osXMLFilename.resize(strlen(m_pszFilename) -
8✔
4242
                                 strlen(CPLGetFilename(m_pszFilename)));
4✔
4243
            osXMLFilename += papszSiblingFiles[iSibling];
4✔
4244
        }
4245
        else
4246
        {
4247
            return;
9,533✔
4248
        }
4249
    }
4250

4251
    if (osXMLFilename.empty())
34✔
4252
    {
4253
        VSIStatBufL sStatBuf;
4254
        bool bGotXML = VSIStatExL(osXMLFilenameLowerCase.c_str(), &sStatBuf,
29✔
4255
                                  VSI_STAT_EXISTS_FLAG) == 0;
29✔
4256

4257
        if (bGotXML)
29✔
4258
        {
4259
            osXMLFilename = osXMLFilenameLowerCase;
×
4260
        }
4261
        else if (VSIIsCaseSensitiveFS(osXMLFilenameLowerCase.c_str()))
29✔
4262
        {
4263
            const std::string osXMLFilenameUpperCase =
4264
                CPLResetExtensionSafe(m_pszFilename, "XML");
58✔
4265
            bGotXML = VSIStatExL(osXMLFilenameUpperCase.c_str(), &sStatBuf,
29✔
4266
                                 VSI_STAT_EXISTS_FLAG) == 0;
4267
            if (bGotXML)
29✔
4268
            {
4269
                osXMLFilename = osXMLFilenameUpperCase;
×
4270
            }
4271
        }
4272

4273
        if (osXMLFilename.empty())
29✔
4274
        {
4275
            return;
29✔
4276
        }
4277
    }
4278

4279
    GByte *pabyRet = nullptr;
4✔
4280
    vsi_l_offset nSize = 0;
4✔
4281
    constexpr int nMaxSize = 10 * 1024 * 1024;
4✔
4282
    if (!VSIIngestFile(nullptr, osXMLFilename.c_str(), &pabyRet, &nSize,
4✔
4283
                       nMaxSize))
4284
        return;
×
4285
    CPLXMLTreeCloser oXML(
4286
        CPLParseXMLString(reinterpret_cast<const char *>(pabyRet)));
4✔
4287
    VSIFree(pabyRet);
4✔
4288
    if (!oXML.get())
4✔
4289
        return;
×
4290
    const char *pszCode = CPLGetXMLValue(
4✔
4291
        oXML.get(), "=metadata.refSysInfo.RefSystem.refSysID.identCode.code",
4✔
4292
        "0");
4293
    const int nCode = atoi(pszCode);
4✔
4294
    if (nCode <= 0)
4✔
4295
        return;
2✔
4296
    if (nCode <= 32767)
2✔
4297
        m_oSRS.importFromEPSG(nCode);
2✔
4298
    else
4299
        m_oSRS.SetFromUserInput(CPLSPrintf("ESRI:%d", nCode));
×
4300

4301
    CPLFree(m_pszXMLFilename);
2✔
4302
    m_pszXMLFilename = CPLStrdup(osXMLFilename.c_str());
2✔
4303
}
4304

4305
/************************************************************************/
4306
/*                            ApplyPamInfo()                            */
4307
/*                                                                      */
4308
/*      PAM Information, if available, overrides the GeoTIFF            */
4309
/*      geotransform and projection definition.  Check for them         */
4310
/*      now.                                                            */
4311
/************************************************************************/
4312

4313
void GTiffDataset::ApplyPamInfo()
11,336✔
4314

4315
{
4316
    bool bGotGTFromPAM = false;
11,336✔
4317

4318
    if (m_nPAMGeorefSrcIndex >= 0 &&
11,336✔
4319
        ((m_bGeoTransformValid &&
11,336✔
4320
          m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
8,120✔
4321
         m_nGeoTransformGeorefSrcIndex < 0 || !m_bGeoTransformValid))
3,226✔
4322
    {
4323
        double adfPamGeoTransform[6] = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0};
11,326✔
4324
        if (GDALPamDataset::GetGeoTransform(adfPamGeoTransform) == CE_None)
11,326✔
4325
        {
4326
            if (m_nGeoTransformGeorefSrcIndex == m_nWORLDFILEGeorefSrcIndex)
44✔
4327
            {
4328
                CPLFree(m_pszGeorefFilename);
12✔
4329
                m_pszGeorefFilename = nullptr;
12✔
4330
            }
4331
            memcpy(m_adfGeoTransform, adfPamGeoTransform, sizeof(double) * 6);
44✔
4332
            m_bGeoTransformValid = true;
44✔
4333
            bGotGTFromPAM = true;
44✔
4334
        }
4335
    }
4336

4337
    if (m_nPAMGeorefSrcIndex >= 0)
11,334✔
4338
    {
4339
        if ((m_nTABFILEGeorefSrcIndex < 0 ||
11,335✔
4340
             m_nPAMGeorefSrcIndex < m_nTABFILEGeorefSrcIndex) &&
11,300✔
4341
            (m_nINTERNALGeorefSrcIndex < 0 ||
11,333✔
4342
             m_nPAMGeorefSrcIndex < m_nINTERNALGeorefSrcIndex))
11,319✔
4343
        {
4344
            const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
11,320✔
4345
            if (poPamSRS)
11,320✔
4346
            {
4347
                m_oSRS = *poPamSRS;
46✔
4348
                m_bLookedForProjection = true;
46✔
4349
                // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4350
            }
11,320✔
4351
        }
4352
        else
4353
        {
4354
            if (m_nINTERNALGeorefSrcIndex >= 0)
15✔
4355
                LookForProjection();
12✔
4356
            if (m_oSRS.IsEmpty())
15✔
4357
            {
4358
                const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
8✔
4359
                if (poPamSRS)
8✔
4360
                {
4361
                    m_oSRS = *poPamSRS;
8✔
4362
                    m_bLookedForProjection = true;
8✔
4363
                    // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4364
                }
4365
            }
4366
        }
4367
    }
4368

4369
    int nPamGCPCount;
4370
    if (m_nPAMGeorefSrcIndex >= 0 && !oMDMD.GetMetadata("xml:ESRI") &&
11,334✔
4371
        (nPamGCPCount = GDALPamDataset::GetGCPCount()) > 0 &&
22,686✔
4372
        ((!m_aoGCPs.empty() &&
19✔
4373
          m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
11✔
4374
         m_nGeoTransformGeorefSrcIndex < 0 || m_aoGCPs.empty()))
10✔
4375
    {
4376
        m_aoGCPs = gdal::GCP::fromC(GDALPamDataset::GetGCPs(), nPamGCPCount);
17✔
4377

4378
        // Invalidate Geotransorm got from less prioritary sources
4379
        if (!m_aoGCPs.empty() && m_bGeoTransformValid && !bGotGTFromPAM &&
19✔
4380
            m_nPAMGeorefSrcIndex == 0)
2✔
4381
        {
4382
            m_bGeoTransformValid = false;
2✔
4383
        }
4384

4385
        // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4386

4387
        const auto *poPamGCPSRS = GDALPamDataset::GetGCPSpatialRef();
17✔
4388
        if (poPamGCPSRS)
17✔
4389
            m_oSRS = *poPamGCPSRS;
15✔
4390
        else
4391
            m_oSRS.Clear();
2✔
4392

4393
        m_bLookedForProjection = true;
17✔
4394
    }
4395

4396
    if (m_nPAMGeorefSrcIndex >= 0)
11,334✔
4397
    {
4398
        CPLXMLNode *psValueAsXML = nullptr;
11,333✔
4399
        CPLXMLNode *psGeodataXform = nullptr;
11,333✔
4400
        char **papszXML = oMDMD.GetMetadata("xml:ESRI");
11,333✔
4401
        if (CSLCount(papszXML) == 1)
11,334✔
4402
        {
4403
            psValueAsXML = CPLParseXMLString(papszXML[0]);
9✔
4404
            if (psValueAsXML)
9✔
4405
                psGeodataXform = CPLGetXMLNode(psValueAsXML, "=GeodataXform");
9✔
4406
        }
4407

4408
        const char *pszTIFFTagResUnit =
4409
            GetMetadataItem("TIFFTAG_RESOLUTIONUNIT");
11,333✔
4410
        const char *pszTIFFTagXRes = GetMetadataItem("TIFFTAG_XRESOLUTION");
11,334✔
4411
        const char *pszTIFFTagYRes = GetMetadataItem("TIFFTAG_YRESOLUTION");
11,336✔
4412
        if (psGeodataXform && pszTIFFTagXRes && pszTIFFTagYRes &&
11,336✔
4413
            pszTIFFTagResUnit && atoi(pszTIFFTagResUnit) == 2)
1✔
4414
        {
4415
            CPLXMLNode *psSourceGCPs =
4416
                CPLGetXMLNode(psGeodataXform, "SourceGCPs");
1✔
4417
            CPLXMLNode *psTargetGCPs =
4418
                CPLGetXMLNode(psGeodataXform, "TargetGCPs");
1✔
4419
            if (psSourceGCPs && psTargetGCPs)
1✔
4420
            {
4421
                std::vector<double> adfSourceGCPs, adfTargetGCPs;
2✔
4422
                for (CPLXMLNode *psIter = psSourceGCPs->psChild;
1✔
4423
                     psIter != nullptr; psIter = psIter->psNext)
34✔
4424
                {
4425
                    if (psIter->eType == CXT_Element &&
33✔
4426
                        EQUAL(psIter->pszValue, "Double"))
32✔
4427
                    {
4428
                        adfSourceGCPs.push_back(
32✔
4429
                            CPLAtof(CPLGetXMLValue(psIter, nullptr, "")));
32✔
4430
                    }
4431
                }
4432
                for (CPLXMLNode *psIter = psTargetGCPs->psChild;
1✔
4433
                     psIter != nullptr; psIter = psIter->psNext)
34✔
4434
                {
4435
                    if (psIter->eType == CXT_Element &&
33✔
4436
                        EQUAL(psIter->pszValue, "Double"))
32✔
4437
                    {
4438
                        adfTargetGCPs.push_back(
32✔
4439
                            CPLAtof(CPLGetXMLValue(psIter, nullptr, "")));
32✔
4440
                    }
4441
                }
4442
                if (adfSourceGCPs.size() == adfTargetGCPs.size() &&
2✔
4443
                    (adfSourceGCPs.size() % 2) == 0)
1✔
4444
                {
4445
                    const char *pszESRI_WKT = CPLGetXMLValue(
1✔
4446
                        psGeodataXform, "SpatialReference.WKT", nullptr);
4447
                    if (pszESRI_WKT)
1✔
4448
                    {
4449
                        m_bLookedForProjection = true;
1✔
4450
                        m_oSRS.SetAxisMappingStrategy(
1✔
4451
                            OAMS_TRADITIONAL_GIS_ORDER);
4452
                        if (m_oSRS.importFromWkt(pszESRI_WKT) != OGRERR_NONE)
1✔
4453
                        {
4454
                            m_oSRS.Clear();
×
4455
                        }
4456
                    }
4457

4458
                    m_aoGCPs.clear();
1✔
4459
                    const size_t nNewGCPCount = adfSourceGCPs.size() / 2;
1✔
4460
                    for (size_t i = 0; i < nNewGCPCount; ++i)
17✔
4461
                    {
4462
                        m_aoGCPs.emplace_back(
4463
                            "", "",
4464
                            // The origin used is the bottom left corner,
4465
                            // and raw values to be multiplied by the
4466
                            // TIFFTAG_XRESOLUTION/TIFFTAG_YRESOLUTION
4467
                            /* pixel  = */
4468
                            adfSourceGCPs[2 * i] * CPLAtof(pszTIFFTagXRes),
16✔
4469
                            /* line = */
4470
                            nRasterYSize - adfSourceGCPs[2 * i + 1] *
32✔
4471
                                               CPLAtof(pszTIFFTagYRes),
16✔
4472
                            /* X = */ adfTargetGCPs[2 * i],
16✔
4473
                            /* Y = */ adfTargetGCPs[2 * i + 1]);
32✔
4474
                    }
4475

4476
                    // Invalidate Geotransform got from less prioritary sources
4477
                    if (!m_aoGCPs.empty() && m_bGeoTransformValid &&
2✔
4478
                        !bGotGTFromPAM && m_nPAMGeorefSrcIndex == 0)
2✔
4479
                    {
4480
                        m_bGeoTransformValid = false;
×
4481
                    }
4482
                }
4483
            }
4484
        }
4485

4486
        if (psValueAsXML)
11,336✔
4487
            CPLDestroyXMLNode(psValueAsXML);
9✔
4488
    }
4489

4490
    /* -------------------------------------------------------------------- */
4491
    /*      Copy any PAM metadata into our GeoTIFF context, and with        */
4492
    /*      the PAM info overriding the GeoTIFF context.                    */
4493
    /* -------------------------------------------------------------------- */
4494
    CSLConstList papszPamDomains = oMDMD.GetDomainList();
11,337✔
4495

4496
    for (int iDomain = 0;
11,373✔
4497
         papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
11,373✔
4498
    {
4499
        const char *pszDomain = papszPamDomains[iDomain];
39✔
4500
        char **papszGT_MD = CSLDuplicate(m_oGTiffMDMD.GetMetadata(pszDomain));
39✔
4501
        char **papszPAM_MD = oMDMD.GetMetadata(pszDomain);
39✔
4502

4503
        papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
39✔
4504

4505
        m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
39✔
4506
        CSLDestroy(papszGT_MD);
39✔
4507
    }
4508

4509
    for (int i = 1; i <= GetRasterCount(); ++i)
226,752✔
4510
    {
4511
        GTiffRasterBand *poBand =
4512
            cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
215,418✔
4513
        papszPamDomains = poBand->oMDMD.GetDomainList();
215,415✔
4514

4515
        for (int iDomain = 0;
215,490✔
4516
             papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
215,490✔
4517
        {
4518
            const char *pszDomain = papszPamDomains[iDomain];
72✔
4519
            char **papszGT_MD =
4520
                CSLDuplicate(poBand->m_oGTiffMDMD.GetMetadata(pszDomain));
72✔
4521
            char **papszPAM_MD = poBand->oMDMD.GetMetadata(pszDomain);
72✔
4522

4523
            papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
72✔
4524

4525
            poBand->m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
72✔
4526
            CSLDestroy(papszGT_MD);
72✔
4527
        }
4528
    }
4529

4530
    for (int i = 1; i <= nBands; ++i)
226,748✔
4531
    {
4532
        GTiffRasterBand *poBand =
4533
            cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
215,416✔
4534

4535
        /* Load scale, offset and unittype from PAM if available */
4536
        int nHaveOffsetScale = false;
215,419✔
4537
        double dfScale = poBand->GDALPamRasterBand::GetScale(&nHaveOffsetScale);
215,419✔
4538
        if (nHaveOffsetScale)
215,417✔
4539
        {
4540
            poBand->m_bHaveOffsetScale = true;
2✔
4541
            poBand->m_dfScale = dfScale;
2✔
4542
            poBand->m_dfOffset = poBand->GDALPamRasterBand::GetOffset();
2✔
4543
        }
4544

4545
        const char *pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
215,417✔
4546
        if (pszUnitType && pszUnitType[0])
215,412✔
4547
            poBand->m_osUnitType = pszUnitType;
15✔
4548

4549
        const char *pszDescription =
4550
            poBand->GDALPamRasterBand::GetDescription();
215,412✔
4551
        if (pszDescription && pszDescription[0])
215,415✔
4552
            poBand->m_osDescription = pszDescription;
19✔
4553

4554
        GDALColorInterp ePAMColorInterp =
4555
            poBand->GDALPamRasterBand::GetColorInterpretation();
215,415✔
4556
        if (ePAMColorInterp != GCI_Undefined)
215,413✔
4557
            poBand->m_eBandInterp = ePAMColorInterp;
51✔
4558

4559
        if (i == 1)
215,413✔
4560
        {
4561
            const auto poCT = poBand->GDALPamRasterBand::GetColorTable();
11,332✔
4562
            if (poCT)
11,333✔
4563
            {
4564
                m_poColorTable.reset(poCT->Clone());
4✔
4565
            }
4566
        }
4567
    }
4568
}
11,332✔
4569

4570
/************************************************************************/
4571
/*                              OpenDir()                               */
4572
/*                                                                      */
4573
/*      Open a specific directory as encoded into a filename.           */
4574
/************************************************************************/
4575

4576
GDALDataset *GTiffDataset::OpenDir(GDALOpenInfo *poOpenInfo)
25✔
4577

4578
{
4579
    bool bAllowRGBAInterface = true;
25✔
4580
    const char *pszFilename = poOpenInfo->pszFilename;
25✔
4581
    if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
25✔
4582
    {
4583
        bAllowRGBAInterface = false;
1✔
4584
        pszFilename += strlen("GTIFF_RAW:");
1✔
4585
    }
4586

4587
    if (!STARTS_WITH_CI(pszFilename, "GTIFF_DIR:") ||
25✔
4588
        pszFilename[strlen("GTIFF_DIR:")] == '\0')
25✔
4589
    {
4590
        return nullptr;
5✔
4591
    }
4592

4593
    /* -------------------------------------------------------------------- */
4594
    /*      Split out filename, and dir#/offset.                            */
4595
    /* -------------------------------------------------------------------- */
4596
    pszFilename += strlen("GTIFF_DIR:");
20✔
4597
    bool bAbsolute = false;
20✔
4598

4599
    if (STARTS_WITH_CI(pszFilename, "off:"))
20✔
4600
    {
4601
        bAbsolute = true;
2✔
4602
        pszFilename += 4;
2✔
4603
    }
4604

4605
    toff_t nOffset = atol(pszFilename);
20✔
4606
    pszFilename += 1;
20✔
4607

4608
    while (*pszFilename != '\0' && pszFilename[-1] != ':')
44✔
4609
        ++pszFilename;
24✔
4610

4611
    if (*pszFilename == '\0' || nOffset == 0)
20✔
4612
    {
4613
        ReportError(
×
4614
            pszFilename, CE_Failure, CPLE_OpenFailed,
4615
            "Unable to extract offset or filename, should take the form:\n"
4616
            "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename");
4617
        return nullptr;
×
4618
    }
4619

4620
    if (poOpenInfo->eAccess == GA_Update)
20✔
4621
    {
4622
        ReportError(pszFilename, CE_Warning, CPLE_AppDefined,
1✔
4623
                    "Opening a specific TIFF directory is not supported in "
4624
                    "update mode. Switching to read-only");
4625
    }
4626

4627
    /* -------------------------------------------------------------------- */
4628
    /*      Try opening the dataset.                                        */
4629
    /* -------------------------------------------------------------------- */
4630
    GTiffOneTimeInit();
20✔
4631

4632
    const char *pszFlag = poOpenInfo->eAccess == GA_Update ? "r+DC" : "rDOC";
20✔
4633
    VSILFILE *l_fpL = VSIFOpenL(pszFilename, pszFlag);
20✔
4634
    if (l_fpL == nullptr)
20✔
4635
        return nullptr;
×
4636
    TIFF *l_hTIFF = VSI_TIFFOpen(pszFilename, pszFlag, l_fpL);
20✔
4637
    if (l_hTIFF == nullptr)
20✔
4638
    {
4639
        CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
×
4640
        return nullptr;
×
4641
    }
4642

4643
    /* -------------------------------------------------------------------- */
4644
    /*      If a directory was requested by index, advance to it now.       */
4645
    /* -------------------------------------------------------------------- */
4646
    if (!bAbsolute)
20✔
4647
    {
4648
        const toff_t nOffsetRequested = nOffset;
18✔
4649
        while (nOffset > 1)
31✔
4650
        {
4651
            if (TIFFReadDirectory(l_hTIFF) == 0)
13✔
4652
            {
4653
                XTIFFClose(l_hTIFF);
×
4654
                ReportError(pszFilename, CE_Failure, CPLE_OpenFailed,
×
4655
                            "Requested directory %lu not found.",
4656
                            static_cast<long unsigned int>(nOffsetRequested));
4657
                CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
×
4658
                return nullptr;
×
4659
            }
4660
            nOffset--;
13✔
4661
        }
4662

4663
        nOffset = TIFFCurrentDirOffset(l_hTIFF);
18✔
4664
    }
4665

4666
    /* -------------------------------------------------------------------- */
4667
    /*      Create a corresponding GDALDataset.                             */
4668
    /* -------------------------------------------------------------------- */
4669
    GTiffDataset *poDS = new GTiffDataset();
20✔
4670
    poDS->SetDescription(poOpenInfo->pszFilename);
20✔
4671
    poDS->m_pszFilename = CPLStrdup(pszFilename);
20✔
4672
    poDS->m_fpL = l_fpL;
20✔
4673
    poDS->m_hTIFF = l_hTIFF;
20✔
4674
    poDS->m_bSingleIFDOpened = true;
20✔
4675

4676
    if (!EQUAL(pszFilename, poOpenInfo->pszFilename) &&
20✔
4677
        !STARTS_WITH_CI(poOpenInfo->pszFilename, "GTIFF_RAW:"))
20✔
4678
    {
4679
        poDS->SetPhysicalFilename(pszFilename);
19✔
4680
        poDS->SetSubdatasetName(poOpenInfo->pszFilename);
19✔
4681
    }
4682

4683
    if (poOpenInfo->AreSiblingFilesLoaded())
20✔
4684
        poDS->oOvManager.TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
20✔
4685

4686
    if (poDS->OpenOffset(l_hTIFF, nOffset, poOpenInfo->eAccess,
20✔
4687
                         bAllowRGBAInterface, true) != CE_None)
20✔
4688
    {
4689
        delete poDS;
1✔
4690
        return nullptr;
1✔
4691
    }
4692

4693
    return poDS;
19✔
4694
}
4695

4696
/************************************************************************/
4697
/*                   ConvertTransferFunctionToString()                  */
4698
/*                                                                      */
4699
/*      Convert a transfer function table into a string.                */
4700
/*      Used by LoadICCProfile().                                       */
4701
/************************************************************************/
4702
static CPLString ConvertTransferFunctionToString(const uint16_t *pTable,
21✔
4703
                                                 uint32_t nTableEntries)
4704
{
4705
    CPLString sValue;
21✔
4706

4707
    for (uint32_t i = 0; i < nTableEntries; ++i)
5,397✔
4708
    {
4709
        if (i > 0)
5,376✔
4710
            sValue += ", ";
5,355✔
4711
        sValue += CPLSPrintf("%d", static_cast<uint32_t>(pTable[i]));
5,376✔
4712
    }
4713

4714
    return sValue;
21✔
4715
}
4716

4717
/************************************************************************/
4718
/*                             LoadICCProfile()                         */
4719
/*                                                                      */
4720
/*      Load ICC Profile or colorimetric data into metadata             */
4721
/************************************************************************/
4722

4723
void GTiffDataset::LoadICCProfile()
4,757✔
4724
{
4725
    if (m_bICCMetadataLoaded)
4,757✔
4726
        return;
4,300✔
4727
    m_bICCMetadataLoaded = true;
470✔
4728

4729
    uint32_t nEmbedLen = 0;
470✔
4730
    uint8_t *pEmbedBuffer = nullptr;
470✔
4731

4732
    if (TIFFGetField(m_hTIFF, TIFFTAG_ICCPROFILE, &nEmbedLen, &pEmbedBuffer))
470✔
4733
    {
4734
        char *pszBase64Profile = CPLBase64Encode(
12✔
4735
            nEmbedLen, reinterpret_cast<const GByte *>(pEmbedBuffer));
4736

4737
        m_oGTiffMDMD.SetMetadataItem("SOURCE_ICC_PROFILE", pszBase64Profile,
12✔
4738
                                     "COLOR_PROFILE");
4739

4740
        CPLFree(pszBase64Profile);
12✔
4741

4742
        return;
12✔
4743
    }
4744

4745
    // Check for colorimetric tiff.
4746
    float *pCHR = nullptr;
458✔
4747
    float *pWP = nullptr;
458✔
4748
    uint16_t *pTFR = nullptr;
458✔
4749
    uint16_t *pTFG = nullptr;
458✔
4750
    uint16_t *pTFB = nullptr;
458✔
4751
    uint16_t *pTransferRange = nullptr;
458✔
4752

4753
    if (TIFFGetField(m_hTIFF, TIFFTAG_PRIMARYCHROMATICITIES, &pCHR))
458✔
4754
    {
4755
        if (TIFFGetField(m_hTIFF, TIFFTAG_WHITEPOINT, &pWP))
8✔
4756
        {
4757
            if (m_nBitsPerSample > 24 ||
24✔
4758
                !TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERFUNCTION, &pTFR,
8✔
4759
                                       &pTFG, &pTFB) ||
8✔
4760
                pTFR == nullptr || pTFG == nullptr || pTFB == nullptr)
16✔
4761
            {
4762
                return;
1✔
4763
            }
4764

4765
            const int TIFFTAG_TRANSFERRANGE = 0x0156;
7✔
4766
            TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERRANGE,
7✔
4767
                                  &pTransferRange);
4768

4769
            // Set all the colorimetric metadata.
4770
            m_oGTiffMDMD.SetMetadataItem(
7✔
4771
                "SOURCE_PRIMARIES_RED",
4772
                CPLString().Printf("%.9f, %.9f, 1.0",
14✔
4773
                                   static_cast<double>(pCHR[0]),
7✔
4774
                                   static_cast<double>(pCHR[1])),
7✔
4775
                "COLOR_PROFILE");
4776
            m_oGTiffMDMD.SetMetadataItem(
7✔
4777
                "SOURCE_PRIMARIES_GREEN",
4778
                CPLString().Printf("%.9f, %.9f, 1.0",
14✔
4779
                                   static_cast<double>(pCHR[2]),
7✔
4780
                                   static_cast<double>(pCHR[3])),
7✔
4781
                "COLOR_PROFILE");
4782
            m_oGTiffMDMD.SetMetadataItem(
7✔
4783
                "SOURCE_PRIMARIES_BLUE",
4784
                CPLString().Printf("%.9f, %.9f, 1.0",
14✔
4785
                                   static_cast<double>(pCHR[4]),
7✔
4786
                                   static_cast<double>(pCHR[5])),
7✔
4787
                "COLOR_PROFILE");
4788

4789
            m_oGTiffMDMD.SetMetadataItem(
7✔
4790
                "SOURCE_WHITEPOINT",
4791
                CPLString().Printf("%.9f, %.9f, 1.0",
14✔
4792
                                   static_cast<double>(pWP[0]),
7✔
4793
                                   static_cast<double>(pWP[1])),
7✔
4794
                "COLOR_PROFILE");
4795

4796
            // Set transfer function metadata.
4797

4798
            // Get length of table.
4799
            const uint32_t nTransferFunctionLength = 1 << m_nBitsPerSample;
7✔
4800

4801
            m_oGTiffMDMD.SetMetadataItem(
7✔
4802
                "TIFFTAG_TRANSFERFUNCTION_RED",
4803
                ConvertTransferFunctionToString(pTFR, nTransferFunctionLength),
14✔
4804
                "COLOR_PROFILE");
4805

4806
            m_oGTiffMDMD.SetMetadataItem(
7✔
4807
                "TIFFTAG_TRANSFERFUNCTION_GREEN",
4808
                ConvertTransferFunctionToString(pTFG, nTransferFunctionLength),
14✔
4809
                "COLOR_PROFILE");
4810

4811
            m_oGTiffMDMD.SetMetadataItem(
7✔
4812
                "TIFFTAG_TRANSFERFUNCTION_BLUE",
4813
                ConvertTransferFunctionToString(pTFB, nTransferFunctionLength),
14✔
4814
                "COLOR_PROFILE");
4815

4816
            // Set transfer range.
4817
            if (pTransferRange)
7✔
4818
            {
4819
                m_oGTiffMDMD.SetMetadataItem(
×
4820
                    "TIFFTAG_TRANSFERRANGE_BLACK",
4821
                    CPLString().Printf("%d, %d, %d",
×
4822
                                       static_cast<int>(pTransferRange[0]),
×
4823
                                       static_cast<int>(pTransferRange[2]),
×
4824
                                       static_cast<int>(pTransferRange[4])),
×
4825
                    "COLOR_PROFILE");
4826
                m_oGTiffMDMD.SetMetadataItem(
×
4827
                    "TIFFTAG_TRANSFERRANGE_WHITE",
4828
                    CPLString().Printf("%d, %d, %d",
×
4829
                                       static_cast<int>(pTransferRange[1]),
×
4830
                                       static_cast<int>(pTransferRange[3]),
×
4831
                                       static_cast<int>(pTransferRange[5])),
×
4832
                    "COLOR_PROFILE");
4833
            }
4834
        }
4835
    }
4836
}
4837

4838
/************************************************************************/
4839
/*                             OpenOffset()                             */
4840
/*                                                                      */
4841
/*      Initialize the GTiffDataset based on a passed in file           */
4842
/*      handle, and directory offset to utilize.  This is called for    */
4843
/*      full res, and overview pages.                                   */
4844
/************************************************************************/
4845

4846
CPLErr GTiffDataset::OpenOffset(TIFF *hTIFFIn, toff_t nDirOffsetIn,
23,641✔
4847
                                GDALAccess eAccessIn, bool bAllowRGBAInterface,
4848
                                bool bReadGeoTransform)
4849

4850
{
4851
    if (!hTIFFIn)
23,641✔
4852
        return CE_Failure;
×
4853

4854
    eAccess = eAccessIn;
23,641✔
4855

4856
    m_hTIFF = hTIFFIn;
23,641✔
4857

4858
    m_nDirOffset = nDirOffsetIn;
23,641✔
4859

4860
    if (!SetDirectory())
23,641✔
4861
        return CE_Failure;
×
4862

4863
    /* -------------------------------------------------------------------- */
4864
    /*      Capture some information from the file that is of interest.     */
4865
    /* -------------------------------------------------------------------- */
4866
    uint32_t nXSize = 0;
23,375✔
4867
    uint32_t nYSize = 0;
23,375✔
4868
    TIFFGetField(m_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
23,375✔
4869
    TIFFGetField(m_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
23,456✔
4870

4871
    // Unlikely to occur, but could happen on a disk full situation.
4872
    if (nXSize == 0 || nYSize == 0)
23,531✔
4873
        return CE_Failure;
136✔
4874

4875
    if (nXSize > INT_MAX || nYSize > INT_MAX)
23,395✔
4876
    {
4877
        // GDAL only supports signed 32bit dimensions.
4878
        ReportError(CE_Failure, CPLE_NotSupported,
31✔
4879
                    "Too large image size: %u x %u", nXSize, nYSize);
4880
        return CE_Failure;
1✔
4881
    }
4882
    nRasterXSize = nXSize;
23,364✔
4883
    nRasterYSize = nYSize;
23,364✔
4884

4885
    if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLESPERPIXEL, &m_nSamplesPerPixel))
23,364✔
4886
        nBands = 1;
6✔
4887
    else
4888
        nBands = m_nSamplesPerPixel;
23,467✔
4889

4890
    if (!TIFFGetField(m_hTIFF, TIFFTAG_BITSPERSAMPLE, &(m_nBitsPerSample)))
23,473✔
4891
        m_nBitsPerSample = 1;
6✔
4892

4893
    if (!TIFFGetField(m_hTIFF, TIFFTAG_PLANARCONFIG, &(m_nPlanarConfig)))
23,509✔
4894
        m_nPlanarConfig = PLANARCONFIG_CONTIG;
×
4895

4896
    if (!TIFFGetField(m_hTIFF, TIFFTAG_PHOTOMETRIC, &(m_nPhotometric)))
23,485✔
4897
        m_nPhotometric = PHOTOMETRIC_MINISBLACK;
9✔
4898

4899
    if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLEFORMAT, &(m_nSampleFormat)))
23,472✔
4900
        m_nSampleFormat = SAMPLEFORMAT_UINT;
145✔
4901

4902
    if (!TIFFGetField(m_hTIFF, TIFFTAG_COMPRESSION, &(m_nCompression)))
23,442✔
4903
        m_nCompression = COMPRESSION_NONE;
×
4904

4905
    if (m_nCompression != COMPRESSION_NONE &&
26,891✔
4906
        !TIFFIsCODECConfigured(m_nCompression))
3,370✔
4907
    {
4908
        const char *pszCompressionMethodName =
4909
            GTIFFGetCompressionMethodName(m_nCompression);
3✔
4910
        if (pszCompressionMethodName)
3✔
4911
        {
4912
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
4913
                        "Cannot open TIFF file due to missing codec %s.",
4914
                        pszCompressionMethodName);
4915
        }
4916
        else
4917
        {
4918
            ReportError(
2✔
4919
                CE_Failure, CPLE_AppDefined,
4920
                "Cannot open TIFF file due to missing codec of code %d.",
4921
                m_nCompression);
2✔
4922
        }
4923
        return CE_Failure;
3✔
4924
    }
4925

4926
    /* -------------------------------------------------------------------- */
4927
    /*      YCbCr JPEG compressed images should be translated on the fly    */
4928
    /*      to RGB by libtiff/libjpeg unless specifically requested         */
4929
    /*      otherwise.                                                      */
4930
    /* -------------------------------------------------------------------- */
4931
    if (m_nCompression == COMPRESSION_JPEG &&
47,513✔
4932
        m_nPhotometric == PHOTOMETRIC_YCBCR &&
23,783✔
4933
        CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
265✔
4934
    {
4935
        m_oGTiffMDMD.SetMetadataItem("SOURCE_COLOR_SPACE", "YCbCr",
265✔
4936
                                     "IMAGE_STRUCTURE");
4937
        int nColorMode = 0;
265✔
4938
        if (!TIFFGetField(m_hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode) ||
530✔
4939
            nColorMode != JPEGCOLORMODE_RGB)
265✔
4940
        {
4941
            TIFFSetField(m_hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
265✔
4942
        }
4943
    }
4944

4945
    /* -------------------------------------------------------------------- */
4946
    /*      Get strip/tile layout.                                          */
4947
    /* -------------------------------------------------------------------- */
4948
    if (TIFFIsTiled(m_hTIFF))
23,518✔
4949
    {
4950
        uint32_t l_nBlockXSize = 0;
3,589✔
4951
        uint32_t l_nBlockYSize = 0;
3,589✔
4952
        TIFFGetField(m_hTIFF, TIFFTAG_TILEWIDTH, &(l_nBlockXSize));
3,589✔
4953
        TIFFGetField(m_hTIFF, TIFFTAG_TILELENGTH, &(l_nBlockYSize));
3,589✔
4954
        if (l_nBlockXSize > INT_MAX || l_nBlockYSize > INT_MAX)
3,590✔
4955
        {
4956
            ReportError(CE_Failure, CPLE_NotSupported,
2✔
4957
                        "Too large block size: %u x %u", l_nBlockXSize,
4958
                        l_nBlockYSize);
4959
            return CE_Failure;
2✔
4960
        }
4961
        m_nBlockXSize = static_cast<int>(l_nBlockXSize);
3,588✔
4962
        m_nBlockYSize = static_cast<int>(l_nBlockYSize);
3,588✔
4963
    }
4964
    else
4965
    {
4966
        if (!TIFFGetField(m_hTIFF, TIFFTAG_ROWSPERSTRIP, &(m_nRowsPerStrip)))
19,750✔
4967
        {
4968
            ReportError(CE_Warning, CPLE_AppDefined,
5✔
4969
                        "RowsPerStrip not defined ... assuming all one strip.");
4970
            m_nRowsPerStrip = nYSize;  // Dummy value.
5✔
4971
        }
4972

4973
        // If the rows per strip is larger than the file we will get
4974
        // confused.  libtiff internally will treat the rowsperstrip as
4975
        // the image height and it is best if we do too. (#4468)
4976
        if (m_nRowsPerStrip > static_cast<uint32_t>(nRasterYSize))
19,859✔
4977
            m_nRowsPerStrip = nRasterYSize;
24✔
4978

4979
        m_nBlockXSize = nRasterXSize;
19,859✔
4980
        m_nBlockYSize = m_nRowsPerStrip;
19,859✔
4981
    }
4982

4983
    if (!ComputeBlocksPerColRowAndBand(nBands))
23,447✔
4984
        return CE_Failure;
2✔
4985

4986
    /* -------------------------------------------------------------------- */
4987
    /*      Should we handle this using the GTiffBitmapBand?                */
4988
    /* -------------------------------------------------------------------- */
4989
    bool bTreatAsBitmap = false;
23,301✔
4990

4991
    if (m_nBitsPerSample == 1 && nBands == 1)
23,301✔
4992
    {
4993
        bTreatAsBitmap = true;
406✔
4994

4995
        // Lets treat large "one row" bitmaps using the scanline api.
4996
        if (!TIFFIsTiled(m_hTIFF) && m_nBlockYSize == nRasterYSize &&
561✔
4997
            nRasterYSize > 2000
125✔
4998
            // libtiff does not support reading JBIG files with
4999
            // TIFFReadScanline().
5000
            && m_nCompression != COMPRESSION_JBIG)
561✔
5001
        {
5002
            m_bTreatAsSplitBitmap = true;
10✔
5003
        }
5004
    }
5005

5006
    /* -------------------------------------------------------------------- */
5007
    /*      Should we treat this via the RGBA interface?                    */
5008
    /* -------------------------------------------------------------------- */
5009
    bool bTreatAsRGBA = false;
23,301✔
5010
    if (
23,691✔
5011
#ifdef DEBUG
5012
        CPLTestBool(CPLGetConfigOption("GTIFF_FORCE_RGBA", "NO")) ||
45,077✔
5013
#endif
5014
        (bAllowRGBAInterface && !bTreatAsBitmap && !(m_nBitsPerSample > 8) &&
21,776✔
5015
         (m_nPhotometric == PHOTOMETRIC_CIELAB ||
17,889✔
5016
          m_nPhotometric == PHOTOMETRIC_LOGL ||
17,888✔
5017
          m_nPhotometric == PHOTOMETRIC_LOGLUV ||
17,886✔
5018
          m_nPhotometric == PHOTOMETRIC_SEPARATED ||
17,886✔
5019
          (m_nPhotometric == PHOTOMETRIC_YCBCR &&
17,877✔
5020
           m_nCompression != COMPRESSION_JPEG))))
243✔
5021
    {
5022
        char szMessage[1024] = {};
35✔
5023

5024
        if (TIFFRGBAImageOK(m_hTIFF, szMessage) == 1)
35✔
5025
        {
5026
            const char *pszSourceColorSpace = nullptr;
35✔
5027
            nBands = 4;
35✔
5028
            switch (m_nPhotometric)
35✔
5029
            {
5030
                case PHOTOMETRIC_CIELAB:
1✔
5031
                    pszSourceColorSpace = "CIELAB";
1✔
5032
                    break;
1✔
5033
                case PHOTOMETRIC_LOGL:
1✔
5034
                    pszSourceColorSpace = "LOGL";
1✔
5035
                    break;
1✔
5036
                case PHOTOMETRIC_LOGLUV:
×
5037
                    pszSourceColorSpace = "LOGLUV";
×
5038
                    break;
×
5039
                case PHOTOMETRIC_SEPARATED:
10✔
5040
                    pszSourceColorSpace = "CMYK";
10✔
5041
                    break;
10✔
5042
                case PHOTOMETRIC_YCBCR:
13✔
5043
                    pszSourceColorSpace = "YCbCr";
13✔
5044
                    nBands = 3;  // probably true for other photometric values
13✔
5045
                    break;
13✔
5046
            }
5047
            if (pszSourceColorSpace)
35✔
5048
                m_oGTiffMDMD.SetMetadataItem("SOURCE_COLOR_SPACE",
25✔
5049
                                             pszSourceColorSpace,
5050
                                             "IMAGE_STRUCTURE");
5051
            bTreatAsRGBA = true;
35✔
5052
        }
5053
        else
5054
        {
5055
            CPLDebug("GTiff", "TIFFRGBAImageOK says:\n%s", szMessage);
×
5056
        }
5057
    }
5058

5059
    // libtiff has various issues with OJPEG compression and chunky-strip
5060
    // support with the "classic" scanline/strip/tile interfaces, and that
5061
    // wouldn't work either, so better bail out.
5062
    if (m_nCompression == COMPRESSION_OJPEG && !bTreatAsRGBA)
23,691✔
5063
    {
5064
        ReportError(
×
5065
            CE_Failure, CPLE_NotSupported,
5066
            "Old-JPEG compression only supported through RGBA interface, "
5067
            "which cannot be used probably because the file is corrupted");
5068
        return CE_Failure;
×
5069
    }
5070

5071
    // If photometric is YCbCr, scanline/strip/tile interfaces assumes that
5072
    // we are ready with downsampled data. And we are not.
5073
    if (m_nCompression != COMPRESSION_JPEG &&
23,691✔
5074
        m_nCompression != COMPRESSION_OJPEG &&
23,213✔
5075
        m_nPhotometric == PHOTOMETRIC_YCBCR &&
23,210✔
5076
        m_nPlanarConfig == PLANARCONFIG_CONTIG && !bTreatAsRGBA)
12✔
5077
    {
5078
        uint16_t nF1, nF2;
5079
        TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nF1, &nF2);
1✔
5080
        if (nF1 != 1 || nF2 != 1)
1✔
5081
        {
5082
            ReportError(CE_Failure, CPLE_AppDefined,
1✔
5083
                        "Cannot open TIFF file with YCbCr, subsampling and "
5084
                        "BitsPerSample > 8 that is not JPEG compressed");
5085
            return CE_Failure;
1✔
5086
        }
5087
    }
5088

5089
    /* -------------------------------------------------------------------- */
5090
    /*      Should we treat this via the split interface?                   */
5091
    /* -------------------------------------------------------------------- */
5092
    if (!TIFFIsTiled(m_hTIFF) && m_nBitsPerSample == 8 &&
43,790✔
5093
        m_nBlockYSize == nRasterYSize && nRasterYSize > 2000 && !bTreatAsRGBA &&
43,809✔
5094
        CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
24✔
5095
    {
5096
        m_bTreatAsSplit = true;
24✔
5097
    }
5098

5099
    /* -------------------------------------------------------------------- */
5100
    /*      Should we treat this via the odd bits interface?                */
5101
    /* -------------------------------------------------------------------- */
5102
    bool bTreatAsOdd = false;
23,685✔
5103
    if (m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
23,685✔
5104
    {
5105
        if (m_nBitsPerSample == 16 || m_nBitsPerSample == 24)
1,217✔
5106
            bTreatAsOdd = true;
18✔
5107
        else if (m_nBitsPerSample != 32 && m_nBitsPerSample != 64)
1,199✔
5108
        {
5109
            ReportError(CE_Failure, CPLE_AppDefined,
×
5110
                        "Cannot open TIFF file with SampleFormat=IEEEFP "
5111
                        "and BitsPerSample=%d",
5112
                        m_nBitsPerSample);
×
5113
            return CE_Failure;
×
5114
        }
5115
    }
5116
    else if (!bTreatAsRGBA && !bTreatAsBitmap && m_nBitsPerSample != 8 &&
22,468✔
5117
             m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
2,655✔
5118
             m_nBitsPerSample != 64 && m_nBitsPerSample != 128)
775✔
5119
    {
5120
        bTreatAsOdd = true;
203✔
5121
    }
5122

5123
/* -------------------------------------------------------------------- */
5124
/*      We can't support 'chunks' bigger than 2GB on 32 bit builds      */
5125
/* -------------------------------------------------------------------- */
5126
#if SIZEOF_VOIDP == 4
5127
    uint64_t nChunkSize = 0;
5128
    if (m_bTreatAsSplit || m_bTreatAsSplitBitmap)
5129
    {
5130
        nChunkSize = TIFFScanlineSize64(m_hTIFF);
5131
    }
5132
    else
5133
    {
5134
        if (TIFFIsTiled(m_hTIFF))
5135
            nChunkSize = TIFFTileSize64(m_hTIFF);
5136
        else
5137
            nChunkSize = TIFFStripSize64(m_hTIFF);
5138
    }
5139
    if (bTreatAsRGBA)
5140
    {
5141
        nChunkSize =
5142
            std::max(nChunkSize,
5143
                     4 * static_cast<uint64_t>(m_nBlockXSize) * m_nBlockYSize);
5144
    }
5145
    if (nChunkSize > static_cast<uint64_t>(INT_MAX))
5146
    {
5147
        ReportError(CE_Failure, CPLE_NotSupported,
5148
                    "Scanline/tile/strip size bigger than 2GB unsupported "
5149
                    "on 32-bit builds.");
5150
        return CE_Failure;
5151
    }
5152
#endif
5153

5154
    const bool bMinIsWhite = m_nPhotometric == PHOTOMETRIC_MINISWHITE;
23,685✔
5155

5156
    /* -------------------------------------------------------------------- */
5157
    /*      Check for NODATA                                                */
5158
    /* -------------------------------------------------------------------- */
5159
    char *pszText = nullptr;
23,685✔
5160
    if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_NODATA, &pszText) &&
24,738✔
5161
        !EQUAL(pszText, ""))
1,053✔
5162
    {
5163
        if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
1,052✔
5164
            m_nSampleFormat == SAMPLEFORMAT_INT)
95✔
5165
        {
5166
            m_bNoDataSetAsInt64 = true;
5✔
5167
            m_nNoDataValueInt64 =
5✔
5168
                static_cast<int64_t>(std::strtoll(pszText, nullptr, 10));
5✔
5169
        }
5170
        else if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
1,047✔
5171
                 m_nSampleFormat == SAMPLEFORMAT_UINT)
90✔
5172
        {
5173
            m_bNoDataSetAsUInt64 = true;
5✔
5174
            m_nNoDataValueUInt64 =
5✔
5175
                static_cast<uint64_t>(std::strtoull(pszText, nullptr, 10));
5✔
5176
        }
5177
        else
5178
        {
5179
            m_bNoDataSet = true;
1,042✔
5180
            m_dfNoDataValue = CPLAtofM(pszText);
1,042✔
5181
            if (m_nBitsPerSample == 32 &&
1,042✔
5182
                m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
157✔
5183
            {
5184
                m_dfNoDataValue =
116✔
5185
                    GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
116✔
5186
                m_dfNoDataValue = static_cast<float>(m_dfNoDataValue);
116✔
5187
            }
5188
        }
5189
    }
5190

5191
    /* -------------------------------------------------------------------- */
5192
    /*      Capture the color table if there is one.                        */
5193
    /* -------------------------------------------------------------------- */
5194
    unsigned short *panRed = nullptr;
23,687✔
5195
    unsigned short *panGreen = nullptr;
23,687✔
5196
    unsigned short *panBlue = nullptr;
23,687✔
5197

5198
    if (bTreatAsRGBA || m_nBitsPerSample > 16 ||
44,716✔
5199
        TIFFGetField(m_hTIFF, TIFFTAG_COLORMAP, &panRed, &panGreen, &panBlue) ==
21,048✔
5200
            0)
5201
    {
5202
        // Build inverted palette if we have inverted photometric.
5203
        // Pixel values remains unchanged.  Avoid doing this for *deep*
5204
        // data types (per #1882)
5205
        if (m_nBitsPerSample <= 16 && m_nPhotometric == PHOTOMETRIC_MINISWHITE)
23,476✔
5206
        {
5207
            m_poColorTable = std::make_unique<GDALColorTable>();
13✔
5208
            const int nColorCount = 1 << m_nBitsPerSample;
13✔
5209

5210
            for (int iColor = 0; iColor < nColorCount; ++iColor)
39✔
5211
            {
5212
                const short nValue = static_cast<short>(
26✔
5213
                    ((255 * (nColorCount - 1 - iColor)) / (nColorCount - 1)));
26✔
5214
                const GDALColorEntry oEntry = {nValue, nValue, nValue,
26✔
5215
                                               static_cast<short>(255)};
26✔
5216
                m_poColorTable->SetColorEntry(iColor, &oEntry);
26✔
5217
            }
5218

5219
            m_nPhotometric = PHOTOMETRIC_PALETTE;
13✔
5220
        }
5221
        else
5222
        {
5223
            m_poColorTable.reset();
23,463✔
5224
        }
5225
    }
5226
    else
5227
    {
5228
        const int nColorCount = 1 << m_nBitsPerSample;
192✔
5229
        m_poColorTable = gdal::tiff_common::TIFFColorMapTagToColorTable(
144✔
5230
            panRed, panGreen, panBlue, nColorCount, m_nColorTableMultiplier,
192✔
5231
            DEFAULT_COLOR_TABLE_MULTIPLIER_257, m_bNoDataSet, m_dfNoDataValue);
192✔
5232
    }
5233

5234
    /* -------------------------------------------------------------------- */
5235
    /*      Create band information objects.                                */
5236
    /* -------------------------------------------------------------------- */
5237
    for (int iBand = 0; iBand < nBands; ++iBand)
518,336✔
5238
    {
5239
        if (bTreatAsRGBA)
495,069✔
5240
            SetBand(iBand + 1, new GTiffRGBABand(this, iBand + 1));
127✔
5241
        else if (m_bTreatAsSplitBitmap)
494,942✔
5242
            SetBand(iBand + 1, new GTiffSplitBitmapBand(this, iBand + 1));
10✔
5243
        else if (m_bTreatAsSplit)
494,932✔
5244
            SetBand(iBand + 1, new GTiffSplitBand(this, iBand + 1));
131,118✔
5245
        else if (bTreatAsBitmap)
363,814✔
5246
            SetBand(iBand + 1, new GTiffBitmapBand(this, iBand + 1));
396✔
5247
        else if (bTreatAsOdd)
363,418✔
5248
            SetBand(iBand + 1, new GTiffOddBitsBand(this, iBand + 1));
368✔
5249
        else
5250
            SetBand(iBand + 1, new GTiffRasterBand(this, iBand + 1));
363,050✔
5251
    }
5252

5253
    if (GetRasterBand(1)->GetRasterDataType() == GDT_Unknown)
23,267✔
5254
    {
5255
        ReportError(CE_Failure, CPLE_NotSupported,
1✔
5256
                    "Unsupported TIFF configuration: BitsPerSample(=%d) and "
5257
                    "SampleType(=%d)",
5258
                    m_nBitsPerSample, m_nSampleFormat);
1✔
5259
        return CE_Failure;
1✔
5260
    }
5261

5262
    m_bReadGeoTransform = bReadGeoTransform;
23,364✔
5263

5264
    /* -------------------------------------------------------------------- */
5265
    /*      Capture some other potentially interesting information.         */
5266
    /* -------------------------------------------------------------------- */
5267
    char szWorkMDI[200] = {};
23,364✔
5268
    uint16_t nShort = 0;
23,364✔
5269

5270
    const auto *pasTIFFTags = GetTIFFTags();
23,364✔
5271
    for (size_t iTag = 0; pasTIFFTags[iTag].pszTagName; ++iTag)
354,122✔
5272
    {
5273
        if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_STRING)
330,497✔
5274
        {
5275
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &pszText))
188,749✔
5276
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
129✔
5277
                                             pszText);
5278
        }
5279
        else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_FLOAT)
141,748✔
5280
        {
5281
            float fVal = 0.0;
47,125✔
5282
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &fVal))
47,125✔
5283
            {
5284
                CPLsnprintf(szWorkMDI, sizeof(szWorkMDI), "%.8g", fVal);
172✔
5285
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
172✔
5286
                                             szWorkMDI);
5287
            }
5288
        }
5289
        else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_SHORT &&
94,623✔
5290
                 pasTIFFTags[iTag].nTagVal != TIFFTAG_RESOLUTIONUNIT)
70,731✔
5291
        {
5292
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nShort))
46,967✔
5293
            {
5294
                snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
8✔
5295
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
8✔
5296
                                             szWorkMDI);
5297
            }
5298
        }
5299
        else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_BYTE_STRING)
47,656✔
5300
        {
5301
            uint32_t nCount = 0;
23,604✔
5302
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nCount,
23,604✔
5303
                             &pszText))
23,620✔
5304
            {
5305
                std::string osStr;
2✔
5306
                osStr.assign(pszText, nCount);
1✔
5307
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
1✔
5308
                                             osStr.c_str());
5309
            }
5310
        }
5311
    }
5312

5313
    if (TIFFGetField(m_hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort))
23,625✔
5314
    {
5315
        if (nShort == RESUNIT_NONE)
88✔
5316
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (unitless)", nShort);
34✔
5317
        else if (nShort == RESUNIT_INCH)
54✔
5318
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/inch)", nShort);
53✔
5319
        else if (nShort == RESUNIT_CENTIMETER)
1✔
5320
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/cm)", nShort);
1✔
5321
        else
5322
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
×
5323
        m_oGTiffMDMD.SetMetadataItem("TIFFTAG_RESOLUTIONUNIT", szWorkMDI);
88✔
5324
    }
5325

5326
    int nTagSize = 0;
23,628✔
5327
    void *pData = nullptr;
23,628✔
5328
    if (TIFFGetField(m_hTIFF, TIFFTAG_XMLPACKET, &nTagSize, &pData))
23,628✔
5329
    {
5330
        char *pszXMP = static_cast<char *>(VSI_MALLOC_VERBOSE(nTagSize + 1));
35✔
5331
        if (pszXMP)
35✔
5332
        {
5333
            memcpy(pszXMP, pData, nTagSize);
35✔
5334
            pszXMP[nTagSize] = '\0';
35✔
5335

5336
            char *apszMDList[2] = {pszXMP, nullptr};
35✔
5337
            m_oGTiffMDMD.SetMetadata(apszMDList, "xml:XMP");
35✔
5338

5339
            CPLFree(pszXMP);
35✔
5340
        }
5341
    }
5342

5343
    if (m_nCompression != COMPRESSION_NONE)
23,631✔
5344
    {
5345
        const char *pszCompressionMethodName =
5346
            GTIFFGetCompressionMethodName(m_nCompression);
3,368✔
5347
        if (pszCompressionMethodName)
3,367✔
5348
        {
5349
            m_oGTiffMDMD.SetMetadataItem(
3,367✔
5350
                "COMPRESSION", pszCompressionMethodName, "IMAGE_STRUCTURE");
5351
        }
5352
        else
5353
        {
5354
            CPLString oComp;
×
5355
            oComp.Printf("%d", m_nCompression);
×
5356
            m_oGTiffMDMD.SetMetadataItem("COMPRESSION", oComp.c_str());
×
5357
        }
5358
    }
5359

5360
    if (m_nCompression == COMPRESSION_JPEG &&
23,630✔
5361
        m_nPhotometric == PHOTOMETRIC_YCBCR)
477✔
5362
    {
5363
        m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "YCbCr JPEG",
265✔
5364
                                     "IMAGE_STRUCTURE");
5365
    }
5366
    else if (m_nCompression == COMPRESSION_LERC)
23,365✔
5367
    {
5368
        uint32_t nLercParamCount = 0;
317✔
5369
        uint32_t *panLercParams = nullptr;
317✔
5370
        if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_PARAMETERS, &nLercParamCount,
317✔
5371
                         &panLercParams) &&
634✔
5372
            nLercParamCount == 2)
317✔
5373
        {
5374
            memcpy(m_anLercAddCompressionAndVersion, panLercParams,
317✔
5375
                   sizeof(m_anLercAddCompressionAndVersion));
5376
        }
5377

5378
        uint32_t nAddVersion = LERC_ADD_COMPRESSION_NONE;
317✔
5379
        if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_ADD_COMPRESSION, &nAddVersion) &&
634✔
5380
            nAddVersion != LERC_ADD_COMPRESSION_NONE)
317✔
5381
        {
5382
            if (nAddVersion == LERC_ADD_COMPRESSION_DEFLATE)
173✔
5383
            {
5384
                m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "LERC_DEFLATE",
90✔
5385
                                             "IMAGE_STRUCTURE");
5386
            }
5387
            else if (nAddVersion == LERC_ADD_COMPRESSION_ZSTD)
83✔
5388
            {
5389
                m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "LERC_ZSTD",
83✔
5390
                                             "IMAGE_STRUCTURE");
5391
            }
5392
        }
5393
        uint32_t nLercVersion = LERC_VERSION_2_4;
317✔
5394
        if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_VERSION, &nLercVersion))
317✔
5395
        {
5396
            if (nLercVersion == LERC_VERSION_2_4)
317✔
5397
            {
5398
                m_oGTiffMDMD.SetMetadataItem("LERC_VERSION", "2.4",
317✔
5399
                                             "IMAGE_STRUCTURE");
5400
            }
5401
            else
5402
            {
5403
                ReportError(CE_Warning, CPLE_AppDefined,
×
5404
                            "Unknown Lerc version: %d", nLercVersion);
5405
            }
5406
        }
5407
    }
5408

5409
    if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1)
23,630✔
5410
        m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
4,737✔
5411
    else
5412
        m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
18,893✔
5413

5414
    if ((GetRasterBand(1)->GetRasterDataType() == GDT_Byte &&
23,618✔
5415
         m_nBitsPerSample != 8) ||
19,471✔
5416
        (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 &&
23,002✔
5417
         m_nBitsPerSample != 16) ||
47,187✔
5418
        ((GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 ||
22,846✔
5419
          GetRasterBand(1)->GetRasterDataType() == GDT_Float32) &&
22,485✔
5420
         m_nBitsPerSample != 32))
1,029✔
5421
    {
5422
        for (int i = 0; i < nBands; ++i)
1,404✔
5423
            cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i + 1))
777✔
5424
                ->m_oGTiffMDMD.SetMetadataItem(
777✔
5425
                    "NBITS",
5426
                    CPLString().Printf("%d",
1,554✔
5427
                                       static_cast<int>(m_nBitsPerSample)),
777✔
5428
                    "IMAGE_STRUCTURE");
5429
    }
5430

5431
    if (bMinIsWhite)
23,268✔
5432
        m_oGTiffMDMD.SetMetadataItem("MINISWHITE", "YES", "IMAGE_STRUCTURE");
15✔
5433

5434
    if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
23,268✔
5435
    {
5436
        CPLXMLNode *psRoot = CPLParseXMLString(pszText);
2,975✔
5437
        const CPLXMLNode *psItem =
5438
            psRoot ? CPLGetXMLNode(psRoot, "=GDALMetadata") : nullptr;
2,976✔
5439
        if (psItem)
2,976✔
5440
            psItem = psItem->psChild;
2,975✔
5441
        bool bMaxZErrorFound = false;
2,976✔
5442
        bool bMaxZErrorOverviewFound = false;
2,976✔
5443
        for (; psItem != nullptr; psItem = psItem->psNext)
14,016✔
5444
        {
5445

5446
            if (psItem->eType != CXT_Element ||
11,040✔
5447
                !EQUAL(psItem->pszValue, "Item"))
11,040✔
5448
                continue;
×
5449

5450
            const char *pszKey = CPLGetXMLValue(psItem, "name", nullptr);
11,041✔
5451
            const char *pszValue = CPLGetXMLValue(psItem, nullptr, nullptr);
11,041✔
5452
            int nBand = atoi(CPLGetXMLValue(psItem, "sample", "-1"));
11,040✔
5453
            if (nBand < -1 || nBand > 65535)
11,041✔
5454
                continue;
1✔
5455
            nBand++;
11,040✔
5456
            const char *pszRole = CPLGetXMLValue(psItem, "role", "");
11,040✔
5457
            const char *pszDomain = CPLGetXMLValue(psItem, "domain", "");
11,040✔
5458

5459
            if (pszKey == nullptr || pszValue == nullptr)
11,041✔
5460
                continue;
146✔
5461
            if (EQUAL(pszDomain, "IMAGE_STRUCTURE"))
10,895✔
5462
            {
5463
                if (EQUAL(pszKey, "INTERLEAVE"))
738✔
5464
                {
5465
                    if (EQUAL(pszValue, "TILE"))
39✔
5466
                    {
5467
                        m_bTileInterleave = true;
17✔
5468
                        m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "TILE",
17✔
5469
                                                     "IMAGE_STRUCTURE");
5470
                    }
5471
                    else
5472
                    {
5473
                        CPLDebug("GTiff",
22✔
5474
                                 "Unhandled INTERLEAVE=%s found in "
5475
                                 "GDAL_METADATA tag",
5476
                                 pszValue);
5477
                    }
5478
                }
5479
                else if (m_nCompression == COMPRESSION_WEBP &&
699✔
5480
                         EQUAL(pszKey, "COMPRESSION_REVERSIBILITY"))
73✔
5481
                {
5482
                    if (EQUAL(pszValue, "LOSSLESS"))
13✔
5483
                        m_bWebPLossless = true;
13✔
5484
                    else if (EQUAL(pszValue, "LOSSY"))
×
5485
                        m_bWebPLossless = false;
×
5486
                }
5487
                else if (m_nCompression == COMPRESSION_WEBP &&
686✔
5488
                         EQUAL(pszKey, "WEBP_LEVEL"))
60✔
5489
                {
5490
                    const int nLevel = atoi(pszValue);
60✔
5491
                    if (nLevel >= 1 && nLevel <= 100)
60✔
5492
                    {
5493
                        m_oGTiffMDMD.SetMetadataItem(
60✔
5494
                            "COMPRESSION_REVERSIBILITY", "LOSSY",
5495
                            "IMAGE_STRUCTURE");
5496
                        m_bWebPLossless = false;
60✔
5497
                        m_nWebPLevel = static_cast<signed char>(nLevel);
60✔
5498
                    }
60✔
5499
                }
5500
                else if (m_nCompression == COMPRESSION_LERC &&
626✔
5501
                         EQUAL(pszKey, "MAX_Z_ERROR"))
196✔
5502
                {
5503
                    bMaxZErrorFound = true;
28✔
5504
                    m_dfMaxZError = CPLAtof(pszValue);
28✔
5505
                }
5506
                else if (m_nCompression == COMPRESSION_LERC &&
598✔
5507
                         EQUAL(pszKey, "MAX_Z_ERROR_OVERVIEW"))
168✔
5508
                {
5509
                    bMaxZErrorOverviewFound = true;
4✔
5510
                    m_dfMaxZErrorOverview = CPLAtof(pszValue);
4✔
5511
                }
5512
#if HAVE_JXL
5513
                else if ((m_nCompression == COMPRESSION_JXL ||
594✔
5514
                          m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
592✔
5515
                         EQUAL(pszKey, "COMPRESSION_REVERSIBILITY"))
414✔
5516
                {
5517
                    if (EQUAL(pszValue, "LOSSLESS"))
167✔
5518
                        m_bJXLLossless = true;
167✔
5519
                    else if (EQUAL(pszValue, "LOSSY"))
×
5520
                        m_bJXLLossless = false;
×
5521
                }
5522
                else if ((m_nCompression == COMPRESSION_JXL ||
427✔
5523
                          m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
426✔
5524
                         EQUAL(pszKey, "JXL_DISTANCE"))
247✔
5525
                {
5526
                    const double dfVal = CPLAtof(pszValue);
38✔
5527
                    if (dfVal > 0 && dfVal <= 15)
38✔
5528
                    {
5529
                        m_oGTiffMDMD.SetMetadataItem(
38✔
5530
                            "COMPRESSION_REVERSIBILITY", "LOSSY",
5531
                            "IMAGE_STRUCTURE");
5532
                        m_bJXLLossless = false;
38✔
5533
                        m_fJXLDistance = static_cast<float>(dfVal);
38✔
5534
                    }
38✔
5535
                }
5536
                else if ((m_nCompression == COMPRESSION_JXL ||
389✔
5537
                          m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
388✔
5538
                         EQUAL(pszKey, "JXL_ALPHA_DISTANCE"))
209✔
5539
                {
5540
                    const double dfVal = CPLAtof(pszValue);
4✔
5541
                    if (dfVal > 0 && dfVal <= 15)
4✔
5542
                    {
5543
                        m_oGTiffMDMD.SetMetadataItem(
×
5544
                            "COMPRESSION_REVERSIBILITY", "LOSSY",
5545
                            "IMAGE_STRUCTURE");
5546
                        m_fJXLAlphaDistance = static_cast<float>(dfVal);
×
5547
                    }
4✔
5548
                }
5549
                else if ((m_nCompression == COMPRESSION_JXL ||
385✔
5550
                          m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
384✔
5551
                         EQUAL(pszKey, "JXL_EFFORT"))
205✔
5552
                {
5553
                    const int nEffort = atoi(pszValue);
205✔
5554
                    if (nEffort >= 1 && nEffort <= 9)
205✔
5555
                    {
5556
                        m_nJXLEffort = nEffort;
205✔
5557
                    }
205✔
5558
                }
5559
#endif
5560
                else
5561
                {
5562
                    continue;
180✔
5563
                }
5564
            }
5565

5566
            bool bIsXML = false;
10,715✔
5567

5568
            if (STARTS_WITH_CI(pszDomain, "xml:"))
10,715✔
5569
                bIsXML = TRUE;
3✔
5570

5571
            // Note: this un-escaping should not normally be done, as the
5572
            // deserialization of the tree from XML also does it, so we end up
5573
            // width double XML escaping, but keep it for backward
5574
            // compatibility.
5575
            char *pszUnescapedValue =
5576
                CPLUnescapeString(pszValue, nullptr, CPLES_XML);
10,715✔
5577
            if (nBand == 0)
10,715✔
5578
            {
5579
                if (bIsXML)
7,280✔
5580
                {
5581
                    char *apszMD[2] = {pszUnescapedValue, nullptr};
3✔
5582
                    m_oGTiffMDMD.SetMetadata(apszMD, pszDomain);
3✔
5583
                }
5584
                else
5585
                {
5586
                    m_oGTiffMDMD.SetMetadataItem(pszKey, pszUnescapedValue,
7,277✔
5587
                                                 pszDomain);
5588
                }
5589
            }
5590
            else
5591
            {
5592
                GTiffRasterBand *poBand =
5593
                    cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
3,435✔
5594
                if (poBand != nullptr)
3,434✔
5595
                {
5596
                    if (EQUAL(pszRole, "scale"))
3,434✔
5597
                    {
5598
                        poBand->m_bHaveOffsetScale = true;
40✔
5599
                        poBand->m_dfScale = CPLAtofM(pszUnescapedValue);
40✔
5600
                    }
5601
                    else if (EQUAL(pszRole, "offset"))
3,394✔
5602
                    {
5603
                        poBand->m_bHaveOffsetScale = true;
40✔
5604
                        poBand->m_dfOffset = CPLAtofM(pszUnescapedValue);
40✔
5605
                    }
5606
                    else if (EQUAL(pszRole, "unittype"))
3,354✔
5607
                    {
5608
                        poBand->m_osUnitType = pszUnescapedValue;
159✔
5609
                    }
5610
                    else if (EQUAL(pszRole, "description"))
3,195✔
5611
                    {
5612
                        poBand->m_osDescription = pszUnescapedValue;
41✔
5613
                    }
5614
                    else if (EQUAL(pszRole, "colorinterp"))
3,154✔
5615
                    {
5616
                        if (EQUAL(pszUnescapedValue, "undefined"))
596✔
5617
                            poBand->m_eBandInterp = GCI_Undefined;
185✔
5618
                        else
5619
                        {
5620
                            poBand->m_eBandInterp =
411✔
5621
                                GDALGetColorInterpretationByName(
411✔
5622
                                    pszUnescapedValue);
5623
                            if (poBand->m_eBandInterp == GCI_Undefined)
411✔
5624
                            {
5625
                                poBand->m_oGTiffMDMD.SetMetadataItem(
1✔
5626
                                    "COLOR_INTERPRETATION", pszUnescapedValue);
5627
                            }
5628
                        }
5629
                    }
5630
                    else
5631
                    {
5632
                        if (bIsXML)
2,558✔
5633
                        {
5634
                            char *apszMD[2] = {pszUnescapedValue, nullptr};
×
5635
                            poBand->m_oGTiffMDMD.SetMetadata(apszMD, pszDomain);
×
5636
                        }
5637
                        else
5638
                        {
5639
                            poBand->m_oGTiffMDMD.SetMetadataItem(
2,558✔
5640
                                pszKey, pszUnescapedValue, pszDomain);
5641
                        }
5642
                    }
5643
                }
5644
            }
5645
            CPLFree(pszUnescapedValue);
10,715✔
5646
        }
5647

5648
        if (bMaxZErrorFound && !bMaxZErrorOverviewFound)
2,976✔
5649
        {
5650
            m_dfMaxZErrorOverview = m_dfMaxZError;
27✔
5651
        }
5652

5653
        CPLDestroyXMLNode(psRoot);
2,976✔
5654
    }
5655

5656
    if (m_bStreamingIn)
23,505✔
5657
    {
5658
        toff_t *panOffsets = nullptr;
7✔
5659
        TIFFGetField(m_hTIFF,
7✔
5660
                     TIFFIsTiled(m_hTIFF) ? TIFFTAG_TILEOFFSETS
7✔
5661
                                          : TIFFTAG_STRIPOFFSETS,
5662
                     &panOffsets);
5663
        if (panOffsets)
7✔
5664
        {
5665
            int nBlockCount = TIFFIsTiled(m_hTIFF)
7✔
5666
                                  ? TIFFNumberOfTiles(m_hTIFF)
7✔
5667
                                  : TIFFNumberOfStrips(m_hTIFF);
6✔
5668
            for (int i = 1; i < nBlockCount; ++i)
1,437✔
5669
            {
5670
                if (panOffsets[i] < panOffsets[i - 1])
1,431✔
5671
                {
5672
                    m_oGTiffMDMD.SetMetadataItem("UNORDERED_BLOCKS", "YES",
1✔
5673
                                                 "TIFF");
5674
                    CPLDebug("GTIFF",
1✔
5675
                             "Offset of block %d is lower than previous block. "
5676
                             "Reader must be careful",
5677
                             i);
5678
                    break;
1✔
5679
                }
5680
            }
5681
        }
5682
    }
5683

5684
    if (m_nCompression == COMPRESSION_JPEG)
23,505✔
5685
    {
5686
        bool bHasQuantizationTable = false;
477✔
5687
        bool bHasHuffmanTable = false;
477✔
5688
        int nQuality =
5689
            GuessJPEGQuality(bHasQuantizationTable, bHasHuffmanTable);
477✔
5690
        if (nQuality > 0)
477✔
5691
        {
5692
            m_oGTiffMDMD.SetMetadataItem(
453✔
5693
                "JPEG_QUALITY", CPLSPrintf("%d", nQuality), "IMAGE_STRUCTURE");
5694
            int nJpegTablesMode = JPEGTABLESMODE_QUANT;
453✔
5695
            if (bHasHuffmanTable)
453✔
5696
            {
5697
                nJpegTablesMode |= JPEGTABLESMODE_HUFF;
91✔
5698
            }
5699
            m_oGTiffMDMD.SetMetadataItem("JPEGTABLESMODE",
453✔
5700
                                         CPLSPrintf("%d", nJpegTablesMode),
5701
                                         "IMAGE_STRUCTURE");
5702
        }
5703
        if (eAccess == GA_Update)
477✔
5704
        {
5705
            SetJPEGQualityAndTablesModeFromFile(nQuality, bHasQuantizationTable,
165✔
5706
                                                bHasHuffmanTable);
5707
        }
5708
    }
5709
    else if (eAccess == GA_Update &&
26,348✔
5710
             m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
3,320✔
5711
                                          "IMAGE_STRUCTURE") == nullptr)
5712
    {
5713
        if (m_nCompression == COMPRESSION_WEBP)
3,216✔
5714
        {
5715
            const char *pszReversibility =
5716
                GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
37✔
5717
            if (pszReversibility && strstr(pszReversibility, "LOSSLESS"))
37✔
5718
            {
5719
                m_bWebPLossless = true;
2✔
5720
            }
5721
            else if (pszReversibility && strstr(pszReversibility, "LOSSY"))
35✔
5722
            {
5723
                m_bWebPLossless = false;
8✔
5724
            }
5725
        }
5726
#ifdef HAVE_JXL
5727
        else if (m_nCompression == COMPRESSION_JXL ||
3,179✔
5728
                 m_nCompression == COMPRESSION_JXL_DNG_1_7)
3,179✔
5729
        {
5730
            const char *pszReversibility =
5731
                GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
16✔
5732
            if (pszReversibility && strstr(pszReversibility, "LOSSLESS"))
16✔
5733
            {
5734
                m_bJXLLossless = true;
2✔
5735
            }
5736
            else if (pszReversibility && strstr(pszReversibility, "LOSSY"))
14✔
5737
            {
5738
                m_bJXLLossless = false;
6✔
5739
            }
5740
        }
5741
#endif
5742
    }
5743

5744
    if (GTIFFSupportsPredictor(m_nCompression))
23,505✔
5745
    {
5746
        uint16_t nPredictor = 0;
1,817✔
5747
        if (TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &nPredictor) &&
3,601✔
5748
            nPredictor > 1)
1,784✔
5749
        {
5750
            m_oGTiffMDMD.SetMetadataItem(
91✔
5751
                "PREDICTOR", CPLSPrintf("%d", nPredictor), "IMAGE_STRUCTURE");
5752
        }
5753
    }
5754

5755
    CPLAssert(m_bReadGeoTransform == bReadGeoTransform);
23,582✔
5756
    CPLAssert(!m_bMetadataChanged);
23,582✔
5757
    m_bMetadataChanged = false;
23,582✔
5758

5759
    return CE_None;
23,582✔
5760
}
5761

5762
/************************************************************************/
5763
/*                         GetSiblingFiles()                            */
5764
/************************************************************************/
5765

5766
CSLConstList GTiffDataset::GetSiblingFiles()
31,816✔
5767
{
5768
    if (m_bHasGotSiblingFiles)
31,816✔
5769
    {
5770
        return oOvManager.GetSiblingFiles();
18,369✔
5771
    }
5772
    if (m_poBaseDS)
13,447✔
5773
    {
5774
        return m_poBaseDS->GetSiblingFiles();
77✔
5775
    }
5776

5777
    m_bHasGotSiblingFiles = true;
13,370✔
5778
    const int nMaxFiles =
5779
        atoi(CPLGetConfigOption("GDAL_READDIR_LIMIT_ON_OPEN", "1000"));
13,370✔
5780
    const std::string osDirname = CPLGetDirnameSafe(m_pszFilename);
26,739✔
5781
    CPLStringList aosSiblingFiles(VSIReadDirEx(osDirname.c_str(), nMaxFiles));
26,738✔
5782
    if (nMaxFiles > 0 && aosSiblingFiles.size() > nMaxFiles)
13,369✔
5783
    {
5784
        CPLDebug("GTiff", "GDAL_READDIR_LIMIT_ON_OPEN reached on %s",
1✔
5785
                 osDirname.c_str());
5786
        aosSiblingFiles.clear();
1✔
5787
    }
5788
    oOvManager.TransferSiblingFiles(aosSiblingFiles.StealList());
13,369✔
5789

5790
    return oOvManager.GetSiblingFiles();
13,369✔
5791
}
5792

5793
/************************************************************************/
5794
/*                   IdentifyAuthorizedGeoreferencingSources()          */
5795
/************************************************************************/
5796

5797
void GTiffDataset::IdentifyAuthorizedGeoreferencingSources()
22,864✔
5798
{
5799
    if (m_bHasIdentifiedAuthorizedGeoreferencingSources)
22,864✔
5800
        return;
9,573✔
5801
    m_bHasIdentifiedAuthorizedGeoreferencingSources = true;
13,291✔
5802
    CPLString osGeorefSources = CSLFetchNameValueDef(
5803
        papszOpenOptions, "GEOREF_SOURCES",
13,291✔
5804
        CPLGetConfigOption("GDAL_GEOREF_SOURCES",
5805
                           "PAM,INTERNAL,TABFILE,WORLDFILE,XML"));
26,582✔
5806
    char **papszTokens = CSLTokenizeString2(osGeorefSources, ",", 0);
13,291✔
5807
    m_nPAMGeorefSrcIndex =
13,290✔
5808
        static_cast<signed char>(CSLFindString(papszTokens, "PAM"));
13,290✔
5809
    m_nINTERNALGeorefSrcIndex =
13,288✔
5810
        static_cast<signed char>(CSLFindString(papszTokens, "INTERNAL"));
13,290✔
5811
    m_nTABFILEGeorefSrcIndex =
13,288✔
5812
        static_cast<signed char>(CSLFindString(papszTokens, "TABFILE"));
13,288✔
5813
    m_nWORLDFILEGeorefSrcIndex =
13,291✔
5814
        static_cast<signed char>(CSLFindString(papszTokens, "WORLDFILE"));
13,288✔
5815
    m_nXMLGeorefSrcIndex =
13,289✔
5816
        static_cast<signed char>(CSLFindString(papszTokens, "XML"));
13,291✔
5817
    CSLDestroy(papszTokens);
13,289✔
5818
}
5819

5820
/************************************************************************/
5821
/*                     LoadGeoreferencingAndPamIfNeeded()               */
5822
/************************************************************************/
5823

5824
void GTiffDataset::LoadGeoreferencingAndPamIfNeeded()
2,268,530✔
5825

5826
{
5827
    if (!m_bReadGeoTransform && !m_bLoadPam)
2,268,530✔
5828
        return;
2,253,660✔
5829

5830
    IdentifyAuthorizedGeoreferencingSources();
14,872✔
5831

5832
    /* -------------------------------------------------------------------- */
5833
    /*      Get the transform or gcps from the GeoTIFF file.                */
5834
    /* -------------------------------------------------------------------- */
5835
    if (m_bReadGeoTransform)
13,258✔
5836
    {
5837
        m_bReadGeoTransform = false;
13,258✔
5838

5839
        char *pszTabWKT = nullptr;
13,258✔
5840
        double *padfTiePoints = nullptr;
13,258✔
5841
        double *padfScale = nullptr;
13,258✔
5842
        double *padfMatrix = nullptr;
13,258✔
5843
        uint16_t nCount = 0;
13,258✔
5844
        bool bPixelIsPoint = false;
13,258✔
5845
        unsigned short nRasterType = 0;
13,258✔
5846
        bool bPointGeoIgnore = false;
13,258✔
5847

5848
        std::set<signed char> aoSetPriorities;
26,518✔
5849
        if (m_nINTERNALGeorefSrcIndex >= 0)
13,258✔
5850
            aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
13,231✔
5851
        if (m_nTABFILEGeorefSrcIndex >= 0)
13,260✔
5852
            aoSetPriorities.insert(m_nTABFILEGeorefSrcIndex);
13,205✔
5853
        if (m_nWORLDFILEGeorefSrcIndex >= 0)
13,262✔
5854
            aoSetPriorities.insert(m_nWORLDFILEGeorefSrcIndex);
13,223✔
5855
        for (const auto nIndex : aoSetPriorities)
24,174✔
5856
        {
5857
            if (m_nINTERNALGeorefSrcIndex == nIndex)
20,523✔
5858
            {
5859
                GTIF *psGTIF =
5860
                    GTiffDataset::GTIFNew(m_hTIFF);  // How expensive this is?
13,223✔
5861

5862
                if (psGTIF)
13,226✔
5863
                {
5864
                    if (GDALGTIFKeyGetSHORT(psGTIF, GTRasterTypeGeoKey,
13,226✔
5865
                                            &nRasterType, 0, 1) == 1 &&
21,982✔
5866
                        nRasterType == static_cast<short>(RasterPixelIsPoint))
8,756✔
5867
                    {
5868
                        bPixelIsPoint = true;
161✔
5869
                        bPointGeoIgnore = CPLTestBool(CPLGetConfigOption(
161✔
5870
                            "GTIFF_POINT_GEO_IGNORE", "FALSE"));
5871
                    }
5872

5873
                    GTIFFree(psGTIF);
13,226✔
5874
                }
5875

5876
                m_adfGeoTransform[0] = 0.0;
13,226✔
5877
                m_adfGeoTransform[1] = 1.0;
13,226✔
5878
                m_adfGeoTransform[2] = 0.0;
13,226✔
5879
                m_adfGeoTransform[3] = 0.0;
13,226✔
5880
                m_adfGeoTransform[4] = 0.0;
13,226✔
5881
                m_adfGeoTransform[5] = 1.0;
13,226✔
5882

5883
                uint16_t nCountScale = 0;
13,226✔
5884
                if (TIFFGetField(m_hTIFF, TIFFTAG_GEOPIXELSCALE, &nCountScale,
13,226✔
5885
                                 &padfScale) &&
9,448✔
5886
                    nCountScale >= 2 && padfScale[0] != 0.0 &&
22,674✔
5887
                    padfScale[1] != 0.0)
9,448✔
5888
                {
5889
                    m_adfGeoTransform[1] = padfScale[0];
9,448✔
5890
                    if (padfScale[1] < 0)
9,448✔
5891
                    {
5892
                        const char *pszOptionVal = CPLGetConfigOption(
3✔
5893
                            "GTIFF_HONOUR_NEGATIVE_SCALEY", nullptr);
5894
                        if (pszOptionVal == nullptr)
3✔
5895
                        {
5896
                            ReportError(
1✔
5897
                                CE_Warning, CPLE_AppDefined,
5898
                                "File with negative value for ScaleY in "
5899
                                "GeoPixelScale tag. This is rather "
5900
                                "unusual. GDAL, contrary to the GeoTIFF "
5901
                                "specification, assumes that the file "
5902
                                "was intended to be north-up, and will "
5903
                                "treat this file as if ScaleY was "
5904
                                "positive. You may override this behavior "
5905
                                "by setting the GTIFF_HONOUR_NEGATIVE_SCALEY "
5906
                                "configuration option to YES");
5907
                            m_adfGeoTransform[5] = padfScale[1];
1✔
5908
                        }
5909
                        else if (CPLTestBool(pszOptionVal))
2✔
5910
                        {
5911
                            m_adfGeoTransform[5] = -padfScale[1];
1✔
5912
                        }
5913
                        else
5914
                        {
5915
                            m_adfGeoTransform[5] = padfScale[1];
1✔
5916
                        }
5917
                    }
5918
                    else
5919
                    {
5920
                        m_adfGeoTransform[5] = -padfScale[1];
9,445✔
5921
                    }
5922

5923
                    if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
9,448✔
5924
                                     &padfTiePoints) &&
18,896✔
5925
                        nCount >= 6)
9,448✔
5926
                    {
5927
                        m_adfGeoTransform[0] =
9,448✔
5928
                            padfTiePoints[3] -
9,448✔
5929
                            padfTiePoints[0] * m_adfGeoTransform[1];
9,448✔
5930
                        m_adfGeoTransform[3] =
9,448✔
5931
                            padfTiePoints[4] -
9,448✔
5932
                            padfTiePoints[1] * m_adfGeoTransform[5];
9,448✔
5933

5934
                        if (bPixelIsPoint && !bPointGeoIgnore)
9,448✔
5935
                        {
5936
                            m_adfGeoTransform[0] -=
126✔
5937
                                (m_adfGeoTransform[1] * 0.5 +
126✔
5938
                                 m_adfGeoTransform[2] * 0.5);
126✔
5939
                            m_adfGeoTransform[3] -=
126✔
5940
                                (m_adfGeoTransform[4] * 0.5 +
126✔
5941
                                 m_adfGeoTransform[5] * 0.5);
126✔
5942
                        }
5943

5944
                        m_bGeoTransformValid = true;
9,448✔
5945
                        m_nGeoTransformGeorefSrcIndex = nIndex;
9,448✔
5946

5947
                        if (nCountScale >= 3 && GetRasterCount() == 1 &&
15,683✔
5948
                            (padfScale[2] != 0.0 || padfTiePoints[2] != 0.0 ||
6,235✔
5949
                             padfTiePoints[5] != 0.0))
6,209✔
5950
                        {
5951
                            LookForProjection();
28✔
5952
                            if (!m_oSRS.IsEmpty() && m_oSRS.IsVertical())
28✔
5953
                            {
5954
                                /* modelTiePointTag = (pixel, line, z0, X, Y,
5955
                                 * Z0) */
5956
                                /* thus Z(some_point) = (z(some_point) - z0) *
5957
                                 * scaleZ + Z0 */
5958
                                /* equivalently written as */
5959
                                /* Z(some_point) = z(some_point) * scaleZ +
5960
                                 * offsetZ with */
5961
                                /* offsetZ = - z0 * scaleZ + Z0 */
5962
                                double dfScale = padfScale[2];
18✔
5963
                                double dfOffset = -padfTiePoints[2] * dfScale +
18✔
5964
                                                  padfTiePoints[5];
18✔
5965
                                GTiffRasterBand *poBand =
5966
                                    cpl::down_cast<GTiffRasterBand *>(
18✔
5967
                                        GetRasterBand(1));
5968
                                poBand->m_bHaveOffsetScale = true;
18✔
5969
                                poBand->m_dfScale = dfScale;
18✔
5970
                                poBand->m_dfOffset = dfOffset;
18✔
5971
                            }
5972
                        }
5973
                    }
5974
                }
5975

5976
                else if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX, &nCount,
3,778✔
5977
                                      &padfMatrix) &&
3,894✔
5978
                         nCount == 16)
116✔
5979
                {
5980
                    m_adfGeoTransform[0] = padfMatrix[3];
116✔
5981
                    m_adfGeoTransform[1] = padfMatrix[0];
116✔
5982
                    m_adfGeoTransform[2] = padfMatrix[1];
116✔
5983
                    m_adfGeoTransform[3] = padfMatrix[7];
116✔
5984
                    m_adfGeoTransform[4] = padfMatrix[4];
116✔
5985
                    m_adfGeoTransform[5] = padfMatrix[5];
116✔
5986

5987
                    if (bPixelIsPoint && !bPointGeoIgnore)
116✔
5988
                    {
5989
                        m_adfGeoTransform[0] -= m_adfGeoTransform[1] * 0.5 +
4✔
5990
                                                m_adfGeoTransform[2] * 0.5;
4✔
5991
                        m_adfGeoTransform[3] -= m_adfGeoTransform[4] * 0.5 +
4✔
5992
                                                m_adfGeoTransform[5] * 0.5;
4✔
5993
                    }
5994

5995
                    m_bGeoTransformValid = true;
116✔
5996
                    m_nGeoTransformGeorefSrcIndex = nIndex;
116✔
5997
                }
5998
                if (m_bGeoTransformValid)
13,226✔
5999
                    break;
9,564✔
6000
            }
6001

6002
            /* --------------------------------------------------------------------
6003
             */
6004
            /*      Otherwise try looking for a .tab, .tfw, .tifw or .wld file.
6005
             */
6006
            /* --------------------------------------------------------------------
6007
             */
6008
            if (m_nTABFILEGeorefSrcIndex == nIndex)
10,962✔
6009
            {
6010
                char *pszGeorefFilename = nullptr;
3,646✔
6011

6012
                CSLConstList papszSiblingFiles = GetSiblingFiles();
3,646✔
6013

6014
                // Begin with .tab since it can also have projection info.
6015
                int nGCPCount = 0;
3,645✔
6016
                GDAL_GCP *pasGCPList = nullptr;
3,645✔
6017
                const int bTabFileOK = GDALReadTabFile2(
7,291✔
6018
                    m_pszFilename, m_adfGeoTransform, &pszTabWKT, &nGCPCount,
3,645✔
6019
                    &pasGCPList, papszSiblingFiles, &pszGeorefFilename);
6020

6021
                if (bTabFileOK)
3,646✔
6022
                {
6023
                    m_nGeoTransformGeorefSrcIndex = nIndex;
14✔
6024
                    // if( pszTabWKT )
6025
                    // {
6026
                    //     m_nProjectionGeorefSrcIndex = nIndex;
6027
                    // }
6028
                    m_aoGCPs = gdal::GCP::fromC(pasGCPList, nGCPCount);
14✔
6029
                    if (m_aoGCPs.empty())
14✔
6030
                    {
6031
                        m_bGeoTransformValid = true;
14✔
6032
                    }
6033
                }
6034

6035
                if (nGCPCount)
3,646✔
6036
                {
6037
                    GDALDeinitGCPs(nGCPCount, pasGCPList);
×
6038
                    CPLFree(pasGCPList);
×
6039
                }
6040

6041
                if (pszGeorefFilename)
3,646✔
6042
                {
6043
                    CPLFree(m_pszGeorefFilename);
14✔
6044
                    m_pszGeorefFilename = pszGeorefFilename;
14✔
6045
                    pszGeorefFilename = nullptr;
14✔
6046
                }
6047
                if (m_bGeoTransformValid)
3,646✔
6048
                    break;
14✔
6049
            }
6050

6051
            if (m_nWORLDFILEGeorefSrcIndex == nIndex)
10,948✔
6052
            {
6053
                char *pszGeorefFilename = nullptr;
3,654✔
6054

6055
                CSLConstList papszSiblingFiles = GetSiblingFiles();
3,654✔
6056

6057
                m_bGeoTransformValid = CPL_TO_BOOL(GDALReadWorldFile2(
3,654✔
6058
                    m_pszFilename, nullptr, m_adfGeoTransform,
3,654✔
6059
                    papszSiblingFiles, &pszGeorefFilename));
6060

6061
                if (!m_bGeoTransformValid)
3,654✔
6062
                {
6063
                    m_bGeoTransformValid = CPL_TO_BOOL(GDALReadWorldFile2(
3,622✔
6064
                        m_pszFilename, "wld", m_adfGeoTransform,
3,622✔
6065
                        papszSiblingFiles, &pszGeorefFilename));
6066
                }
6067
                if (m_bGeoTransformValid)
3,654✔
6068
                    m_nGeoTransformGeorefSrcIndex = nIndex;
37✔
6069

6070
                if (pszGeorefFilename)
3,654✔
6071
                {
6072
                    CPLFree(m_pszGeorefFilename);
37✔
6073
                    m_pszGeorefFilename = pszGeorefFilename;
37✔
6074
                    pszGeorefFilename = nullptr;
37✔
6075
                }
6076
                if (m_bGeoTransformValid)
3,654✔
6077
                    break;
37✔
6078
            }
6079
        }
6080

6081
        /* --------------------------------------------------------------------
6082
         */
6083
        /*      Check for GCPs. */
6084
        /* --------------------------------------------------------------------
6085
         */
6086
        if (m_nINTERNALGeorefSrcIndex >= 0 &&
39,754✔
6087
            TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
13,234✔
6088
                         &padfTiePoints) &&
26,494✔
6089
            !m_bGeoTransformValid)
9,582✔
6090
        {
6091
            m_aoGCPs.clear();
134✔
6092
            const int nNewGCPCount = nCount / 6;
134✔
6093
            for (int iGCP = 0; iGCP < nNewGCPCount; ++iGCP)
628✔
6094
            {
6095
                m_aoGCPs.emplace_back(CPLSPrintf("%d", iGCP + 1), "",
×
6096
                                      /* pixel = */ padfTiePoints[iGCP * 6 + 0],
494✔
6097
                                      /* line = */ padfTiePoints[iGCP * 6 + 1],
494✔
6098
                                      /* X = */ padfTiePoints[iGCP * 6 + 3],
494✔
6099
                                      /* Y = */ padfTiePoints[iGCP * 6 + 4],
494✔
6100
                                      /* Z = */ padfTiePoints[iGCP * 6 + 5]);
494✔
6101

6102
                if (bPixelIsPoint && !bPointGeoIgnore)
494✔
6103
                {
6104
                    m_aoGCPs.back().Pixel() += 0.5;
48✔
6105
                    m_aoGCPs.back().Line() += 0.5;
48✔
6106
                }
6107
            }
6108
            m_nGeoTransformGeorefSrcIndex = m_nINTERNALGeorefSrcIndex;
134✔
6109
        }
6110

6111
        /* --------------------------------------------------------------------
6112
         */
6113
        /*      Did we find a tab file?  If so we will use its coordinate */
6114
        /*      system and give it precedence. */
6115
        /* --------------------------------------------------------------------
6116
         */
6117
        if (pszTabWKT != nullptr && m_oSRS.IsEmpty())
13,260✔
6118
        {
6119
            m_oSRS.importFromWkt(pszTabWKT);
14✔
6120
            m_bLookedForProjection = true;
14✔
6121
        }
6122

6123
        CPLFree(pszTabWKT);
13,260✔
6124
    }
6125

6126
    if (m_bLoadPam && m_nPAMGeorefSrcIndex >= 0)
13,259✔
6127
    {
6128
        /* --------------------------------------------------------------------
6129
         */
6130
        /*      Initialize any PAM information. */
6131
        /* --------------------------------------------------------------------
6132
         */
6133
        CPLAssert(!m_bColorProfileMetadataChanged);
11,335✔
6134
        CPLAssert(!m_bMetadataChanged);
11,335✔
6135
        CPLAssert(!m_bGeoTIFFInfoChanged);
11,335✔
6136
        CPLAssert(!m_bNoDataChanged);
11,335✔
6137

6138
        // We must absolutely unset m_bLoadPam now, otherwise calling
6139
        // GetFileList() on a .tif with a .aux will result in an (almost)
6140
        // endless sequence of calls.
6141
        m_bLoadPam = false;
11,335✔
6142

6143
        TryLoadXML(GetSiblingFiles());
11,335✔
6144
        ApplyPamInfo();
11,336✔
6145

6146
        m_bColorProfileMetadataChanged = false;
11,334✔
6147
        m_bMetadataChanged = false;
11,334✔
6148
        m_bGeoTIFFInfoChanged = false;
11,334✔
6149
        m_bNoDataChanged = false;
11,334✔
6150
    }
6151
    m_bLoadPam = false;
13,258✔
6152
}
6153

6154
/************************************************************************/
6155
/*                          GetSpatialRef()                             */
6156
/************************************************************************/
6157

6158
const OGRSpatialReference *GTiffDataset::GetSpatialRef() const
16,424✔
6159

6160
{
6161
    const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
16,424✔
6162
    if (m_aoGCPs.empty())
16,423✔
6163
    {
6164
        const_cast<GTiffDataset *>(this)->LookForProjection();
15,897✔
6165
    }
6166

6167
    return m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
16,423✔
6168
}
6169

6170
/************************************************************************/
6171
/*                          GetGeoTransform()                           */
6172
/************************************************************************/
6173

6174
CPLErr GTiffDataset::GetGeoTransform(double *padfTransform)
214,561✔
6175

6176
{
6177
    LoadGeoreferencingAndPamIfNeeded();
214,561✔
6178

6179
    memcpy(padfTransform, m_adfGeoTransform, sizeof(double) * 6);
214,561✔
6180

6181
    if (!m_bGeoTransformValid)
214,561✔
6182
        return CE_Failure;
200,643✔
6183

6184
    // Same logic as in the .gtx driver, for the benefit of
6185
    // GDALOpenVerticalShiftGrid() when used with PROJ-data's US geoids.
6186
    if (CPLFetchBool(papszOpenOptions, "SHIFT_ORIGIN_IN_MINUS_180_PLUS_180",
13,918✔
6187
                     false))
6188
    {
6189
        if (padfTransform[0] < -180.0 - padfTransform[1])
×
6190
            padfTransform[0] += 360.0;
×
6191
        else if (padfTransform[0] > 180.0)
×
6192
            padfTransform[0] -= 360.0;
×
6193
    }
6194

6195
    return CE_None;
13,918✔
6196
}
6197

6198
/************************************************************************/
6199
/*                            GetGCPCount()                             */
6200
/************************************************************************/
6201

6202
int GTiffDataset::GetGCPCount()
4,323✔
6203

6204
{
6205
    LoadGeoreferencingAndPamIfNeeded();
4,323✔
6206

6207
    return static_cast<int>(m_aoGCPs.size());
4,323✔
6208
}
6209

6210
/************************************************************************/
6211
/*                          GetGCPSpatialRef()                          */
6212
/************************************************************************/
6213

6214
const OGRSpatialReference *GTiffDataset::GetGCPSpatialRef() const
626✔
6215

6216
{
6217
    const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
626✔
6218

6219
    if (!m_aoGCPs.empty())
626✔
6220
    {
6221
        const_cast<GTiffDataset *>(this)->LookForProjection();
153✔
6222
    }
6223
    return !m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
626✔
6224
}
6225

6226
/************************************************************************/
6227
/*                               GetGCPs()                              */
6228
/************************************************************************/
6229

6230
const GDAL_GCP *GTiffDataset::GetGCPs()
492✔
6231

6232
{
6233
    LoadGeoreferencingAndPamIfNeeded();
492✔
6234

6235
    return gdal::GCP::c_ptr(m_aoGCPs);
492✔
6236
}
6237

6238
/************************************************************************/
6239
/*                      GetMetadataDomainList()                         */
6240
/************************************************************************/
6241

6242
char **GTiffDataset::GetMetadataDomainList()
33✔
6243
{
6244
    LoadGeoreferencingAndPamIfNeeded();
33✔
6245

6246
    char **papszDomainList = CSLDuplicate(m_oGTiffMDMD.GetDomainList());
33✔
6247
    char **papszBaseList = GDALDataset::GetMetadataDomainList();
33✔
6248

6249
    const int nbBaseDomains = CSLCount(papszBaseList);
33✔
6250

6251
    for (int domainId = 0; domainId < nbBaseDomains; ++domainId)
68✔
6252
    {
6253
        if (CSLFindString(papszDomainList, papszBaseList[domainId]) < 0)
35✔
6254
        {
6255
            papszDomainList =
6256
                CSLAddString(papszDomainList, papszBaseList[domainId]);
33✔
6257
        }
6258
    }
6259

6260
    CSLDestroy(papszBaseList);
33✔
6261

6262
    return BuildMetadataDomainList(papszDomainList, TRUE, "",
33✔
6263
                                   "ProxyOverviewRequest", MD_DOMAIN_RPC,
6264
                                   MD_DOMAIN_IMD, "SUBDATASETS", "EXIF",
6265
                                   "xml:XMP", "COLOR_PROFILE", nullptr);
33✔
6266
}
6267

6268
/************************************************************************/
6269
/*                            GetMetadata()                             */
6270
/************************************************************************/
6271

6272
char **GTiffDataset::GetMetadata(const char *pszDomain)
27,533✔
6273

6274
{
6275
    if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
27,533✔
6276
    {
6277
        GTiffDataset::GetMetadataItem("COMPRESSION_REVERSIBILITY", pszDomain);
117✔
6278
    }
6279
    else
6280
    {
6281
        LoadGeoreferencingAndPamIfNeeded();
27,416✔
6282
    }
6283

6284
    if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
27,533✔
6285
        return GDALPamDataset::GetMetadata(pszDomain);
33✔
6286

6287
    if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
27,500✔
6288
    {
6289
        return GDALDataset::GetMetadata(pszDomain);
6✔
6290
    }
6291

6292
    else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
27,494✔
6293
                                      EQUAL(pszDomain, MD_DOMAIN_IMD) ||
17,657✔
6294
                                      EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
13,701✔
6295
        LoadMetadata();
13,164✔
6296

6297
    else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
14,330✔
6298
        ScanDirectories();
1,195✔
6299

6300
    else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
13,135✔
6301
        LoadEXIFMetadata();
57✔
6302

6303
    else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
13,078✔
6304
        LoadICCProfile();
48✔
6305

6306
    else if (pszDomain == nullptr || EQUAL(pszDomain, ""))
13,030✔
6307
        LoadMDAreaOrPoint();  // To set GDALMD_AREA_OR_POINT.
7,095✔
6308

6309
    return m_oGTiffMDMD.GetMetadata(pszDomain);
27,494✔
6310
}
6311

6312
/************************************************************************/
6313
/*                          GetMetadataItem()                           */
6314
/************************************************************************/
6315

6316
const char *GTiffDataset::GetMetadataItem(const char *pszName,
138,204✔
6317
                                          const char *pszDomain)
6318

6319
{
6320
    if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
138,204✔
6321
    {
6322
        if ((m_nCompression == COMPRESSION_WEBP ||
212,278✔
6323
             m_nCompression == COMPRESSION_JXL ||
69,376✔
6324
             m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
69,375✔
6325
            EQUAL(pszName, "COMPRESSION_REVERSIBILITY") &&
140,904✔
6326
            m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
77✔
6327
                                         "IMAGE_STRUCTURE") == nullptr)
6328
        {
6329
            const char *pszDriverName =
60✔
6330
                m_nCompression == COMPRESSION_WEBP ? "WEBP" : "JPEGXL";
60✔
6331
            auto poTileDriver = GDALGetDriverByName(pszDriverName);
60✔
6332
            if (poTileDriver)
60✔
6333
            {
6334
                vsi_l_offset nOffset = 0;
60✔
6335
                vsi_l_offset nSize = 0;
60✔
6336
                IsBlockAvailable(0, &nOffset, &nSize, nullptr);
60✔
6337
                if (nSize > 0)
60✔
6338
                {
6339
                    const std::string osSubfile(
6340
                        CPLSPrintf("/vsisubfile/" CPL_FRMT_GUIB "_%d,%s",
6341
                                   static_cast<GUIntBig>(nOffset),
6342
                                   static_cast<int>(std::min(
25✔
6343
                                       static_cast<vsi_l_offset>(1024), nSize)),
25✔
6344
                                   m_pszFilename));
50✔
6345
                    const char *const apszDrivers[] = {pszDriverName, nullptr};
25✔
6346
                    auto poWebPDataset =
6347
                        std::unique_ptr<GDALDataset>(GDALDataset::Open(
6348
                            osSubfile.c_str(), GDAL_OF_RASTER, apszDrivers));
50✔
6349
                    if (poWebPDataset)
25✔
6350
                    {
6351
                        const char *pszReversibility =
6352
                            poWebPDataset->GetMetadataItem(
25✔
6353
                                "COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
25✔
6354
                        if (pszReversibility)
25✔
6355
                            m_oGTiffMDMD.SetMetadataItem(
25✔
6356
                                "COMPRESSION_REVERSIBILITY", pszReversibility,
6357
                                "IMAGE_STRUCTURE");
6358
                    }
6359
                }
6360
            }
6361
        }
71,451✔
6362
    }
6363
    else
6364
    {
6365
        LoadGeoreferencingAndPamIfNeeded();
66,753✔
6366
    }
6367

6368
    if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
138,203✔
6369
    {
6370
        return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
4✔
6371
    }
6372
    else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
138,199✔
6373
                                      EQUAL(pszDomain, MD_DOMAIN_IMD) ||
138,144✔
6374
                                      EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
138,140✔
6375
    {
6376
        LoadMetadata();
43✔
6377
    }
6378
    else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
138,156✔
6379
    {
6380
        ScanDirectories();
×
6381
    }
6382
    else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
138,156✔
6383
    {
6384
        LoadEXIFMetadata();
1✔
6385
    }
6386
    else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
138,155✔
6387
    {
6388
        LoadICCProfile();
4,709✔
6389
    }
6390
    else if ((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
133,446✔
6391
             pszName != nullptr && EQUAL(pszName, GDALMD_AREA_OR_POINT))
56,047✔
6392
    {
6393
        LoadMDAreaOrPoint();  // To set GDALMD_AREA_OR_POINT.
6,049✔
6394
    }
6395
    else if (pszDomain != nullptr && EQUAL(pszDomain, "_DEBUG_") &&
127,397✔
6396
             pszName != nullptr)
6397
    {
6398
#ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
6399
        if (EQUAL(pszName, "UNREACHED_VIRTUALMEMIO_CODE_PATH"))
6400
        {
6401
            CPLString osMissing;
6402
            for (int i = 0;
6403
                 i < static_cast<int>(CPL_ARRAYSIZE(anReachedVirtualMemIO));
6404
                 ++i)
6405
            {
6406
                if (!anReachedVirtualMemIO[i])
6407
                {
6408
                    if (!osMissing.empty())
6409
                        osMissing += ",";
6410
                    osMissing += CPLSPrintf("%d", i);
6411
                }
6412
            }
6413
            return (osMissing.size()) ? CPLSPrintf("%s", osMissing.c_str())
6414
                                      : nullptr;
6415
        }
6416
        else
6417
#endif
6418
            if (EQUAL(pszName, "TIFFTAG_EXTRASAMPLES"))
79✔
6419
        {
6420
            CPLString osRet;
18✔
6421
            uint16_t *v = nullptr;
18✔
6422
            uint16_t count = 0;
18✔
6423

6424
            if (TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
18✔
6425
            {
6426
                for (int i = 0; i < static_cast<int>(count); ++i)
53✔
6427
                {
6428
                    if (i > 0)
37✔
6429
                        osRet += ",";
21✔
6430
                    osRet += CPLSPrintf("%d", v[i]);
37✔
6431
                }
6432
            }
6433
            return (osRet.size()) ? CPLSPrintf("%s", osRet.c_str()) : nullptr;
18✔
6434
        }
6435
        else if (EQUAL(pszName, "TIFFTAG_PHOTOMETRIC"))
61✔
6436
        {
6437
            return CPLSPrintf("%d", m_nPhotometric);
6✔
6438
        }
6439

6440
        else if (EQUAL(pszName, "TIFFTAG_GDAL_METADATA"))
55✔
6441
        {
6442
            char *pszText = nullptr;
7✔
6443
            if (!TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
7✔
6444
                return nullptr;
6✔
6445

6446
            return pszText;
1✔
6447
        }
6448
        else if (EQUAL(pszName, "HAS_USED_READ_ENCODED_API"))
48✔
6449
        {
6450
            return m_bHasUsedReadEncodedAPI ? "1" : "0";
6✔
6451
        }
6452
        else if (EQUAL(pszName, "WEBP_LOSSLESS"))
42✔
6453
        {
6454
            return m_bWebPLossless ? "1" : "0";
6✔
6455
        }
6456
        else if (EQUAL(pszName, "WEBP_LEVEL"))
36✔
6457
        {
6458
            return CPLSPrintf("%d", m_nWebPLevel);
2✔
6459
        }
6460
        else if (EQUAL(pszName, "MAX_Z_ERROR"))
34✔
6461
        {
6462
            return CPLSPrintf("%f", m_dfMaxZError);
10✔
6463
        }
6464
        else if (EQUAL(pszName, "MAX_Z_ERROR_OVERVIEW"))
24✔
6465
        {
6466
            return CPLSPrintf("%f", m_dfMaxZErrorOverview);
6✔
6467
        }
6468
#if HAVE_JXL
6469
        else if (EQUAL(pszName, "JXL_LOSSLESS"))
18✔
6470
        {
6471
            return m_bJXLLossless ? "1" : "0";
9✔
6472
        }
6473
        else if (EQUAL(pszName, "JXL_DISTANCE"))
9✔
6474
        {
6475
            return CPLSPrintf("%f", m_fJXLDistance);
4✔
6476
        }
6477
        else if (EQUAL(pszName, "JXL_ALPHA_DISTANCE"))
5✔
6478
        {
6479
            return CPLSPrintf("%f", m_fJXLAlphaDistance);
×
6480
        }
6481
        else if (EQUAL(pszName, "JXL_EFFORT"))
5✔
6482
        {
6483
            return CPLSPrintf("%u", m_nJXLEffort);
4✔
6484
        }
6485
#endif
6486
        return nullptr;
1✔
6487
    }
6488

6489
    else if (pszDomain != nullptr && EQUAL(pszDomain, "TIFF") &&
127,318✔
6490
             pszName != nullptr)
6491
    {
6492
        if (EQUAL(pszName, "GDAL_STRUCTURAL_METADATA"))
7✔
6493
        {
6494
            const auto nOffset = VSIFTellL(m_fpL);
2✔
6495
            VSIFSeekL(m_fpL, 0, SEEK_SET);
2✔
6496
            GByte abyData[1024];
6497
            size_t nRead = VSIFReadL(abyData, 1, sizeof(abyData) - 1, m_fpL);
2✔
6498
            abyData[nRead] = 0;
2✔
6499
            VSIFSeekL(m_fpL, nOffset, SEEK_SET);
2✔
6500
            if (nRead > 4)
2✔
6501
            {
6502
                const int nOffsetOfStructuralMetadata =
2✔
6503
                    (abyData[2] == 0x2B || abyData[3] == 0x2B) ? 16 : 8;
2✔
6504
                const int nSizePatternLen =
2✔
6505
                    static_cast<int>(strlen("XXXXXX bytes\n"));
6506
                if (nRead > nOffsetOfStructuralMetadata +
2✔
6507
                                strlen("GDAL_STRUCTURAL_METADATA_SIZE=") +
2✔
6508
                                nSizePatternLen &&
2✔
6509
                    memcmp(abyData + nOffsetOfStructuralMetadata,
2✔
6510
                           "GDAL_STRUCTURAL_METADATA_SIZE=",
6511
                           strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) == 0)
6512
                {
6513
                    char *pszStructuralMD = reinterpret_cast<char *>(
1✔
6514
                        abyData + nOffsetOfStructuralMetadata);
1✔
6515
                    const int nLenMD =
6516
                        atoi(pszStructuralMD +
1✔
6517
                             strlen("GDAL_STRUCTURAL_METADATA_SIZE="));
6518
                    if (nOffsetOfStructuralMetadata +
1✔
6519
                            strlen("GDAL_STRUCTURAL_METADATA_SIZE=") +
6520
                            nSizePatternLen + nLenMD <=
1✔
6521
                        nRead)
6522
                    {
6523
                        pszStructuralMD[strlen(
6524
                                            "GDAL_STRUCTURAL_METADATA_SIZE=") +
6525
                                        nSizePatternLen + nLenMD] = 0;
1✔
6526
                        return CPLSPrintf("%s", pszStructuralMD);
1✔
6527
                    }
6528
                }
6529
            }
6530
            return nullptr;
1✔
6531
        }
6532
    }
6533

6534
    return m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
138,119✔
6535
}
6536

6537
/************************************************************************/
6538
/*                         LoadEXIFMetadata()                           */
6539
/************************************************************************/
6540

6541
void GTiffDataset::LoadEXIFMetadata()
58✔
6542
{
6543
    if (m_bEXIFMetadataLoaded)
58✔
6544
        return;
7✔
6545
    m_bEXIFMetadataLoaded = true;
51✔
6546

6547
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
51✔
6548

6549
    GByte abyHeader[2] = {0};
51✔
6550
    if (VSIFSeekL(fp, 0, SEEK_SET) != 0 || VSIFReadL(abyHeader, 1, 2, fp) != 2)
51✔
6551
        return;
×
6552

6553
    const bool bLittleEndian = abyHeader[0] == 'I' && abyHeader[1] == 'I';
51✔
6554
    const bool bLeastSignificantBit = CPL_IS_LSB != 0;
51✔
6555
    const bool bSwabflag = bLittleEndian != bLeastSignificantBit;  // != is XOR.
51✔
6556

6557
    char **papszMetadata = nullptr;
51✔
6558
    toff_t nOffset = 0;  // TODO(b/28199387): Refactor to simplify casting.
51✔
6559

6560
    if (TIFFGetField(m_hTIFF, TIFFTAG_EXIFIFD, &nOffset))
51✔
6561
    {
6562
        int nExifOffset = static_cast<int>(nOffset);
3✔
6563
        int nInterOffset = 0;
3✔
6564
        int nGPSOffset = 0;
3✔
6565
        EXIFExtractMetadata(papszMetadata, fp, static_cast<int>(nOffset),
3✔
6566
                            bSwabflag, 0, nExifOffset, nInterOffset,
6567
                            nGPSOffset);
6568
    }
6569

6570
    if (TIFFGetField(m_hTIFF, TIFFTAG_GPSIFD, &nOffset))
51✔
6571
    {
6572
        int nExifOffset = 0;  // TODO(b/28199387): Refactor to simplify casting.
3✔
6573
        int nInterOffset = 0;
3✔
6574
        int nGPSOffset = static_cast<int>(nOffset);
3✔
6575
        EXIFExtractMetadata(papszMetadata, fp, static_cast<int>(nOffset),
3✔
6576
                            bSwabflag, 0, nExifOffset, nInterOffset,
6577
                            nGPSOffset);
6578
    }
6579

6580
    if (papszMetadata)
51✔
6581
    {
6582
        m_oGTiffMDMD.SetMetadata(papszMetadata, "EXIF");
3✔
6583
        CSLDestroy(papszMetadata);
3✔
6584
    }
6585
}
6586

6587
/************************************************************************/
6588
/*                           LoadMetadata()                             */
6589
/************************************************************************/
6590
void GTiffDataset::LoadMetadata()
15,686✔
6591
{
6592
    if (m_bIMDRPCMetadataLoaded)
15,686✔
6593
        return;
11,381✔
6594
    m_bIMDRPCMetadataLoaded = true;
4,383✔
6595

6596
    if (EQUAL(CPLGetExtensionSafe(GetDescription()).c_str(), "ovr"))
4,383✔
6597
    {
6598
        // Do not attempt to retrieve metadata files on .tif.ovr files.
6599
        // For example the Pleiades metadata reader might wrongly associate a
6600
        // DIM_xxx.XML file that was meant to be associated with the main
6601
        // TIFF file. The consequence of that wrong association is that if
6602
        // one cleans overviews, then the Delete() method would then delete
6603
        // that DIM_xxx.XML file since it would be reported in the GetFileList()
6604
        // of the overview dataset.
6605
        return;
78✔
6606
    }
6607

6608
    GDALMDReaderManager mdreadermanager;
8,610✔
6609
    GDALMDReaderBase *mdreader = mdreadermanager.GetReader(
4,305✔
6610
        m_pszFilename, oOvManager.GetSiblingFiles(), MDR_ANY);
4,305✔
6611

6612
    if (nullptr != mdreader)
4,305✔
6613
    {
6614
        mdreader->FillMetadata(&m_oGTiffMDMD);
65✔
6615

6616
        if (mdreader->GetMetadataDomain(MD_DOMAIN_RPC) == nullptr)
65✔
6617
        {
6618
            char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
36✔
6619
            if (papszRPCMD)
36✔
6620
            {
6621
                m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
12✔
6622
                CSLDestroy(papszRPCMD);
12✔
6623
            }
6624
        }
6625

6626
        m_papszMetadataFiles = mdreader->GetMetadataFiles();
65✔
6627
    }
6628
    else
6629
    {
6630
        char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
4,240✔
6631
        if (papszRPCMD)
4,240✔
6632
        {
6633
            m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
20✔
6634
            CSLDestroy(papszRPCMD);
20✔
6635
        }
6636
    }
6637
}
6638

6639
/************************************************************************/
6640
/*                     HasOptimizedReadMultiRange()                     */
6641
/************************************************************************/
6642

6643
bool GTiffDataset::HasOptimizedReadMultiRange()
2,877,020✔
6644
{
6645
    if (m_nHasOptimizedReadMultiRange >= 0)
2,877,020✔
6646
        return m_nHasOptimizedReadMultiRange != 0;
2,864,230✔
6647
    m_nHasOptimizedReadMultiRange = static_cast<signed char>(
12,659✔
6648
        VSIHasOptimizedReadMultiRange(m_pszFilename)
12,792✔
6649
        // Config option for debug and testing purposes only
6650
        || CPLTestBool(CPLGetConfigOption(
12,551✔
6651
               "GTIFF_HAS_OPTIMIZED_READ_MULTI_RANGE", "NO")));
6652
    return m_nHasOptimizedReadMultiRange != 0;
12,659✔
6653
}
6654

6655
/************************************************************************/
6656
/*                         CacheMultiRange()                            */
6657
/************************************************************************/
6658

6659
static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
258✔
6660
{
6661
    GByte abyTrailer[4];
6662
    memcpy(abyTrailer, strileData + nStrileSize, 4);
258✔
6663
    GByte abyLastBytes[4] = {};
258✔
6664
    if (nStrileSize >= 4)
258✔
6665
        memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
258✔
6666
    else
6667
    {
6668
        // The last bytes will be zero due to the above {} initialization,
6669
        // and that's what should be in abyTrailer too when the trailer is
6670
        // correct.
6671
        memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
×
6672
    }
6673
    return memcmp(abyTrailer, abyLastBytes, 4) == 0;
258✔
6674
}
6675

6676
void *GTiffDataset::CacheMultiRange(int nXOff, int nYOff, int nXSize,
270✔
6677
                                    int nYSize, int nBufXSize, int nBufYSize,
6678
                                    const int *panBandMap, int nBandCount,
6679
                                    GDALRasterIOExtraArg *psExtraArg)
6680
{
6681
    void *pBufferedData = nullptr;
270✔
6682
    // Same logic as in GDALRasterBand::IRasterIO()
6683
    double dfXOff = nXOff;
270✔
6684
    double dfYOff = nYOff;
270✔
6685
    double dfXSize = nXSize;
270✔
6686
    double dfYSize = nYSize;
270✔
6687
    if (psExtraArg->bFloatingPointWindowValidity)
270✔
6688
    {
6689
        dfXOff = psExtraArg->dfXOff;
48✔
6690
        dfYOff = psExtraArg->dfYOff;
48✔
6691
        dfXSize = psExtraArg->dfXSize;
48✔
6692
        dfYSize = psExtraArg->dfYSize;
48✔
6693
    }
6694
    const double dfSrcXInc = dfXSize / static_cast<double>(nBufXSize);
270✔
6695
    const double dfSrcYInc = dfYSize / static_cast<double>(nBufYSize);
270✔
6696
    const double EPS = 1e-10;
270✔
6697
    const int nBlockX1 =
6698
        static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
270✔
6699
        m_nBlockXSize;
270✔
6700
    const int nBlockY1 =
6701
        static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
270✔
6702
        m_nBlockYSize;
270✔
6703
    const int nBlockX2 =
6704
        static_cast<int>(
270✔
6705
            std::min(static_cast<double>(nRasterXSize - 1),
540✔
6706
                     (nBufXSize - 1 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
270✔
6707
        m_nBlockXSize;
270✔
6708
    const int nBlockY2 =
6709
        static_cast<int>(
270✔
6710
            std::min(static_cast<double>(nRasterYSize - 1),
540✔
6711
                     (nBufYSize - 1 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
270✔
6712
        m_nBlockYSize;
270✔
6713

6714
    struct StrileData
6715
    {
6716
        vsi_l_offset nOffset;
6717
        vsi_l_offset nByteCount;
6718
        bool bTryMask;
6719
    };
6720

6721
    std::map<int, StrileData> oMapStrileToOffsetByteCount;
540✔
6722

6723
    // Dedicated method to retrieved the offset and size in an efficient way
6724
    // when m_bBlockOrderRowMajor and m_bLeaderSizeAsUInt4 conditions are
6725
    // met.
6726
    // Except for the last block, we just read the offset from the TIFF offset
6727
    // array, and retrieve the size in the leader 4 bytes that come before the
6728
    // payload.
6729
    auto OptimizedRetrievalOfOffsetSize =
6730
        [&](int nBand, int nBlockId, vsi_l_offset &nOffset, vsi_l_offset &nSize,
219✔
6731
            size_t nTotalSize, size_t nMaxRawBlockCacheSize)
6732
    {
6733
        bool bTryMask = m_bMaskInterleavedWithImagery;
1,231✔
6734
        nOffset = TIFFGetStrileOffset(m_hTIFF, nBlockId);
219✔
6735
        if (nOffset >= 4)
219✔
6736
        {
6737
            if ((m_nPlanarConfig == PLANARCONFIG_CONTIG &&
156✔
6738
                 nBlockId == m_nBlocksPerBand - 1) ||
132✔
6739
                (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
130✔
6740
                 nBlockId == m_nBlocksPerBand * nBands - 1))
24✔
6741
            {
6742
                // Special case for the last block. As there is no next block
6743
                // from which to retrieve an offset, use the good old method
6744
                // that consists in reading the ByteCount array.
6745
                if (m_nPlanarConfig == PLANARCONFIG_CONTIG && bTryMask &&
26✔
6746
                    GetRasterBand(1)->GetMaskBand() && m_poMaskDS)
54✔
6747
                {
6748
                    auto nMaskOffset =
6749
                        TIFFGetStrileOffset(m_poMaskDS->m_hTIFF, nBlockId);
23✔
6750
                    if (nMaskOffset)
23✔
6751
                    {
6752
                        nSize = nMaskOffset +
23✔
6753
                                TIFFGetStrileByteCount(m_poMaskDS->m_hTIFF,
23✔
6754
                                                       nBlockId) -
23✔
6755
                                nOffset;
23✔
6756
                    }
6757
                    else
6758
                    {
6759
                        bTryMask = false;
×
6760
                    }
6761
                }
6762
                if (nSize == 0)
28✔
6763
                {
6764
                    nSize = TIFFGetStrileByteCount(m_hTIFF, nBlockId);
5✔
6765
                }
6766
                if (nSize && m_bTrailerRepeatedLast4BytesRepeated)
28✔
6767
                {
6768
                    nSize += 4;
28✔
6769
                }
28✔
6770
            }
6771
            else
6772
            {
6773
                const auto nNextBlockId =
128✔
6774
                    (m_bTileInterleave && nBand < nBands)
11✔
6775
                        ? nBlockId + m_nBlocksPerBand
256✔
6776
                    : (m_bTileInterleave && nBand == nBands)
3✔
6777
                        ? nBlockId - (nBand - 1) * m_nBlocksPerBand + 1
123✔
6778
                        : nBlockId + 1;
117✔
6779
                auto nOffsetNext = TIFFGetStrileOffset(m_hTIFF, nNextBlockId);
128✔
6780
                if (nOffsetNext > nOffset)
128✔
6781
                {
6782
                    nSize = nOffsetNext - nOffset;
120✔
6783
                }
6784
                else
6785
                {
6786
                    // Shouldn't happen for a compliant file
6787
                    if (nOffsetNext != 0)
8✔
6788
                    {
6789
                        CPLDebug("GTiff", "Tile %d is not located after %d",
×
6790
                                 nNextBlockId, nBlockId);
6791
                    }
6792
                    bTryMask = false;
8✔
6793
                    nSize = TIFFGetStrileByteCount(m_hTIFF, nBlockId);
8✔
6794
                    if (m_bTrailerRepeatedLast4BytesRepeated)
8✔
6795
                        nSize += 4;
8✔
6796
                }
6797
            }
6798
            if (nSize)
156✔
6799
            {
6800
                nOffset -= 4;
156✔
6801
                nSize += 4;
156✔
6802
                if (nTotalSize + nSize < nMaxRawBlockCacheSize)
156✔
6803
                {
6804
                    StrileData data;
6805
                    data.nOffset = nOffset;
156✔
6806
                    data.nByteCount = nSize;
156✔
6807
                    data.bTryMask = bTryMask;
156✔
6808
                    oMapStrileToOffsetByteCount[nBlockId] = data;
156✔
6809
                }
6810
            }
6811
        }
6812
        else
6813
        {
6814
            // Sparse tile
6815
            StrileData data;
6816
            data.nOffset = 0;
63✔
6817
            data.nByteCount = 0;
63✔
6818
            data.bTryMask = false;
63✔
6819
            oMapStrileToOffsetByteCount[nBlockId] = data;
63✔
6820
        }
6821
    };
219✔
6822

6823
    // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
6824
    // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
6825
    // mask) from the temporary oMapStrileToOffsetByteCount.
6826
    auto FillCacheStrileToOffsetByteCount =
6827
        [&](const std::vector<vsi_l_offset> &anOffsets,
38✔
6828
            const std::vector<size_t> &anSizes,
6829
            const std::vector<void *> &apData)
6830
    {
6831
        CPLAssert(m_bLeaderSizeAsUInt4);
38✔
6832
        size_t i = 0;
38✔
6833
        vsi_l_offset nLastOffset = 0;
38✔
6834
        for (const auto &entry : oMapStrileToOffsetByteCount)
217✔
6835
        {
6836
            const auto nBlockId = entry.first;
179✔
6837
            const auto nOffset = entry.second.nOffset;
179✔
6838
            const auto nSize = entry.second.nByteCount;
179✔
6839
            if (nOffset == 0)
179✔
6840
            {
6841
                // Sparse tile
6842
                m_oCacheStrileToOffsetByteCount.insert(nBlockId,
6843
                                                       std::pair(0, 0));
23✔
6844
                continue;
77✔
6845
            }
6846

6847
            if (nOffset < nLastOffset)
156✔
6848
            {
6849
                // shouldn't happen normally if tiles are sorted
6850
                i = 0;
2✔
6851
            }
6852
            nLastOffset = nOffset;
156✔
6853
            while (i < anOffsets.size() &&
320✔
6854
                   !(nOffset >= anOffsets[i] &&
160✔
6855
                     nOffset + nSize <= anOffsets[i] + anSizes[i]))
160✔
6856
            {
6857
                i++;
4✔
6858
            }
6859
            CPLAssert(i < anOffsets.size());
156✔
6860
            CPLAssert(nOffset >= anOffsets[i]);
156✔
6861
            CPLAssert(nOffset + nSize <= anOffsets[i] + anSizes[i]);
156✔
6862
            GUInt32 nSizeFromLeader;
6863
            memcpy(&nSizeFromLeader,
156✔
6864
                   // cppcheck-suppress containerOutOfBounds
6865
                   static_cast<GByte *>(apData[i]) + nOffset - anOffsets[i],
156✔
6866
                   sizeof(nSizeFromLeader));
6867
            CPL_LSBPTR32(&nSizeFromLeader);
156✔
6868
            bool bOK = true;
156✔
6869
            constexpr int nLeaderSize = 4;
156✔
6870
            const int nTrailerSize =
156✔
6871
                (m_bTrailerRepeatedLast4BytesRepeated ? 4 : 0);
156✔
6872
            if (nSizeFromLeader > nSize - nLeaderSize - nTrailerSize)
156✔
6873
            {
6874
                CPLDebug("GTiff",
×
6875
                         "Inconsistent block size from in leader of block %d",
6876
                         nBlockId);
6877
                bOK = false;
×
6878
            }
6879
            else if (m_bTrailerRepeatedLast4BytesRepeated)
156✔
6880
            {
6881
                // Check trailer consistency
6882
                const GByte *strileData = static_cast<GByte *>(apData[i]) +
156✔
6883
                                          nOffset - anOffsets[i] + nLeaderSize;
156✔
6884
                if (!CheckTrailer(strileData, nSizeFromLeader))
156✔
6885
                {
6886
                    CPLDebug("GTiff", "Inconsistent trailer of block %d",
×
6887
                             nBlockId);
6888
                    bOK = false;
×
6889
                }
6890
            }
6891
            if (!bOK)
156✔
6892
            {
6893
                return false;
×
6894
            }
6895

6896
            {
6897
                const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
156✔
6898
                const vsi_l_offset nRealSize = nSizeFromLeader;
156✔
6899
#ifdef DEBUG_VERBOSE
6900
                CPLDebug("GTiff",
6901
                         "Block %d found at offset " CPL_FRMT_GUIB
6902
                         " with size " CPL_FRMT_GUIB,
6903
                         nBlockId, nRealOffset, nRealSize);
6904
#endif
6905
                m_oCacheStrileToOffsetByteCount.insert(
6906
                    nBlockId, std::pair(nRealOffset, nRealSize));
156✔
6907
            }
6908

6909
            // Processing of mask
6910
            if (!(entry.second.bTryMask && m_bMaskInterleavedWithImagery &&
258✔
6911
                  GetRasterBand(1)->GetMaskBand() && m_poMaskDS))
102✔
6912
            {
6913
                continue;
54✔
6914
            }
6915

6916
            bOK = false;
102✔
6917
            const vsi_l_offset nMaskOffsetWithLeader =
102✔
6918
                nOffset + nLeaderSize + nSizeFromLeader + nTrailerSize;
102✔
6919
            if (nMaskOffsetWithLeader + nLeaderSize <=
204✔
6920
                anOffsets[i] + anSizes[i])
102✔
6921
            {
6922
                GUInt32 nMaskSizeFromLeader;
6923
                memcpy(&nMaskSizeFromLeader,
102✔
6924
                       static_cast<GByte *>(apData[i]) + nMaskOffsetWithLeader -
102✔
6925
                           anOffsets[i],
102✔
6926
                       sizeof(nMaskSizeFromLeader));
6927
                CPL_LSBPTR32(&nMaskSizeFromLeader);
102✔
6928
                if (nMaskOffsetWithLeader + nLeaderSize + nMaskSizeFromLeader +
204✔
6929
                        nTrailerSize <=
204✔
6930
                    anOffsets[i] + anSizes[i])
102✔
6931
                {
6932
                    bOK = true;
102✔
6933
                    if (m_bTrailerRepeatedLast4BytesRepeated)
102✔
6934
                    {
6935
                        // Check trailer consistency
6936
                        const GByte *strileMaskData =
6937
                            static_cast<GByte *>(apData[i]) + nOffset -
102✔
6938
                            anOffsets[i] + nLeaderSize + nSizeFromLeader +
204✔
6939
                            nTrailerSize + nLeaderSize;
102✔
6940
                        if (!CheckTrailer(strileMaskData, nMaskSizeFromLeader))
102✔
6941
                        {
6942
                            CPLDebug("GTiff",
×
6943
                                     "Inconsistent trailer of mask of block %d",
6944
                                     nBlockId);
6945
                            bOK = false;
×
6946
                        }
6947
                    }
6948
                }
6949
                if (bOK)
102✔
6950
                {
6951
                    const vsi_l_offset nRealOffset = nOffset + nLeaderSize +
102✔
6952
                                                     nSizeFromLeader +
102✔
6953
                                                     nTrailerSize + nLeaderSize;
102✔
6954
                    const vsi_l_offset nRealSize = nMaskSizeFromLeader;
102✔
6955
#ifdef DEBUG_VERBOSE
6956
                    CPLDebug("GTiff",
6957
                             "Mask of block %d found at offset " CPL_FRMT_GUIB
6958
                             " with size " CPL_FRMT_GUIB,
6959
                             nBlockId, nRealOffset, nRealSize);
6960
#endif
6961

6962
                    m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
102✔
6963
                        nBlockId, std::pair(nRealOffset, nRealSize));
102✔
6964
                }
6965
            }
6966
            if (!bOK)
102✔
6967
            {
6968
                CPLDebug("GTiff",
×
6969
                         "Mask for block %d is not properly interleaved with "
6970
                         "imagery block",
6971
                         nBlockId);
6972
            }
6973
        }
6974
        return true;
38✔
6975
    };
270✔
6976

6977
    thandle_t th = TIFFClientdata(m_hTIFF);
270✔
6978
    if (!VSI_TIFFHasCachedRanges(th))
270✔
6979
    {
6980
        std::vector<std::pair<vsi_l_offset, size_t>> aOffsetSize;
236✔
6981
        size_t nTotalSize = 0;
236✔
6982
        const unsigned int nMaxRawBlockCacheSize = atoi(
236✔
6983
            CPLGetConfigOption("GDAL_MAX_RAW_BLOCK_CACHE_SIZE", "10485760"));
236✔
6984
        bool bGoOn = true;
236✔
6985
        for (int iBand = 0; iBand < nBandCount; ++iBand)
476✔
6986
        {
6987
            const int nBand = panBandMap[iBand];
240✔
6988
            GTiffRasterBand *poBand =
6989
                cpl::down_cast<GTiffRasterBand *>(papoBands[nBand - 1]);
240✔
6990
            for (int iY = nBlockY1; bGoOn && iY <= nBlockY2; iY++)
561✔
6991
            {
6992
                for (int iX = nBlockX1; bGoOn && iX <= nBlockX2; iX++)
1,046✔
6993
                {
6994
                    GDALRasterBlock *poBlock =
6995
                        poBand->TryGetLockedBlockRef(iX, iY);
725✔
6996
                    if (poBlock != nullptr)
725✔
6997
                    {
6998
                        poBlock->DropLock();
300✔
6999
                        continue;
300✔
7000
                    }
7001
                    int nBlockId = iX + iY * m_nBlocksPerRow;
425✔
7002
                    if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
425✔
7003
                        nBlockId += (nBand - 1) * m_nBlocksPerBand;
24✔
7004
                    vsi_l_offset nOffset = 0;
425✔
7005
                    vsi_l_offset nSize = 0;
425✔
7006

7007
                    if (!m_bStreamingIn && m_bBlockOrderRowMajor &&
425✔
7008
                        m_bLeaderSizeAsUInt4)
219✔
7009
                    {
7010
                        OptimizedRetrievalOfOffsetSize(nBand, nBlockId, nOffset,
219✔
7011
                                                       nSize, nTotalSize,
7012
                                                       nMaxRawBlockCacheSize);
7013
                    }
7014
                    else
7015
                    {
7016
                        CPL_IGNORE_RET_VAL(IsBlockAvailable(nBlockId, &nOffset,
206✔
7017
                                                            &nSize, nullptr));
7018
                    }
7019
                    if (nSize)
425✔
7020
                    {
7021
                        if (nTotalSize + nSize < nMaxRawBlockCacheSize)
167✔
7022
                        {
7023
#ifdef DEBUG_VERBOSE
7024
                            CPLDebug(
7025
                                "GTiff",
7026
                                "Precaching for block (%d, %d), " CPL_FRMT_GUIB
7027
                                "-" CPL_FRMT_GUIB,
7028
                                iX, iY, nOffset,
7029
                                nOffset + static_cast<size_t>(nSize) - 1);
7030
#endif
7031
                            aOffsetSize.push_back(
167✔
7032
                                std::pair(nOffset, static_cast<size_t>(nSize)));
167✔
7033
                            nTotalSize += static_cast<size_t>(nSize);
167✔
7034
                        }
7035
                        else
7036
                        {
7037
                            bGoOn = false;
×
7038
                        }
7039
                    }
7040
                }
7041
            }
7042
        }
7043

7044
        std::sort(aOffsetSize.begin(), aOffsetSize.end());
236✔
7045

7046
        if (nTotalSize > 0)
236✔
7047
        {
7048
            pBufferedData = VSI_MALLOC_VERBOSE(nTotalSize);
43✔
7049
            if (pBufferedData)
43✔
7050
            {
7051
                std::vector<vsi_l_offset> anOffsets;
43✔
7052
                std::vector<size_t> anSizes;
43✔
7053
                std::vector<void *> apData;
43✔
7054
                anOffsets.push_back(aOffsetSize[0].first);
43✔
7055
                apData.push_back(static_cast<GByte *>(pBufferedData));
43✔
7056
                size_t nChunkSize = aOffsetSize[0].second;
43✔
7057
                size_t nAccOffset = 0;
43✔
7058
                // Try to merge contiguous or slightly overlapping ranges
7059
                for (size_t i = 0; i < aOffsetSize.size() - 1; i++)
167✔
7060
                {
7061
                    if (aOffsetSize[i].first < aOffsetSize[i + 1].first &&
248✔
7062
                        aOffsetSize[i].first + aOffsetSize[i].second >=
124✔
7063
                            aOffsetSize[i + 1].first)
124✔
7064
                    {
7065
                        const auto overlap = aOffsetSize[i].first +
120✔
7066
                                             aOffsetSize[i].second -
120✔
7067
                                             aOffsetSize[i + 1].first;
120✔
7068
                        // That should always be the case for well behaved
7069
                        // TIFF files.
7070
                        if (aOffsetSize[i + 1].second > overlap)
120✔
7071
                        {
7072
                            nChunkSize += static_cast<size_t>(
120✔
7073
                                aOffsetSize[i + 1].second - overlap);
120✔
7074
                        }
7075
                    }
7076
                    else
7077
                    {
7078
                        // terminate current block
7079
                        anSizes.push_back(nChunkSize);
4✔
7080
#ifdef DEBUG_VERBOSE
7081
                        CPLDebug("GTiff",
7082
                                 "Requesting range [" CPL_FRMT_GUIB
7083
                                 "-" CPL_FRMT_GUIB "]",
7084
                                 anOffsets.back(),
7085
                                 anOffsets.back() + anSizes.back() - 1);
7086
#endif
7087
                        nAccOffset += nChunkSize;
4✔
7088
                        // start a new range
7089
                        anOffsets.push_back(aOffsetSize[i + 1].first);
4✔
7090
                        apData.push_back(static_cast<GByte *>(pBufferedData) +
4✔
7091
                                         nAccOffset);
7092
                        nChunkSize = aOffsetSize[i + 1].second;
4✔
7093
                    }
7094
                }
7095
                // terminate last block
7096
                anSizes.push_back(nChunkSize);
43✔
7097
#ifdef DEBUG_VERBOSE
7098
                CPLDebug(
7099
                    "GTiff",
7100
                    "Requesting range [" CPL_FRMT_GUIB "-" CPL_FRMT_GUIB "]",
7101
                    anOffsets.back(), anOffsets.back() + anSizes.back() - 1);
7102
#endif
7103

7104
                VSILFILE *fp = VSI_TIFFGetVSILFile(th);
43✔
7105

7106
                // An error in VSIFReadMultiRangeL() will not be critical,
7107
                // as this method is an optimization, and if it fails,
7108
                // tile-by-tile data acquisition will be done, so we can
7109
                // temporary turn failures into warnings.
7110
                bool ok;
7111
                {
7112
                    CPLTurnFailureIntoWarningBackuper
7113
                        oFailureToWarninBackuper{};
43✔
7114
                    ok = VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
43✔
7115
                                             &apData[0], &anOffsets[0],
43✔
7116
                                             &anSizes[0], fp) == 0;
43✔
7117
                }
7118

7119
                if (ok)
43✔
7120
                {
7121
                    if (!oMapStrileToOffsetByteCount.empty() &&
81✔
7122
                        !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
38✔
7123
                                                          apData))
7124
                    {
7125
                        // Retry without optimization
7126
                        CPLFree(pBufferedData);
×
7127
                        m_bLeaderSizeAsUInt4 = false;
×
7128
                        void *pRet = CacheMultiRange(
×
7129
                            nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
7130
                            panBandMap, nBandCount, psExtraArg);
7131
                        m_bLeaderSizeAsUInt4 = true;
×
7132
                        return pRet;
×
7133
                    }
7134

7135
                    VSI_TIFFSetCachedRanges(
43✔
7136
                        th, static_cast<int>(anSizes.size()), &apData[0],
43✔
7137
                        &anOffsets[0], &anSizes[0]);
43✔
7138
                }
7139
                else
7140
                {
7141
                    CPLFree(pBufferedData);
×
7142
                    pBufferedData = nullptr;
×
7143
                }
7144
            }
7145
        }
7146
    }
7147
    return pBufferedData;
270✔
7148
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc