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

OSGeo / gdal / 15899162844

26 Jun 2025 10:14AM UTC coverage: 71.088% (+0.004%) from 71.084%
15899162844

Pull #12623

github

web-flow
Merge c704a8392 into f5cb024d4
Pull Request #12623: gdal raster overview add: add a --overview-src option

209 of 244 new or added lines in 5 files covered. (85.66%)

96 existing lines in 44 files now uncovered.

574014 of 807474 relevant lines covered (71.09%)

250815.03 hits per line

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

91.3
/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()
1,044,380✔
53
{
54
    if (m_nJPEGOverviewCount >= 0)
1,044,380✔
55
        return m_nJPEGOverviewCount;
1,044,080✔
56

57
    m_nJPEGOverviewCount = 0;
297✔
58
    if (m_poBaseDS || eAccess != GA_ReadOnly ||
273✔
59
        m_nCompression != COMPRESSION_JPEG ||
225✔
60
        (nRasterXSize < 256 && nRasterYSize < 256) ||
22✔
61
        !CPLTestBool(CPLGetConfigOption("GTIFF_IMPLICIT_JPEG_OVR", "YES")) ||
592✔
62
        GDALGetDriverByName("JPEG") == nullptr)
22✔
63
    {
64
        return 0;
275✔
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,800✔
406
{
407
    const auto psJob = static_cast<const GTiffDecompressJob *>(pData);
3,800✔
408
    auto psContext = psJob->psContext;
3,800✔
409
    auto poDS = psContext->poDS;
3,800✔
410

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

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

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

441
    const int nYOffsetInBlock = psJob->nYBlock == psContext->nBlockYStart
7,602✔
442
                                    ? psContext->nYOff % poDS->m_nBlockYSize
3,801✔
443
                                    : 0;
444
    const int nYOffsetInData =
3,801✔
445
        psJob->nYBlock == psContext->nBlockYStart
3,801✔
446
            ? 0
3,801✔
447
            : (psJob->nYBlock - psContext->nBlockYStart) * poDS->m_nBlockYSize -
2,885✔
448
                  (psContext->nYOff % poDS->m_nBlockYSize);
2,885✔
449
    const int nYSize =
3,801✔
450
        psJob->nYBlock == psContext->nBlockYStart
3,801✔
451
            ? (psJob->nYBlock == psContext->nBlockYEnd
7,602✔
452
                   ? psContext->nYSize
913✔
453
                   : poDS->m_nBlockYSize -
913✔
454
                         (psContext->nYOff % poDS->m_nBlockYSize))
913✔
455
        : psJob->nYBlock == psContext->nBlockYEnd
2,888✔
456
            ? (((psContext->nYOff + psContext->nYSize) % poDS->m_nBlockYSize) ==
3,804✔
457
                       0
458
                   ? poDS->m_nBlockYSize
916✔
459
                   : ((psContext->nYOff + psContext->nYSize) %
801✔
460
                      poDS->m_nBlockYSize))
801✔
461
            : poDS->m_nBlockYSize;
1,972✔
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,801✔
473
    {
474
        {
475
            std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
2✔
476
            if (!psContext->bSuccess)
2✔
477
                return;
×
478
        }
479
        const double dfNoDataValue =
2✔
480
            poDS->m_bNoDataSet ? poDS->m_dfNoDataValue : 0;
2✔
481
        for (int y = 0; y < nYSize; ++y)
102✔
482
        {
483
            for (int i = 0; i < nBandsToWrite; ++i)
200✔
484
            {
485
                const int iDstBandIdx =
100✔
486
                    poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
100✔
487
                        ? i
100✔
488
                        : psJob->iDstBandIdxSeparate;
×
489
                GDALCopyWords64(
100✔
490
                    &dfNoDataValue, GDT_Float64, 0,
491
                    psContext->pabyData + iDstBandIdx * psContext->nBandSpace +
100✔
492
                        (y + nYOffsetInData) * psContext->nLineSpace +
100✔
493
                        nXOffsetInData * psContext->nPixelSpace,
100✔
494
                    psContext->eBufType,
495
                    static_cast<int>(psContext->nPixelSpace), nXSize);
100✔
496
            }
497
        }
498
        return;
2✔
499
    }
500

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

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

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

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

527
    FreeBlocks oFreeBlocks(apoBlocks);
3,789✔
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,792✔
562

563
    const auto AllocInputBuffer = [&]()
2,580✔
564
    {
565
        bool bError = false;
2,580✔
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,580✔
577
            }
578
            catch (const std::exception &)
×
579
            {
580
                bError = true;
×
581
            }
582
        }
583
        if (bError)
2,570✔
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,570✔
591
    };
3,792✔
592

593
    if (psContext->bHasPRead)
3,792✔
594
    {
595
        {
596
            std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
3,792✔
597
            if (!psContext->bSuccess)
3,800✔
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,800✔
605
            {
606
                psContext->bSuccess = false;
×
607
                return;
×
608
            }
609
        }
610
        if (nAlreadyLoadedBlocks != nBandsToCache)
3,800✔
611
        {
612
            if (!AllocInputBuffer())
2,580✔
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,576✔
619
                                           psJob->nOffset) != abyInput.size())
5,149✔
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,792✔
672
    GByte *pDstPtr = psContext->pabyData +
3,799✔
673
                     nYOffsetInData * psContext->nLineSpace +
3,799✔
674
                     nXOffsetInData * psContext->nPixelSpace;
3,799✔
675

676
    if (nAlreadyLoadedBlocks != nBandsToCache)
3,799✔
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,576✔
682
        VSILFILE *fpTmp = VSIFOpenL(osTmpFilename.c_str(), "wb+");
2,575✔
683
        TIFF *hTIFFTmp =
684
            VSI_TIFFOpen(osTmpFilename.c_str(),
2,580✔
685
                         psContext->bTIFFIsBigEndian ? "wb+" : "wl+", fpTmp);
2,580✔
686
        CPLAssert(hTIFFTmp != nullptr);
2,580✔
687
        const int nBlockYSize =
2,580✔
688
            (psContext->bIsTiled ||
3,036✔
689
             psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
456✔
690
                ? poDS->m_nBlockYSize
3,036✔
691
            : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
53✔
692
                ? poDS->m_nBlockYSize
53✔
693
                : poDS->nRasterYSize % poDS->m_nBlockYSize;
42✔
694
        TIFFSetField(hTIFFTmp, TIFFTAG_IMAGEWIDTH, poDS->m_nBlockXSize);
2,580✔
695
        TIFFSetField(hTIFFTmp, TIFFTAG_IMAGELENGTH, nBlockYSize);
2,580✔
696
        TIFFSetField(hTIFFTmp, TIFFTAG_BITSPERSAMPLE, poDS->m_nBitsPerSample);
2,580✔
697
        TIFFSetField(hTIFFTmp, TIFFTAG_COMPRESSION, poDS->m_nCompression);
2,580✔
698
        TIFFSetField(hTIFFTmp, TIFFTAG_PHOTOMETRIC, poDS->m_nPhotometric);
2,580✔
699
        TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLEFORMAT, poDS->m_nSampleFormat);
2,580✔
700
        TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLESPERPIXEL,
2,580✔
701
                     poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
2,580✔
702
                         ? poDS->m_nSamplesPerPixel
760✔
703
                         : 1);
704
        TIFFSetField(hTIFFTmp, TIFFTAG_ROWSPERSTRIP, nBlockYSize);
2,580✔
705
        TIFFSetField(hTIFFTmp, TIFFTAG_PLANARCONFIG, poDS->m_nPlanarConfig);
2,580✔
706
        if (psContext->nPredictor != PREDICTOR_NONE)
2,580✔
707
            TIFFSetField(hTIFFTmp, TIFFTAG_PREDICTOR, psContext->nPredictor);
60✔
708
        if (poDS->m_nCompression == COMPRESSION_LERC)
2,580✔
709
        {
710
            TIFFSetField(hTIFFTmp, TIFFTAG_LERC_PARAMETERS, 2,
30✔
711
                         poDS->m_anLercAddCompressionAndVersion);
30✔
712
        }
713
        else if (poDS->m_nCompression == COMPRESSION_JPEG)
2,550✔
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,580✔
728
        {
729
            if (psContext->pExtraSamples)
760✔
730
            {
731
                TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
66✔
732
                             psContext->nExtraSampleCount,
66✔
733
                             psContext->pExtraSamples);
734
            }
735
            else
736
            {
737
                const int nSamplesAccountedFor =
694✔
738
                    poDS->m_nPhotometric == PHOTOMETRIC_RGB          ? 3
916✔
739
                    : poDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ? 1
222✔
740
                                                                     : 0;
741
                if (nSamplesAccountedFor > 0 &&
694✔
742
                    poDS->m_nSamplesPerPixel > nSamplesAccountedFor)
687✔
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,580✔
756
        TIFFWriteDirectory(hTIFFTmp);
2,580✔
757
        XTIFFClose(hTIFFTmp);
2,580✔
758

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

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

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

777
        GByte *pabyOutput;
778
        std::vector<GByte> abyOutput;
2,579✔
779
        if (poDS->m_nCompression == COMPRESSION_NONE &&
5,382✔
780
            !TIFFIsByteSwapped(poDS->m_hTIFF) && abyInput.size() >= nReqSize &&
2,803✔
781
            (psContext->bSkipBlockCache || nBandsPerStrile > 1))
224✔
782
        {
783
            pabyOutput = abyInput.data();
224✔
784
        }
785
        else
786
        {
787
            if (psContext->bSkipBlockCache || nBandsPerStrile > 1)
2,355✔
788
            {
789
                abyOutput.resize(nReqSize);
2,059✔
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,580✔
805
        CPL_IGNORE_RET_VAL(VSIFCloseL(fpTmp));
2,580✔
806
        VSIUnlink(osTmpFilename.c_str());
2,579✔
807

808
        if (!bRet)
2,580✔
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,580✔
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,580✔
854
            pabyOutput +
855
            (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
2,580✔
856
             nXOffsetInBlock) *
2,580✔
857
                nDTSize * nBandsPerStrile;
2,580✔
858
        const size_t nSrcLineInc = static_cast<size_t>(poDS->m_nBlockXSize) *
2,580✔
859
                                   nDTSize * nBandsPerStrile;
2,580✔
860

861
        // Optimization when writing to BIP buffer.
862
        if (psContext->bUseBIPOptim)
2,580✔
863
        {
864
            for (int y = 0; y < nYSize; ++y)
9,444✔
865
            {
866
                GDALCopyWords64(pSrcPtr, psContext->eDT, nDTSize, pDstPtr,
9,139✔
867
                                psContext->eBufType, psContext->nBufDTSize,
868
                                static_cast<size_t>(nXSize) * poDS->nBands);
9,139✔
869
                pSrcPtr += nSrcLineInc;
9,139✔
870
                pDstPtr += psContext->nLineSpace;
9,139✔
871
            }
872
            return;
305✔
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,275✔
890
                {
891
                    GDALDeinterleave(
12,060✔
892
                        pSrcPtr, psContext->eDT, psContext->nBandCount,
893
                        ppDestBuffers.data(), psContext->eDT, nXSize);
894
                    pSrcPtr += nSrcLineInc;
12,060✔
895
                    for (int i = 0; i < psContext->nBandCount; ++i)
48,236✔
896
                    {
897
                        ppDestBuffers[i] =
36,176✔
898
                            static_cast<GByte *>(ppDestBuffers[i]) +
36,176✔
899
                            psContext->nLineSpace;
36,174✔
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,739✔
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,797✔
947
             nXOffsetInBlock) *
2,797✔
948
                nDTSize;
2,797✔
949
        for (int y = 0; y < nYSize; ++y)
68,188✔
950
        {
951
            GDALCopyWords64(pSrcPtr + static_cast<size_t>(y) *
65,379✔
952
                                          poDS->m_nBlockXSize * nDTSize,
65,379✔
953
                            psContext->eDT, nDTSize,
954
                            pDstPtr + iDstBandIdx * psContext->nBandSpace +
65,379✔
955
                                y * psContext->nLineSpace,
65,379✔
956
                            psContext->eBufType,
957
                            static_cast<int>(psContext->nPixelSpace), nXSize);
65,379✔
958
        }
959
    }
960
}
961

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

966
bool GTiffDataset::IsMultiThreadedReadCompatible() const
265✔
967
{
968
    return cpl::down_cast<GTiffRasterBand *>(papoBands[0])
265✔
969
               ->IsBaseGTiffClass() &&
265✔
970
           !m_bStreamingIn && !m_bStreamingOut &&
528✔
971
           (m_nCompression == COMPRESSION_NONE ||
263✔
972
            m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
240✔
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);
267✔
982
}
983

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

988
CPLErr GTiffDataset::MultiThreadedRead(int nXOff, int nYOff, int nXSize,
247✔
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();
494✔
996
    if (poQueue == nullptr)
247✔
997
    {
998
        return CE_Failure;
×
999
    }
1000

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

1011
    GTiffDecompressContext sContext;
494✔
1012
    sContext.poHandle = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
247✔
1013
    sContext.bHasPRead =
247✔
1014
        sContext.poHandle->HasPRead()
247✔
1015
#ifdef DEBUG
1016
        && CPLTestBool(CPLGetConfigOption("GTIFF_ALLOW_PREAD", "YES"))
247✔
1017
#endif
1018
        ;
1019
    sContext.poDS = this;
247✔
1020
    sContext.eDT = GetRasterBand(1)->GetRasterDataType();
247✔
1021
    sContext.nXOff = nXOff;
247✔
1022
    sContext.nYOff = nYOff;
247✔
1023
    sContext.nXSize = nXSize;
247✔
1024
    sContext.nYSize = nYSize;
247✔
1025
    sContext.nBlockXStart = nBlockXStart;
247✔
1026
    sContext.nBlockXEnd = nBlockXEnd;
247✔
1027
    sContext.nBlockYStart = nBlockYStart;
247✔
1028
    sContext.nBlockYEnd = nBlockYEnd;
247✔
1029
    sContext.pabyData = static_cast<GByte *>(pData);
247✔
1030
    sContext.eBufType = eBufType;
247✔
1031
    sContext.nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
247✔
1032
    sContext.nBandCount = nBandCount;
247✔
1033
    sContext.panBandMap = panBandMap;
247✔
1034
    sContext.nPixelSpace = nPixelSpace;
247✔
1035
    sContext.nLineSpace = nLineSpace;
247✔
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;
247✔
1040
    sContext.bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
247✔
1041
    sContext.bTIFFIsBigEndian = CPL_TO_BOOL(TIFFIsBigEndian(m_hTIFF));
247✔
1042
    sContext.nPredictor = PREDICTOR_NONE;
247✔
1043
    sContext.nBlocksPerRow = m_nBlocksPerRow;
247✔
1044

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

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

1084
    if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
247✔
1085
        (nBands == 3 || nBands == 4) && nBands == nBandCount &&
191✔
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 &&
247✔
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)
247✔
1144
    {
1145
        std::vector<int> anBandsToCheck;
234✔
1146
        if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1)
234✔
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)
170✔
1156
            {
1157
                anBandsToCheck.push_back(panBandMap[i] - 1);
112✔
1158
            }
1159
        }
1160
        if (!anBandsToCheck.empty())
234✔
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;
234✔
1170
            for (int y = 0; y < nYBlocks; ++y)
1,225✔
1171
            {
1172
                for (int x = 0; x < nXBlocks; ++x)
3,521✔
1173
                {
1174
                    for (const int iBand : anBandsToCheck)
8,912✔
1175
                    {
1176
                        if (m_nLoadedBlock >= 0 && m_bLoadedBlockDirty &&
6,400✔
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,800✔
1186
                            nBlockXStart + x, nBlockYStart + y);
6,400✔
1187
                        if (poBlock)
6,400✔
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:
216✔
1201
            if (bUseBaseImplementation)
234✔
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 =
216✔
1219
            m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
216✔
1220
        if (!oQueue.empty())
216✔
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));
216✔
1242
        if (sContext.bHasPRead)
216✔
1243
            sContext.poHandle->Flush();
216✔
1244
    }
1245

1246
    if (GTIFFSupportsPredictor(m_nCompression))
229✔
1247
    {
1248
        TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &sContext.nPredictor);
148✔
1249
    }
1250
    else if (m_nCompression == COMPRESSION_JPEG)
81✔
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)
229✔
1262
    {
1263
        TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &sContext.nExtraSampleCount,
182✔
1264
                     &sContext.pExtraSamples);
1265
    }
1266

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

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

1298
                bool bErrorInIsBlockAvailable = false;
11,064✔
1299
                if (!sContext.bHasPRead)
11,064✔
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(
11,064✔
1315
                        nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
11,064✔
1316
                        &bErrorInIsBlockAvailable));
1317
                }
1318
                if (bErrorInIsBlockAvailable)
11,064✔
1319
                {
1320
                    ReportError(CE_Failure, CPLE_AppDefined,
2✔
1321
                                "Error while getting location of block %d",
1322
                                nBlockId);
1323
                    std::lock_guard<std::recursive_mutex> oLock(
1324
                        sContext.oMutex);
2✔
1325
                    sContext.bSuccess = false;
2✔
1326
                    return CE_Failure;
2✔
1327
                }
1328

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

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

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

1392
                if (bAddToAdviseRead)
11,062✔
1393
                {
1394
                    anOffsets[nAdviseReadRanges] = asJobs[iJob].nOffset;
9,164✔
1395
                    anSizes[nAdviseReadRanges] =
18,328✔
1396
                        static_cast<size_t>(std::min<vsi_l_offset>(
9,164✔
1397
                            std::numeric_limits<size_t>::max(),
27,492✔
1398
                            asJobs[iJob].nSize));
9,164✔
1399

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

1419
                        asJobs.clear();
1✔
1420
                        anOffsets.clear();
1✔
1421
                        anSizes.clear();
1✔
1422
                        poQueue.reset();
1✔
1423

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

1441
                    ++nAdviseReadRanges;
9,163✔
1442
                }
1443

1444
                ++iJob;
11,061✔
1445
            }
1446
        }
1447
    }
1448

1449
    if (sContext.bSuccess)
226✔
1450
    {
1451
        // Potentially start asynchronous fetching of ranges depending on file
1452
        // implementation
1453
        if (nAdviseReadRanges > 0)
226✔
1454
        {
1455
            sContext.poHandle->AdviseRead(nAdviseReadRanges, anOffsets.data(),
99✔
1456
                                          anSizes.data());
99✔
1457
        }
1458

1459
        // We need to do that as threads will access the block cache
1460
        TemporarilyDropReadWriteLock();
226✔
1461

1462
        for (auto &sJob : asJobs)
4,028✔
1463
        {
1464
            poQueue->SubmitJob(ThreadDecompressionFunc, &sJob);
3,802✔
1465
        }
1466

1467
        // Wait for all jobs to have been completed
1468
        poQueue->WaitCompletion();
226✔
1469

1470
        // Undo effect of above TemporarilyDropReadWriteLock()
1471
        ReacquireReadWriteLock();
226✔
1472

1473
        sContext.oErrorAccumulator.ReplayErrors();
226✔
1474
    }
1475

1476
    return sContext.bSuccess ? CE_None : CE_Failure;
226✔
1477
}
1478

1479
/************************************************************************/
1480
/*                        FetchBufferVirtualMemIO                       */
1481
/************************************************************************/
1482

1483
class FetchBufferVirtualMemIO final
1484
{
1485
    const GByte *pabySrcData;
1486
    size_t nMappingSize;
1487
    GByte *pTempBuffer;
1488

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

1497
    const GByte *FetchBytes(vsi_l_offset nOffset, int nPixels, int nDTSize,
897,395✔
1498
                            bool bIsByteSwapped, bool bIsComplex, int nBlockId)
1499
    {
1500
        if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
897,395✔
1501
        {
1502
            CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
24✔
1503
                     nBlockId);
1504
            return nullptr;
24✔
1505
        }
1506
        if (!bIsByteSwapped)
897,371✔
1507
            return pabySrcData + nOffset;
572,847✔
1508
        memcpy(pTempBuffer, pabySrcData + nOffset,
324,524✔
1509
               static_cast<size_t>(nPixels) * nDTSize);
324,524✔
1510
        if (bIsComplex)
324,524✔
1511
            GDALSwapWords(pTempBuffer, nDTSize / 2, 2 * nPixels, nDTSize / 2);
159,940✔
1512
        else
1513
            GDALSwapWords(pTempBuffer, nDTSize, nPixels, nDTSize);
164,584✔
1514
        return pTempBuffer;
324,524✔
1515
    }
1516

1517
    bool FetchBytes(GByte *pabyDstBuffer, vsi_l_offset nOffset, int nPixels,
115,046✔
1518
                    int nDTSize, bool bIsByteSwapped, bool bIsComplex,
1519
                    int nBlockId)
1520
    {
1521
        if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
115,046✔
1522
        {
1523
            CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
11✔
1524
                     nBlockId);
1525
            return false;
11✔
1526
        }
1527
        memcpy(pabyDstBuffer, pabySrcData + nOffset,
115,035✔
1528
               static_cast<size_t>(nPixels) * nDTSize);
115,035✔
1529
        if (bIsByteSwapped)
115,035✔
1530
        {
1531
            if (bIsComplex)
48,082✔
1532
                GDALSwapWords(pabyDstBuffer, nDTSize / 2, 2 * nPixels,
26,390✔
1533
                              nDTSize / 2);
1534
            else
1535
                GDALSwapWords(pabyDstBuffer, nDTSize, nPixels, nDTSize);
21,692✔
1536
        }
1537
        return true;
115,035✔
1538
    }
1539

1540
    // cppcheck-suppress unusedStructMember
1541
    static const bool bMinimizeIO = false;
1542
};
1543

1544
/************************************************************************/
1545
/*                         VirtualMemIO()                               */
1546
/************************************************************************/
1547

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

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

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

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

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

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

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

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

1661
/************************************************************************/
1662
/*                   CopyContigByteMultiBand()                          */
1663
/************************************************************************/
1664

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

1738
/************************************************************************/
1739
/*                         CommonDirectIO()                             */
1740
/************************************************************************/
1741

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

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

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

1776
    bool bUseContigImplementation = m_nPlanarConfig == PLANARCONFIG_CONTIG &&
346✔
1777
                                    nBandCount > 1 && nBandSpace == nBufDTSize;
2,088✔
1778
    if (bUseContigImplementation)
1,742✔
1779
    {
1780
        for (int iBand = 0; iBand < nBandCount; ++iBand)
470✔
1781
        {
1782
            const int nBand = panBandMap[iBand];
370✔
1783
            if (nBand != iBand + 1)
370✔
1784
            {
1785
                bUseContigImplementation = false;
×
1786
                break;
×
1787
            }
1788
        }
1789
    }
1790

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

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

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

1825
            int nBlockXOff = nXOff / m_nBlockXSize;
242✔
1826
            int nXOffsetInBlock = nXOff % m_nBlockXSize;
242✔
1827
            int nBlockId = poFirstBand->ComputeBlockId(nBlockXOff, nBlockYOff);
242✔
1828

1829
            int x = 0;
242✔
1830
            while (x < nBufXSize)
1,200✔
1831
            {
1832
                const toff_t nCurOffset = panOffsets[nBlockId];
960✔
1833
                const int nUsedBlockWidth =
960✔
1834
                    std::min(m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
960✔
1835

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

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

1866
                    for (int k = 0; k < nUsedBlockHeight; ++k)
7,468✔
1867
                    {
1868
                        GByte *pabyLocalData =
6,984✔
1869
                            pabyData + (y + k) * nLineSpace + x * nPixelSpace;
6,984✔
1870
                        const GByte *pabyLocalSrcData =
6,984✔
1871
                            pabyLocalSrcDataK0 +
1872
                            (k * m_nBlockXSize + nXOffsetInBlock) *
6,984✔
1873
                                nBandsPerBlockDTSize;
1874

1875
                        if (bUseContigImplementation && nBands == nBandCount &&
6,984✔
1876
                            nPixelSpace == nBandsPerBlockDTSize)
3,234✔
1877
                        {
1878
                            REACHED(31);
1879
                            GDALCopyWords(pabyLocalSrcData, eDataType, nDTSize,
2,262✔
1880
                                          pabyLocalData, eBufType, nBufDTSize,
1881
                                          nUsedBlockWidth * nBands);
2,262✔
1882
                        }
1883
                        else
1884
                        {
1885
                            REACHED(32);
1886
                            for (int iBand = 0; iBand < nBandCount; ++iBand)
22,608✔
1887
                            {
1888
                                GByte *pabyLocalDataBand =
17,886✔
1889
                                    pabyLocalData + iBand * nBandSpace;
17,886✔
1890
                                const GByte *pabyLocalSrcDataBand =
17,886✔
1891
                                    pabyLocalSrcData +
1892
                                    (panBandMap[iBand] - 1) * nDTSize;
17,886✔
1893

1894
                                GDALCopyWords(pabyLocalSrcDataBand, eDataType,
17,886✔
1895
                                              nBandsPerBlockDTSize,
1896
                                              pabyLocalDataBand, eBufType,
1897
                                              static_cast<int>(nPixelSpace),
1898
                                              nUsedBlockWidth);
1899
                            }
1900
                        }
1901
                    }
1902
                }
1903

1904
                nXOffsetInBlock = 0;
958✔
1905
                ++nBlockXOff;
958✔
1906
                ++nBlockId;
958✔
1907
                x += nUsedBlockWidth;
958✔
1908
            }
1909

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

1932
                int nBlockXOff = nXOff / m_nBlockXSize;
3,304✔
1933
                int nXOffsetInBlock = nXOff % m_nBlockXSize;
3,304✔
1934
                int nBlockId =
1935
                    poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
3,304✔
1936

1937
                int x = 0;
3,304✔
1938
                while (x < nBufXSize)
16,000✔
1939
                {
1940
                    const toff_t nCurOffset = panOffsets[nBlockId];
12,705✔
1941
                    const int nUsedBlockWidth = std::min(
12,705✔
1942
                        m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
12,705✔
1943

1944
                    if (nCurOffset == 0)
12,705✔
1945
                    {
1946
                        REACHED(35);
1947
                        for (int k = 0; k < nUsedBlockHeight; ++k)
42,642✔
1948
                        {
1949
                            GByte *pabyLocalData = pabyData +
39,858✔
1950
                                                   (y + k) * nLineSpace +
39,858✔
1951
                                                   x * nPixelSpace;
39,858✔
1952

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

1971
                        if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
9,912✔
1972
                        {
1973
                            REACHED(36);
1974
                            pabyLocalSrcDataK0 += (nBand - 1) * nDTSize;
512✔
1975
                        }
1976
                        else
1977
                        {
1978
                            REACHED(37);
1979
                        }
1980

1981
                        for (int k = 0; k < nUsedBlockHeight; ++k)
151,464✔
1982
                        {
1983
                            GByte *pabyLocalData = pabyData +
141,552✔
1984
                                                   (y + k) * nLineSpace +
141,552✔
1985
                                                   x * nPixelSpace;
141,552✔
1986
                            const GByte *pabyLocalSrcData =
141,552✔
1987
                                pabyLocalSrcDataK0 +
1988
                                (k * m_nBlockXSize + nXOffsetInBlock) *
141,552✔
1989
                                    nBandsPerBlockDTSize;
1990

1991
                            GDALCopyWords(
141,552✔
1992
                                pabyLocalSrcData, eDataType,
1993
                                nBandsPerBlockDTSize, pabyLocalData, eBufType,
1994
                                static_cast<int>(nPixelSpace), nUsedBlockWidth);
1995
                        }
1996
                    }
1997

1998
                    nXOffsetInBlock = 0;
12,696✔
1999
                    ++nBlockXOff;
12,696✔
2000
                    ++nBlockId;
12,696✔
2001
                    x += nUsedBlockWidth;
12,696✔
2002
                }
2003

2004
                y += nUsedBlockHeight;
3,295✔
2005
            }
2006
        }
2007
    }
2008
    // cppcheck-suppress knownConditionTrueFalse
2009
    else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
248✔
2010
             m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount > 1)
248✔
2011
    {
2012
        GByte *pabyData = static_cast<GByte *>(pData);
20✔
2013
        int anSrcYOffset[256] = {0};
20✔
2014
        for (int y = 0; y < nBufYSize;)
119✔
2015
        {
2016
            const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
100✔
2017
            const int nSrcLine = static_cast<int>(dfYOffStart);
100✔
2018
            const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
100✔
2019
            const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
100✔
2020
            const int nBaseByteOffsetIm_nBlock =
100✔
2021
                nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
100✔
2022
            int ychunk = 1;
100✔
2023
            int nLastSrcLineK = nSrcLine;
100✔
2024
            anSrcYOffset[0] = 0;
100✔
2025
            for (int k = 1; k < nBufYSize - y; ++k)
12,064✔
2026
            {
2027
                int nSrcLineK =
12,044✔
2028
                    nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
12,044✔
2029
                const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
12,044✔
2030
                if (k < 256)
12,044✔
2031
                    anSrcYOffset[k] =
7,544✔
2032
                        ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
7,544✔
2033
                        m_nBlockXSize * nBandsPerBlockDTSize;
7,544✔
2034
                if (nBlockYOffK != m_nBlockYOff)
12,044✔
2035
                {
2036
                    break;
80✔
2037
                }
2038
                ++ychunk;
11,964✔
2039
                nLastSrcLineK = nSrcLineK;
11,964✔
2040
            }
2041
            const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
100✔
2042
            // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
2043

2044
            double dfSrcX = nXOff + 0.5 * dfSrcXInc;
100✔
2045
            int nCurBlockXOff = 0;
100✔
2046
            int nNextBlockXOff = 0;
100✔
2047
            toff_t nCurOffset = 0;
100✔
2048
            const GByte *pabyLocalSrcDataStartLine = nullptr;
100✔
2049
            for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
10,843✔
2050
            {
2051
                const int nSrcPixel = static_cast<int>(dfSrcX);
10,744✔
2052
                if (nSrcPixel >= nNextBlockXOff)
10,744✔
2053
                {
2054
                    const int nBlockXOff = nSrcPixel / m_nBlockXSize;
292✔
2055
                    nCurBlockXOff = nBlockXOff * m_nBlockXSize;
292✔
2056
                    nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
292✔
2057
                    const int nBlockId =
2058
                        poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
292✔
2059
                    nCurOffset = panOffsets[nBlockId];
292✔
2060
                    if (nCurOffset != 0)
292✔
2061
                    {
2062
                        pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
292✔
2063
                            nCurOffset + nBaseByteOffsetIm_nBlock,
146✔
2064
                            m_nBlockXSize * nBandsPerBlock * nUsedBlockHeight,
146✔
2065
                            nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
2066
                        if (pabyLocalSrcDataStartLine == nullptr)
146✔
2067
                            return CE_Failure;
1✔
2068
                    }
2069
                }
2070

2071
                if (nCurOffset == 0)
10,743✔
2072
                {
2073
                    REACHED(38);
2074

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

2121
                        if (bByteOnly)
423,713✔
2122
                        {
2123
                            REACHED(41);
2124
                            for (int iBand = 0; iBand < nBandCount; ++iBand)
2,118,560✔
2125
                            {
2126
                                GByte *pabyLocalDataBand =
1,694,850✔
2127
                                    pabyLocalData + iBand * nBandSpace;
1,694,850✔
2128
                                const GByte *pabyLocalSrcDataBand =
1,694,850✔
2129
                                    pabyLocalSrcData + (panBandMap[iBand] - 1);
1,694,850✔
2130
                                *pabyLocalDataBand = *pabyLocalSrcDataBand;
1,694,850✔
2131
                            }
2132
                        }
2133
                        else
2134
                        {
2135
                            REACHED(42);
2136
                            for (int iBand = 0; iBand < nBandCount; ++iBand)
×
2137
                            {
2138
                                GByte *pabyLocalDataBand =
×
2139
                                    pabyLocalData + iBand * nBandSpace;
×
2140
                                const GByte *pabyLocalSrcDataBand =
×
2141
                                    pabyLocalSrcData +
2142
                                    (panBandMap[iBand] - 1) * nDTSize;
×
2143

2144
                                GDALCopyWords(pabyLocalSrcDataBand, eDataType,
×
2145
                                              0, pabyLocalDataBand, eBufType, 0,
2146
                                              1);
2147
                            }
2148
                        }
2149
                    }
2150
                }
2151
            }
2152

2153
            y += ychunk;
99✔
2154
        }
2155
    }
2156
    // cppcheck-suppress knownConditionTrueFalse
2157
    else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
228✔
2158
    // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
2159
    {
2160
        for (int iBand = 0; iBand < nBandCount; ++iBand)
452✔
2161
        {
2162
            GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
228✔
2163
            const int nBand = panBandMap[iBand];
228✔
2164
            auto poCurBand =
2165
                cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
228✔
2166
            int anSrcYOffset[256] = {0};
228✔
2167
            for (int y = 0; y < nBufYSize;)
1,392✔
2168
            {
2169
                const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
1,168✔
2170
                const int nSrcLine = static_cast<int>(dfYOffStart);
1,168✔
2171
                const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
1,168✔
2172
                const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
1,168✔
2173
                const int nBaseByteOffsetIm_nBlock =
1,168✔
2174
                    nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
1,168✔
2175
                int ychunk = 1;
1,168✔
2176
                int nLastSrcLineK = nSrcLine;
1,168✔
2177
                anSrcYOffset[0] = 0;
1,168✔
2178
                for (int k = 1; k < nBufYSize - y; ++k)
125,300✔
2179
                {
2180
                    const int nSrcLineK =
125,072✔
2181
                        nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
125,072✔
2182
                    const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
125,072✔
2183
                    if (k < 256)
125,072✔
2184
                        anSrcYOffset[k] =
80,072✔
2185
                            ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
80,072✔
2186
                            m_nBlockXSize * nBandsPerBlockDTSize;
80,072✔
2187
                    if (nBlockYOffK != m_nBlockYOff)
125,072✔
2188
                    {
2189
                        break;
940✔
2190
                    }
2191
                    ++ychunk;
124,132✔
2192
                    nLastSrcLineK = nSrcLineK;
124,132✔
2193
                }
2194
                const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
1,168✔
2195
                // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
2196

2197
                double dfSrcX = nXOff + 0.5 * dfSrcXInc;
1,168✔
2198
                int nCurBlockXOff = 0;
1,168✔
2199
                int nNextBlockXOff = 0;
1,168✔
2200
                toff_t nCurOffset = 0;
1,168✔
2201
                const GByte *pabyLocalSrcDataStartLine = nullptr;
1,168✔
2202
                for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
138,796✔
2203
                {
2204
                    int nSrcPixel = static_cast<int>(dfSrcX);
137,632✔
2205
                    if (nSrcPixel >= nNextBlockXOff)
137,632✔
2206
                    {
2207
                        const int nBlockXOff = nSrcPixel / m_nBlockXSize;
3,424✔
2208
                        nCurBlockXOff = nBlockXOff * m_nBlockXSize;
3,424✔
2209
                        nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
3,424✔
2210
                        const int nBlockId =
2211
                            poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
3,424✔
2212
                        nCurOffset = panOffsets[nBlockId];
3,424✔
2213
                        if (nCurOffset != 0)
3,424✔
2214
                        {
2215
                            pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
5,392✔
2216
                                nCurOffset + nBaseByteOffsetIm_nBlock,
2,696✔
2217
                                m_nBlockXSize * nBandsPerBlock *
2,696✔
2218
                                    nUsedBlockHeight,
2219
                                nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
2220
                            if (pabyLocalSrcDataStartLine == nullptr)
2,696✔
2221
                                return CE_Failure;
4✔
2222

2223
                            if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
2,692✔
2224
                            {
2225
                                REACHED(45);
2226
                                pabyLocalSrcDataStartLine +=
72✔
2227
                                    (nBand - 1) * nDTSize;
72✔
2228
                            }
2229
                            else
2230
                            {
2231
                                REACHED(46);
2232
                            }
2233
                        }
2234
                    }
2235

2236
                    if (nCurOffset == 0)
137,628✔
2237
                    {
2238
                        REACHED(47);
2239

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

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

2284
                            if (bByteOnly)
7,845,180✔
2285
                            {
2286
                                REACHED(50);
2287

2288
                                *pabyLocalData = *pabyLocalSrcData;
2,121,160✔
2289
                            }
2290
                            else
2291
                            {
2292
                                REACHED(51);
2293

2294
                                GDALCopyWords(pabyLocalSrcData, eDataType, 0,
5,724,020✔
2295
                                              pabyLocalData, eBufType, 0, 1);
2296
                            }
2297
                        }
2298
                    }
2299
                }
2300

2301
                y += ychunk;
1,164✔
2302
            }
2303
        }
2304
    }
2305
    else if (bUseContigImplementation)
971✔
2306
    {
2307
        // cppcheck-suppress knownConditionTrueFalse
2308
        if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
72✔
2309
        {
2310
            GByte *pabyData = static_cast<GByte *>(pData);
37✔
2311
            for (int y = 0; y < nBufYSize; ++y)
2,777✔
2312
            {
2313
                const int nSrcLine =
2,742✔
2314
                    nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
2,742✔
2315
                const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
2,742✔
2316
                const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
2,742✔
2317
                const int nBaseByteOffsetIm_nBlock =
2,742✔
2318
                    nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
2,742✔
2319

2320
                if (bNoXResampling)
2,742✔
2321
                {
2322
                    GByte *pabyLocalData = pabyData + y * nLineSpace;
2,535✔
2323
                    int nBlockXOff = nXOff / m_nBlockXSize;
2,535✔
2324
                    int nXOffsetInBlock = nXOff % m_nBlockXSize;
2,535✔
2325
                    int nBlockId =
2326
                        poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
2,535✔
2327

2328
                    int x = 0;
2,535✔
2329
                    while (x < nBufXSize)
12,372✔
2330
                    {
2331
                        const int nByteOffsetIm_nBlock =
9,838✔
2332
                            nBaseByteOffsetIm_nBlock +
2333
                            nXOffsetInBlock * nBandsPerBlockDTSize;
9,838✔
2334
                        const toff_t nCurOffset = panOffsets[nBlockId];
9,838✔
2335
                        const int nUsedBlockWidth = std::min(
9,838✔
2336
                            m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
9,838✔
2337

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

2421
                        nXOffsetInBlock = 0;
9,837✔
2422
                        ++nBlockXOff;
9,837✔
2423
                        ++nBlockId;
9,837✔
2424
                        x += nUsedBlockWidth;
9,837✔
2425
                    }
2426
                }
2427
                else  // Contig, tiled, potential resampling & data type change.
2428
                {
2429
                    const GByte *pabyLocalSrcDataStartLine = nullptr;
207✔
2430
                    GByte *pabyLocalData = pabyData + y * nLineSpace;
207✔
2431
                    double dfSrcX = nXOff + 0.5 * dfSrcXInc;
207✔
2432
                    int nCurBlockXOff = 0;
207✔
2433
                    int nNextBlockXOff = 0;
207✔
2434
                    toff_t nCurOffset = 0;
207✔
2435
                    for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
8,373✔
2436
                    {
2437
                        int nSrcPixel = static_cast<int>(dfSrcX);
8,167✔
2438
                        if (nSrcPixel >= nNextBlockXOff)
8,167✔
2439
                        {
2440
                            const int nBlockXOff = nSrcPixel / m_nBlockXSize;
611✔
2441
                            nCurBlockXOff = nBlockXOff * m_nBlockXSize;
611✔
2442
                            nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
611✔
2443
                            const int nBlockId = poFirstBand->ComputeBlockId(
611✔
2444
                                nBlockXOff, m_nBlockYOff);
2445
                            nCurOffset = panOffsets[nBlockId];
611✔
2446
                            if (nCurOffset != 0)
611✔
2447
                            {
2448
                                pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
726✔
2449
                                    nCurOffset + nBaseByteOffsetIm_nBlock,
363✔
2450
                                    m_nBlockXSize * nBandsPerBlock, nDTSize,
363✔
2451
                                    bIsByteSwapped, bIsComplex, nBlockId);
2452
                                if (pabyLocalSrcDataStartLine == nullptr)
363✔
2453
                                    return CE_Failure;
1✔
2454
                            }
2455
                        }
2456
                        const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
8,166✔
2457

2458
                        if (nCurOffset == 0)
8,166✔
2459
                        {
2460
                            REACHED(5);
2461
                            GDALCopyWords(&dfNoData, GDT_Float64, 0,
3,364✔
2462
                                          pabyLocalData, eBufType,
2463
                                          static_cast<int>(nBandSpace),
2464
                                          nBandCount);
2465
                            pabyLocalData += nPixelSpace;
3,364✔
2466
                        }
2467
                        else
2468
                        {
2469
                            const GByte *pabyLocalSrcData =
4,802✔
2470
                                pabyLocalSrcDataStartLine +
2471
                                nXOffsetInBlock * nBandsPerBlockDTSize;
4,802✔
2472

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

2522
                    if (bNoXResamplingNoTypeChange && nBands == nBandCount &&
1,545✔
2523
                        nPixelSpace == nBandsPerBlockDTSize)
936✔
2524
                    {
2525
                        REACHED(8);
2526
                        if (!oFetcher.FetchBytes(
693✔
2527
                                pabyLocalData,
2528
                                nCurOffset + nBaseByteOffsetIm_nBlock,
693✔
2529
                                nXSize * nBandsPerBlock, nDTSize,
2530
                                bIsByteSwapped, bIsComplex, nBlockId))
2531
                        {
2532
                            return CE_Failure;
1✔
2533
                        }
2534
                    }
2535
                    else
2536
                    {
2537
                        const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
1,704✔
2538
                            nCurOffset + nBaseByteOffsetIm_nBlock,
852✔
2539
                            nXSize * nBandsPerBlock, nDTSize, bIsByteSwapped,
2540
                            bIsComplex, nBlockId);
2541
                        if (pabyLocalSrcData == nullptr)
852✔
2542
                            return CE_Failure;
1✔
2543

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

2612
                    int nBaseByteOffsetIm_nBlock = nYOffsetIm_nBlock *
283,506✔
2613
                                                   m_nBlockXSize *
283,506✔
2614
                                                   nBandsPerBlockDTSize;
2615
                    if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
283,506✔
2616
                    {
2617
                        REACHED(12);
2618
                        nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
66,004✔
2619
                    }
2620
                    else
2621
                    {
2622
                        REACHED(13);
2623
                    }
2624

2625
                    if (bNoXResampling)
283,506✔
2626
                    {
2627
                        GByte *pabyLocalData = pabyData + y * nLineSpace;
67,404✔
2628
                        int nBlockXOff = nXOff / m_nBlockXSize;
67,404✔
2629
                        int nBlockId =
2630
                            poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
67,404✔
2631
                        int nXOffsetInBlock = nXOff % m_nBlockXSize;
67,404✔
2632

2633
                        int x = 0;
67,404✔
2634
                        while (x < nBufXSize)
331,986✔
2635
                        {
2636
                            const int nByteOffsetIm_nBlock =
264,592✔
2637
                                nBaseByteOffsetIm_nBlock +
2638
                                nXOffsetInBlock * nBandsPerBlockDTSize;
264,592✔
2639
                            const toff_t nCurOffset = panOffsets[nBlockId];
264,592✔
2640
                            const int nUsedBlockWidth = std::min(
264,592✔
2641
                                m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
264,592✔
2642
                            int nIters = nUsedBlockWidth;
264,592✔
2643

2644
                            if (nCurOffset == 0)
264,592✔
2645
                            {
2646
                                REACHED(16);
2647
                                GDALCopyWords(&dfNoData, GDT_Float64, 0,
52,038✔
2648
                                              pabyLocalData, eBufType,
2649
                                              static_cast<int>(nPixelSpace),
2650
                                              nIters);
2651
                                pabyLocalData += nIters * nPixelSpace;
52,038✔
2652
                            }
2653
                            else
2654
                            {
2655
                                if (bNoTypeChange &&
212,554✔
2656
                                    nPixelSpace == nBandsPerBlockDTSize)
177,871✔
2657
                                {
2658
                                    REACHED(17);
2659
                                    if (!oFetcher.FetchBytes(
84,112✔
2660
                                            pabyLocalData,
2661
                                            nCurOffset + nByteOffsetIm_nBlock,
84,112✔
2662
                                            (nIters - 1) * nBandsPerBlock + 1,
84,112✔
2663
                                            nDTSize, bIsByteSwapped, bIsComplex,
2664
                                            nBlockId))
2665
                                    {
2666
                                        return CE_Failure;
4✔
2667
                                    }
2668
                                    pabyLocalData += nIters * nPixelSpace;
84,108✔
2669
                                }
2670
                                else
2671
                                {
2672
                                    const GByte *pabyLocalSrcData =
256,884✔
2673
                                        oFetcher.FetchBytes(
2674
                                            nCurOffset + nByteOffsetIm_nBlock,
128,442✔
2675
                                            (nIters - 1) * nBandsPerBlock + 1,
128,442✔
2676
                                            nDTSize, bIsByteSwapped, bIsComplex,
2677
                                            nBlockId);
2678
                                    if (pabyLocalSrcData == nullptr)
128,442✔
2679
                                        return CE_Failure;
6✔
2680

2681
                                    REACHED(18);
2682
                                    GDALCopyWords(pabyLocalSrcData, eDataType,
128,436✔
2683
                                                  nBandsPerBlockDTSize,
2684
                                                  pabyLocalData, eBufType,
2685
                                                  static_cast<int>(nPixelSpace),
2686
                                                  nIters);
2687
                                    pabyLocalData += nIters * nPixelSpace;
128,436✔
2688
                                }
2689
                            }
2690

2691
                            nXOffsetInBlock = 0;
264,582✔
2692
                            ++nBlockXOff;
264,582✔
2693
                            ++nBlockId;
264,582✔
2694
                            x += nUsedBlockWidth;
264,582✔
2695
                        }
2696
                    }
2697
                    else
2698
                    {
2699
                        // Non-contig reading, tiled, potential resampling and
2700
                        // data type change.
2701

2702
                        const GByte *pabyLocalSrcDataStartLine = nullptr;
216,102✔
2703
                        GByte *pabyLocalData = pabyData + y * nLineSpace;
216,102✔
2704
                        double dfSrcX = nXOff + 0.5 * dfSrcXInc;
216,102✔
2705
                        int nCurBlockXOff = 0;
216,102✔
2706
                        int nNextBlockXOff = 0;
216,102✔
2707
                        toff_t nCurOffset = 0;
216,102✔
2708
                        for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
16,883,500✔
2709
                        {
2710
                            const int nSrcPixel = static_cast<int>(dfSrcX);
16,667,400✔
2711
                            if (nSrcPixel >= nNextBlockXOff)
16,667,400✔
2712
                            {
2713
                                const int nBlockXOff =
648,202✔
2714
                                    nSrcPixel / m_nBlockXSize;
648,202✔
2715
                                nCurBlockXOff = nBlockXOff * m_nBlockXSize;
648,202✔
2716
                                nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
648,202✔
2717
                                const int nBlockId = poCurBand->ComputeBlockId(
648,202✔
2718
                                    nBlockXOff, m_nBlockYOff);
2719
                                nCurOffset = panOffsets[nBlockId];
648,202✔
2720
                                if (nCurOffset != 0)
648,202✔
2721
                                {
2722
                                    pabyLocalSrcDataStartLine =
998,236✔
2723
                                        oFetcher.FetchBytes(
2724
                                            nCurOffset +
499,118✔
2725
                                                nBaseByteOffsetIm_nBlock,
499,118✔
2726
                                            m_nBlockXSize * nBandsPerBlock,
499,118✔
2727
                                            nDTSize, bIsByteSwapped, bIsComplex,
2728
                                            nBlockId);
2729
                                    if (pabyLocalSrcDataStartLine == nullptr)
499,118✔
2730
                                        return CE_Failure;
4✔
2731
                                }
2732
                            }
2733
                            const int nXOffsetInBlock =
16,667,400✔
2734
                                nSrcPixel - nCurBlockXOff;
2735

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

2749
                                REACHED(22);
2750
                                if (bByteOnly)
12,747,300✔
2751
                                {
2752
                                    *pabyLocalData = *pabyLocalSrcData;
5,192,440✔
2753
                                }
2754
                                else
2755
                                {
2756
                                    GDALCopyWords(pabyLocalSrcData, eDataType,
7,554,900✔
2757
                                                  0, pabyLocalData, eBufType, 0,
2758
                                                  1);
2759
                                }
2760
                                pabyLocalData += nPixelSpace;
12,747,300✔
2761
                            }
2762
                        }
2763
                    }
2764
                }
2765
            }
2766
        }
2767
        else  // Non-contig reading, striped.
2768
        {
2769
            for (int iBand = 0; iBand < nBandCount; ++iBand)
1,796✔
2770
            {
2771
                const int nBand = panBandMap[iBand];
1,324✔
2772
                GByte *pabyData =
1,324✔
2773
                    static_cast<GByte *>(pData) + iBand * nBandSpace;
1,324✔
2774
                for (int y = 0; y < nBufYSize; ++y)
356,944✔
2775
                {
2776
                    const int nSrcLine =
355,637✔
2777
                        nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
355,637✔
2778
                    const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
355,637✔
2779
                    const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
355,637✔
2780
                    int nBlockId = m_nBlockYOff;
355,637✔
2781
                    if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
355,637✔
2782
                    {
2783
                        REACHED(23);
2784
                        nBlockId += m_nBlocksPerBand * (nBand - 1);
282,397✔
2785
                    }
2786
                    else
2787
                    {
2788
                        REACHED(24);
2789
                    }
2790
                    const toff_t nCurOffset = panOffsets[nBlockId];
355,637✔
2791
                    if (nCurOffset == 0)
355,637✔
2792
                    {
2793
                        REACHED(25);
2794
                        GDALCopyWords(&dfNoData, GDT_Float64, 0,
62,846✔
2795
                                      pabyData + y * nLineSpace, eBufType,
62,846✔
2796
                                      static_cast<int>(nPixelSpace), nBufXSize);
2797
                    }
2798
                    else
2799
                    {
2800
                        int nBaseByteOffsetIm_nBlock =
292,791✔
2801
                            (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
292,791✔
2802
                            nBandsPerBlockDTSize;
2803
                        if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
292,791✔
2804
                            nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
43,815✔
2805

2806
                        GByte *pabyLocalData = pabyData + y * nLineSpace;
292,791✔
2807
                        if (bNoXResamplingNoTypeChange &&
292,791✔
2808
                            nPixelSpace == nBandsPerBlockDTSize)
56,217✔
2809
                        {
2810
                            REACHED(26);
2811
                            if (!oFetcher.FetchBytes(
26,844✔
2812
                                    pabyLocalData,
2813
                                    nCurOffset + nBaseByteOffsetIm_nBlock,
26,844✔
2814
                                    (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
26,844✔
2815
                                    bIsByteSwapped, bIsComplex, nBlockId))
2816
                            {
2817
                                return CE_Failure;
5✔
2818
                            }
2819
                        }
2820
                        else
2821
                        {
2822
                            const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
531,894✔
2823
                                nCurOffset + nBaseByteOffsetIm_nBlock,
265,947✔
2824
                                (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
265,947✔
2825
                                bIsByteSwapped, bIsComplex, nBlockId);
2826
                            if (pabyLocalSrcData == nullptr)
265,947✔
2827
                                return CE_Failure;
12✔
2828

2829
                            if (bNoXResamplingNoTypeChange)
265,935✔
2830
                            {
2831
                                REACHED(27);
2832
                                GDALCopyWords(pabyLocalSrcData, eDataType,
29,366✔
2833
                                              nBandsPerBlockDTSize,
2834
                                              pabyLocalData, eBufType,
2835
                                              static_cast<int>(nPixelSpace),
2836
                                              nBufXSize);
2837
                            }
2838
                            else if (bByteOnly)
236,569✔
2839
                            {
2840
                                REACHED(28);
2841
                                double dfSrcX = 0.5 * dfSrcXInc;
73,619✔
2842
                                for (int x = 0; x < nBufXSize;
5,778,430✔
2843
                                     ++x, dfSrcX += dfSrcXInc)
2844
                                {
2845
                                    const int nSrcPixelMinusXOff =
5,704,810✔
2846
                                        static_cast<int>(dfSrcX);
2847
                                    pabyLocalData[x * nPixelSpace] =
5,704,810✔
2848
                                        pabyLocalSrcData[nSrcPixelMinusXOff *
5,704,810✔
2849
                                                         nBandsPerBlockDTSize];
2850
                                }
2851
                            }
2852
                            else
2853
                            {
2854
                                REACHED(29);
2855
                                double dfSrcX = 0.5 * dfSrcXInc;
162,950✔
2856
                                for (int x = 0; x < nBufXSize;
12,817,000✔
2857
                                     ++x, dfSrcX += dfSrcXInc)
2858
                                {
2859
                                    const int nSrcPixelMinusXOff =
12,654,100✔
2860
                                        static_cast<int>(dfSrcX);
2861
                                    GDALCopyWords(pabyLocalSrcData +
12,654,100✔
2862
                                                      nSrcPixelMinusXOff *
12,654,100✔
2863
                                                          nBandsPerBlockDTSize,
2864
                                                  eDataType, 0,
2865
                                                  pabyLocalData +
12,654,100✔
2866
                                                      x * nPixelSpace,
12,654,100✔
2867
                                                  eBufType, 0, 1);
2868
                                }
2869
                            }
2870
                        }
2871
                    }
2872
                }
2873
            }
2874
        }
2875
    }
2876

2877
    return CE_None;
1,691✔
2878
}
2879

2880
/************************************************************************/
2881
/*                           DirectIO()                                 */
2882
/************************************************************************/
2883

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

2895
/************************************************************************/
2896
/*                           DirectIO()                                 */
2897
/************************************************************************/
2898

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

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

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

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

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

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

2974
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
2975
    if (eAccess == GA_Update)
110✔
2976
    {
2977
        FlushCache(false);
×
2978
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
×
2979
    }
2980

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

2995
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
55✔
2996
        FetchBufferDirectIO oFetcher(fp, m_pTempBufferForCommonDirectIO,
2997
                                     nTempBufferForCommonDirectIOSize);
55✔
2998

2999
        return CommonDirectIOClassic(oFetcher, nXOff, nYOff, nXSize, nYSize,
55✔
3000
                                     pData, nBufXSize, nBufYSize, eBufType,
3001
                                     nBandCount, panBandMap, nPixelSpace,
3002
                                     nLineSpace, nBandSpace);
55✔
3003
    }
3004

3005
    // Get strip offsets.
3006
    toff_t *panTIFFOffsets = nullptr;
55✔
3007
    if (!TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets) ||
110✔
3008
        panTIFFOffsets == nullptr)
55✔
3009
    {
3010
        return CE_Failure;
×
3011
    }
3012

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

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

3047
    // Prepare data extraction.
3048
    const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
55✔
3049

3050
    for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
2,312✔
3051
    {
3052
        ppData[iLine] = static_cast<GByte *>(pTmpBuffer) +
2,257✔
3053
                        static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
2,257✔
3054
        int nSrcLine = 0;
2,257✔
3055
        if (nBufYSize < nYSize)  // Sub-sampling in y.
2,257✔
3056
            nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
164✔
3057
        else
3058
            nSrcLine = nYOff + iLine;
2,093✔
3059

3060
        const int nBlockXOff = 0;
2,257✔
3061
        const int nBlockYOff = nSrcLine / m_nBlockYSize;
2,257✔
3062
        const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
2,257✔
3063
        const int nBlockId =
3064
            poProtoBand->ComputeBlockId(nBlockXOff, nBlockYOff);
2,257✔
3065

3066
        panOffsets[iLine] = panTIFFOffsets[nBlockId];
2,257✔
3067
        if (panOffsets[iLine] == 0)  // We don't support sparse files.
2,257✔
3068
            eErr = -1;
27✔
3069

3070
        panOffsets[iLine] +=
2,257✔
3071
            (nXOff +
2,257✔
3072
             static_cast<vsi_l_offset>(nYOffsetInBlock) * m_nBlockXSize) *
2,257✔
3073
            nSrcPixelSize;
2,257✔
3074
        panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
2,257✔
3075
    }
3076

3077
    // Extract data from the file.
3078
    if (eErr == CE_None)
55✔
3079
    {
3080
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
28✔
3081
        const int nRet =
3082
            VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
28✔
3083
        if (nRet != 0)
28✔
3084
            eErr = CE_Failure;
3✔
3085
    }
3086

3087
    // Byte-swap if necessary.
3088
    if (eErr == CE_None && TIFFIsByteSwapped(m_hTIFF))
55✔
3089
    {
3090
        for (int iLine = 0; iLine < nReqYSize; ++iLine)
×
3091
        {
3092
            if (GDALDataTypeIsComplex(eDataType))
×
3093
                GDALSwapWords(ppData[iLine], nDTSize / 2,
×
3094
                              2 * nReqXSize * nContigBands, nDTSize / 2);
×
3095
            else
3096
                GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
×
3097
                              nDTSize);
3098
        }
3099
    }
3100

3101
    // Over-sampling/sub-sampling and/or data type conversion.
3102
    const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
55✔
3103
    if (eErr == CE_None && pTmpBuffer != nullptr)
55✔
3104
    {
3105
        for (int iY = 0; iY < nBufYSize; ++iY)
7,462✔
3106
        {
3107
            const int iSrcY = nBufYSize <= nYSize
14,874✔
3108
                                  ? iY
7,437✔
3109
                                  : static_cast<int>((iY + 0.5) * dfSrcYInc);
5,832✔
3110
            // Optimization: no resampling, no data type change, number of
3111
            // bands requested == number of bands and buffer is packed
3112
            // pixel-interleaved.
3113
            if (nBufXSize == nXSize && nContigBands == nBandCount &&
7,437✔
3114
                eDataType == eBufType && nBandSpace == nDTSize &&
786✔
3115
                nPixelSpace == nBandCount * nBandSpace)
474✔
3116
            {
3117
                memcpy(static_cast<GByte *>(pData) + iY * nLineSpace,
312✔
3118
                       ppData[iSrcY],
312✔
3119
                       static_cast<size_t>(nReqXSize * nPixelSpace));
312✔
3120
            }
3121
            // Other optimization: no resampling, no data type change,
3122
            // data type is Byte/Int8.
3123
            else if (nBufXSize == nXSize && eDataType == eBufType &&
7,125✔
3124
                     (eDataType == GDT_Byte || eDataType == GDT_Int8))
×
3125
            {
3126
                GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]);
808✔
3127
                GByte *pabyDstData =
808✔
3128
                    static_cast<GByte *>(pData) + iY * nLineSpace;
808✔
3129
                if (nBandSpace == 1 && nPixelSpace > nBandCount)
808✔
3130
                {
3131
                    // Buffer is pixel-interleaved (with some stridding
3132
                    // between pixels).
3133
                    CopyContigByteMultiBand(
324✔
3134
                        pabySrcData, nSrcPixelSize, pabyDstData,
3135
                        static_cast<int>(nPixelSpace), nBufXSize, nBandCount);
3136
                }
3137
                else
3138
                {
3139
                    for (int iBand = 0; iBand < nBandCount; ++iBand)
2,248✔
3140
                    {
3141
                        GDALCopyWords(
1,764✔
3142
                            pabySrcData + iBand, GDT_Byte, nSrcPixelSize,
1,764✔
3143
                            pabyDstData + iBand * nBandSpace, GDT_Byte,
1,764✔
3144
                            static_cast<int>(nPixelSpace), nBufXSize);
3145
                    }
3146
                }
808✔
3147
            }
3148
            else  // General case.
3149
            {
3150
                for (int iBand = 0; iBand < nBandCount; ++iBand)
31,585✔
3151
                {
3152
                    GByte *pabySrcData =
25,268✔
3153
                        static_cast<GByte *>(ppData[iSrcY]) + iBand * nDTSize;
25,268✔
3154
                    GByte *pabyDstData = static_cast<GByte *>(pData) +
25,268✔
3155
                                         iBand * nBandSpace + iY * nLineSpace;
25,268✔
3156
                    if ((eDataType == GDT_Byte && eBufType == GDT_Byte) ||
25,268✔
3157
                        (eDataType == GDT_Int8 && eBufType == GDT_Int8))
×
3158
                    {
3159
                        double dfSrcX = 0.5 * dfSrcXInc;
23,972✔
3160
                        for (int iX = 0; iX < nBufXSize;
1,718,820✔
3161
                             ++iX, dfSrcX += dfSrcXInc)
1,694,850✔
3162
                        {
3163
                            int iSrcX = static_cast<int>(dfSrcX);
1,694,850✔
3164
                            pabyDstData[iX * nPixelSpace] =
1,694,850✔
3165
                                pabySrcData[iSrcX * nSrcPixelSize];
1,694,850✔
3166
                        }
23,972✔
3167
                    }
3168
                    else
3169
                    {
3170
                        double dfSrcX = 0.5 * dfSrcXInc;
1,296✔
3171
                        for (int iX = 0; iX < nBufXSize;
106,272✔
3172
                             ++iX, dfSrcX += dfSrcXInc)
104,976✔
3173
                        {
3174
                            int iSrcX = static_cast<int>(dfSrcX);
104,976✔
3175
                            GDALCopyWords(pabySrcData + iSrcX * nSrcPixelSize,
104,976✔
3176
                                          eDataType, 0,
3177
                                          pabyDstData + iX * nPixelSpace,
104,976✔
3178
                                          eBufType, 0, 1);
3179
                        }
3180
                    }
3181
                }
3182
            }
3183
        }
3184
    }
3185

3186
    CPLFree(pTmpBuffer);
55✔
3187
    CPLFree(ppData);
55✔
3188
    CPLFree(panOffsets);
55✔
3189
    CPLFree(panSizes);
55✔
3190

3191
    return eErr;
55✔
3192
}
3193

3194
/************************************************************************/
3195
/*                             ReadStrile()                             */
3196
/************************************************************************/
3197

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

3231
    // For debugging
3232
    if (m_poBaseDS)
2,125,030✔
3233
        m_poBaseDS->m_bHasUsedReadEncodedAPI = true;
3,485✔
3234
    else
3235
        m_bHasUsedReadEncodedAPI = true;
2,121,550✔
3236

3237
#if 0
3238
    // Can be useful to test TIFFReadFromUserBuffer() for local files
3239
    VSILFILE* fpTIF = VSI_TIFFGetVSILFile(TIFFClientdata( m_hTIFF ));
3240
    std::vector<GByte> tmp(TIFFGetStrileByteCount(m_hTIFF, nBlockId));
3241
    VSIFSeekL(fpTIF, TIFFGetStrileOffset(m_hTIFF, nBlockId), SEEK_SET);
3242
    VSIFReadL(&tmp[0], 1, TIFFGetStrileByteCount(m_hTIFF, nBlockId), fpTIF);
3243
    if( !TIFFReadFromUserBuffer( m_hTIFF, nBlockId,
3244
                                &tmp[0], tmp.size(),
3245
                                pOutputBuffer, nBlockReqSize ) )
3246
    {
3247
        return false;
3248
    }
3249
#else
3250
    // Set to 1 to allow GTiffErrorHandler to implement limitation on error
3251
    // messages
3252
    GTIFFGetThreadLocalLibtiffError() = 1;
2,125,030✔
3253
    if (TIFFIsTiled(m_hTIFF))
2,125,030✔
3254
    {
3255
        if (TIFFReadEncodedTile(m_hTIFF, nBlockId, pOutputBuffer,
29,882✔
3256
                                nBlockReqSize) == -1 &&
29,911✔
3257
            !m_bIgnoreReadErrors)
30✔
3258
        {
3259
            CPLError(CE_Failure, CPLE_AppDefined,
30✔
3260
                     "TIFFReadEncodedTile() failed.");
3261
            GTIFFGetThreadLocalLibtiffError() = 0;
30✔
3262
            return false;
30✔
3263
        }
3264
    }
3265
    else
3266
    {
3267
        if (TIFFReadEncodedStrip(m_hTIFF, nBlockId, pOutputBuffer,
2,095,150✔
3268
                                 nBlockReqSize) == -1 &&
2,095,220✔
3269
            !m_bIgnoreReadErrors)
69✔
3270
        {
3271
            CPLError(CE_Failure, CPLE_AppDefined,
68✔
3272
                     "TIFFReadEncodedStrip() failed.");
3273
            GTIFFGetThreadLocalLibtiffError() = 0;
68✔
3274
            return false;
68✔
3275
        }
3276
    }
3277
    GTIFFGetThreadLocalLibtiffError() = 0;
2,124,930✔
3278
#endif
3279
    return true;
2,124,930✔
3280
}
3281

3282
/************************************************************************/
3283
/*                            LoadBlockBuf()                            */
3284
/*                                                                      */
3285
/*      Load working block buffer with request block (tile/strip).      */
3286
/************************************************************************/
3287

3288
CPLErr GTiffDataset::LoadBlockBuf(int nBlockId, bool bReadFromDisk)
230,184✔
3289

3290
{
3291
    if (m_nLoadedBlock == nBlockId && m_pabyBlockBuf != nullptr)
230,184✔
3292
        return CE_None;
139,799✔
3293

3294
    /* -------------------------------------------------------------------- */
3295
    /*      If we have a dirty loaded block, flush it out first.            */
3296
    /* -------------------------------------------------------------------- */
3297
    if (m_nLoadedBlock != -1 && m_bLoadedBlockDirty)
90,385✔
3298
    {
3299
        const CPLErr eErr = FlushBlockBuf();
4,577✔
3300
        if (eErr != CE_None)
4,577✔
3301
            return eErr;
×
3302
    }
3303

3304
    /* -------------------------------------------------------------------- */
3305
    /*      Get block size.                                                 */
3306
    /* -------------------------------------------------------------------- */
3307
    const GPtrDiff_t nBlockBufSize = static_cast<GPtrDiff_t>(
90,385✔
3308
        TIFFIsTiled(m_hTIFF) ? TIFFTileSize(m_hTIFF) : TIFFStripSize(m_hTIFF));
90,385✔
3309
    if (!nBlockBufSize)
90,383✔
3310
    {
3311
        ReportError(CE_Failure, CPLE_AppDefined,
×
3312
                    "Bogus block size; unable to allocate a buffer.");
3313
        return CE_Failure;
×
3314
    }
3315

3316
    /* -------------------------------------------------------------------- */
3317
    /*      Allocate a temporary buffer for this strip.                     */
3318
    /* -------------------------------------------------------------------- */
3319
    if (m_pabyBlockBuf == nullptr)
90,383✔
3320
    {
3321
        m_pabyBlockBuf =
7,107✔
3322
            static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockBufSize));
7,107✔
3323
        if (m_pabyBlockBuf == nullptr)
7,107✔
3324
        {
3325
            return CE_Failure;
1✔
3326
        }
3327
    }
3328

3329
    if (m_nLoadedBlock == nBlockId)
90,382✔
3330
        return CE_None;
4,788✔
3331

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

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

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

3365
    if (nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize &&
51,581✔
3366
        !(m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF)))
1,245✔
3367
    {
3368
        nBlockReqSize =
1,242✔
3369
            (nBlockBufSize / m_nBlockYSize) *
1,242✔
3370
            (m_nBlockYSize -
1,242✔
3371
             static_cast<int>(
3372
                 (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
1,242✔
3373
                 nRasterYSize));
1,242✔
3374
        memset(m_pabyBlockBuf, 0, nBlockBufSize);
1,242✔
3375
    }
3376

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

3392
    /* -------------------------------------------------------------------- */
3393
    /*      Load the block, if it isn't our current block.                  */
3394
    /* -------------------------------------------------------------------- */
3395
    CPLErr eErr = CE_None;
49,541✔
3396

3397
    if (!ReadStrile(nBlockId, m_pabyBlockBuf, nBlockReqSize))
49,541✔
3398
    {
3399
        memset(m_pabyBlockBuf, 0, nBlockBufSize);
19✔
3400
        eErr = CE_Failure;
19✔
3401
    }
3402

3403
    if (eErr == CE_None)
49,541✔
3404
    {
3405
        if (m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF) &&
50,332✔
3406
            nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize)
810✔
3407
        {
3408
            const auto nValidBytes =
3✔
3409
                (nBlockBufSize / m_nBlockYSize) *
3✔
3410
                (m_nBlockYSize -
3✔
3411
                 static_cast<int>(
3412
                     (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
3✔
3413
                     nRasterYSize));
3✔
3414
            // Zero-out unused area
3415
            memset(m_pabyBlockBuf + nValidBytes, 0,
3✔
3416
                   nBlockBufSize - nValidBytes);
3✔
3417
        }
3418

3419
        m_nLoadedBlock = nBlockId;
49,522✔
3420
    }
3421
    else
3422
    {
3423
        m_nLoadedBlock = -1;
19✔
3424
    }
3425
    m_bLoadedBlockDirty = false;
49,541✔
3426

3427
    return eErr;
49,541✔
3428
}
3429

3430
/************************************************************************/
3431
/*                              Identify()                              */
3432
/************************************************************************/
3433

3434
int GTiffDataset::Identify(GDALOpenInfo *poOpenInfo)
113,062✔
3435

3436
{
3437
    const char *pszFilename = poOpenInfo->pszFilename;
113,062✔
3438
    if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
113,062✔
3439
    {
3440
        pszFilename += strlen("GTIFF_RAW:");
20✔
3441
        GDALOpenInfo oOpenInfo(pszFilename, poOpenInfo->eAccess);
40✔
3442
        return Identify(&oOpenInfo);
20✔
3443
    }
3444

3445
    /* -------------------------------------------------------------------- */
3446
    /*      We have a special hook for handling opening a specific          */
3447
    /*      directory of a TIFF file.                                       */
3448
    /* -------------------------------------------------------------------- */
3449
    if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
113,042✔
3450
        return TRUE;
50✔
3451

3452
    /* -------------------------------------------------------------------- */
3453
    /*      First we check to see if the file has the expected header       */
3454
    /*      bytes.                                                          */
3455
    /* -------------------------------------------------------------------- */
3456
    if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 2)
112,992✔
3457
        return FALSE;
56,989✔
3458

3459
    if ((poOpenInfo->pabyHeader[0] != 'I' ||
56,003✔
3460
         poOpenInfo->pabyHeader[1] != 'I') &&
46,852✔
3461
        (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
9,171✔
3462
        return FALSE;
8,903✔
3463

3464
    if ((poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0) &&
47,100✔
3465
        (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0) &&
578✔
3466
        (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0) &&
332✔
3467
        (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
20✔
3468
        return FALSE;
×
3469

3470
    return TRUE;
47,100✔
3471
}
3472

3473
/************************************************************************/
3474
/*                          GTIFFExtendMemoryFile()                     */
3475
/************************************************************************/
3476

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

3504
/************************************************************************/
3505
/*                         GTIFFMakeBufferedStream()                    */
3506
/************************************************************************/
3507

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

3718
    return true;
7✔
3719
}
3720

3721
/************************************************************************/
3722
/*                       AssociateExternalMask()                        */
3723
/************************************************************************/
3724

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

3757
/************************************************************************/
3758
/*                                Open()                                */
3759
/************************************************************************/
3760

3761
GDALDataset *GTiffDataset::Open(GDALOpenInfo *poOpenInfo)
23,309✔
3762

3763
{
3764
    const char *pszFilename = poOpenInfo->pszFilename;
23,309✔
3765

3766
    /* -------------------------------------------------------------------- */
3767
    /*      Check if it looks like a TIFF file.                             */
3768
    /* -------------------------------------------------------------------- */
3769
    if (!Identify(poOpenInfo))
23,309✔
3770
        return nullptr;
×
3771

3772
    bool bAllowRGBAInterface = true;
23,304✔
3773
    if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
23,304✔
3774
    {
3775
        bAllowRGBAInterface = false;
10✔
3776
        pszFilename += strlen("GTIFF_RAW:");
10✔
3777
    }
3778

3779
    /* -------------------------------------------------------------------- */
3780
    /*      We have a special hook for handling opening a specific          */
3781
    /*      directory of a TIFF file.                                       */
3782
    /* -------------------------------------------------------------------- */
3783
    if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
23,304✔
3784
        return OpenDir(poOpenInfo);
25✔
3785

3786
    GTiffOneTimeInit();
23,279✔
3787

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

3816
    // Store errors/warnings and emit them later.
3817
    TIFF *l_hTIFF;
3818
    CPLErrorAccumulator oErrorAccumulator;
46,563✔
3819
    {
3820
        auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
23,278✔
3821
        CPL_IGNORE_RET_VAL(oAccumulator);
23,281✔
3822
        CPLSetCurrentErrorHandlerCatchDebug(FALSE);
23,276✔
3823
        const bool bDeferStrileLoading = CPLTestBool(
23,275✔
3824
            CPLGetConfigOption("GTIFF_USE_DEFER_STRILE_LOADING", "YES"));
3825
        l_hTIFF = VSI_TIFFOpen(
23,282✔
3826
            pszFilename,
3827
            poOpenInfo->eAccess == GA_ReadOnly
23,282✔
3828
                ? ((bStreaming || !bDeferStrileLoading) ? "rC" : "rDOC")
22,494✔
3829
                : (!bDeferStrileLoading ? "r+C" : "r+DC"),
788✔
3830
            poOpenInfo->fpL);
3831
    };
3832

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

3845
    if (l_hTIFF == nullptr)
23,267✔
3846
        return nullptr;
2✔
3847

3848
    uint32_t nXSize = 0;
23,265✔
3849
    TIFFGetField(l_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
23,265✔
3850
    uint32_t nYSize = 0;
23,274✔
3851
    TIFFGetField(l_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
23,274✔
3852

3853
    if (nXSize > INT_MAX || nYSize > INT_MAX)
23,274✔
3854
    {
3855
        // GDAL only supports signed 32bit dimensions.
3856
        ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
5✔
3857
                    "Too large image size: %u x %u", nXSize, nYSize);
3858
        XTIFFClose(l_hTIFF);
1✔
3859
        return nullptr;
1✔
3860
    }
3861

3862
    uint16_t l_nCompression = 0;
23,269✔
3863
    if (!TIFFGetField(l_hTIFF, TIFFTAG_COMPRESSION, &(l_nCompression)))
23,269✔
3864
        l_nCompression = COMPRESSION_NONE;
×
3865

3866
    /* -------------------------------------------------------------------- */
3867
    /*      Create a corresponding GDALDataset.                             */
3868
    /* -------------------------------------------------------------------- */
3869
    GTiffDataset *poDS = new GTiffDataset();
23,266✔
3870
    poDS->SetDescription(pszFilename);
23,276✔
3871
    poDS->m_pszFilename = CPLStrdup(pszFilename);
23,271✔
3872
    poDS->m_fpL = poOpenInfo->fpL;
23,277✔
3873
    poOpenInfo->fpL = nullptr;
23,277✔
3874
    poDS->m_bStreamingIn = bStreaming;
23,277✔
3875
    poDS->m_nCompression = l_nCompression;
23,277✔
3876

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

3948
    // In the case of GDAL_DISABLE_READDIR_ON_OPEN = NO / EMPTY_DIR
3949
    if (poOpenInfo->AreSiblingFilesLoaded() &&
23,431✔
3950
        CSLCount(poOpenInfo->GetSiblingFiles()) <= 1)
157✔
3951
    {
3952
        poDS->oOvManager.TransferSiblingFiles(
61✔
3953
            CSLDuplicate(poOpenInfo->GetSiblingFiles()));
61✔
3954
        poDS->m_bHasGotSiblingFiles = true;
61✔
3955
    }
3956

3957
    // Should be capped by 257, to avoid 65535 / m_nColorTableMultiplier to overflow 255
3958
    poDS->m_nColorTableMultiplier = std::max(
23,257✔
3959
        0, std::min(257,
69,790✔
3960
                    atoi(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
23,268✔
3961
                                              "COLOR_TABLE_MULTIPLIER", "0"))));
23,265✔
3962

3963
    if (poDS->OpenOffset(l_hTIFF, TIFFCurrentDirOffset(l_hTIFF),
23,257✔
3964
                         poOpenInfo->eAccess, bAllowRGBAInterface,
3965
                         true) != CE_None)
23,270✔
3966
    {
3967
        delete poDS;
9✔
3968
        return nullptr;
9✔
3969
    }
3970

3971
    // Do we want blocks that are set to zero and that haven't yet being
3972
    // allocated as tile/strip to remain implicit?
3973
    if (CPLFetchBool(poOpenInfo->papszOpenOptions, "SPARSE_OK", false))
23,261✔
3974
        poDS->m_bWriteEmptyTiles = false;
53✔
3975

3976
    poDS->InitCreationOrOpenOptions(poOpenInfo->eAccess == GA_Update,
23,258✔
3977
                                    poOpenInfo->papszOpenOptions);
23,258✔
3978

3979
    poDS->m_bLoadPam = true;
23,255✔
3980
    poDS->m_bColorProfileMetadataChanged = false;
23,255✔
3981
    poDS->m_bMetadataChanged = false;
23,255✔
3982
    poDS->m_bGeoTIFFInfoChanged = false;
23,255✔
3983
    poDS->m_bNoDataChanged = false;
23,255✔
3984
    poDS->m_bForceUnsetGTOrGCPs = false;
23,255✔
3985
    poDS->m_bForceUnsetProjection = false;
23,255✔
3986

3987
    // Used by GTIFFBuildOverviewsEx() for the COG driver
3988
    const char *pszMaskOverviewDS = CSLFetchNameValue(
46,513✔
3989
        poOpenInfo->papszOpenOptions, "MASK_OVERVIEW_DATASET");
23,255✔
3990
    if (pszMaskOverviewDS)
23,258✔
3991
    {
3992
        poDS->m_poMaskExtOvrDS.reset(GDALDataset::Open(
9✔
3993
            pszMaskOverviewDS, GDAL_OF_RASTER | GDAL_OF_INTERNAL));
3994
        if (!poDS->m_poMaskExtOvrDS || !poDS->AssociateExternalMask())
9✔
3995
        {
3996
            CPLDebug("GTiff",
×
3997
                     "Association with external mask overview file failed");
3998
        }
3999
    }
4000

4001
    /* -------------------------------------------------------------------- */
4002
    /*      Initialize info for external overviews.                         */
4003
    /* -------------------------------------------------------------------- */
4004
    poDS->oOvManager.Initialize(poDS, poOpenInfo, pszFilename);
23,258✔
4005

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

4014
    return poDS;
23,267✔
4015
}
4016

4017
/************************************************************************/
4018
/*                      GTiffDatasetSetAreaOrPointMD()                  */
4019
/************************************************************************/
4020

4021
static void GTiffDatasetSetAreaOrPointMD(GTIF *hGTIF,
13,452✔
4022
                                         GDALMultiDomainMetadata &m_oGTiffMDMD)
4023
{
4024
    // Is this a pixel-is-point dataset?
4025
    unsigned short nRasterType = 0;
13,452✔
4026

4027
    if (GDALGTIFKeyGetSHORT(hGTIF, GTRasterTypeGeoKey, &nRasterType, 0, 1) == 1)
13,452✔
4028
    {
4029
        if (nRasterType == static_cast<short>(RasterPixelIsPoint))
8,202✔
4030
            m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT,
235✔
4031
                                         GDALMD_AOP_POINT);
4032
        else
4033
            m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA);
7,967✔
4034
    }
4035
}
13,451✔
4036

4037
/************************************************************************/
4038
/*                         LoadMDAreaOrPoint()                          */
4039
/************************************************************************/
4040

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

4045
void GTiffDataset::LoadMDAreaOrPoint()
15,969✔
4046
{
4047
    if (m_bLookedForProjection || m_bLookedForMDAreaOrPoint ||
16,981✔
4048
        m_oGTiffMDMD.GetMetadataItem(GDALMD_AREA_OR_POINT) != nullptr)
1,012✔
4049
        return;
14,957✔
4050

4051
    m_bLookedForMDAreaOrPoint = true;
1,012✔
4052

4053
    GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
1,012✔
4054

4055
    if (!hGTIF)
1,012✔
4056
    {
4057
        ReportError(CE_Warning, CPLE_AppDefined,
×
4058
                    "GeoTIFF tags apparently corrupt, they are being ignored.");
4059
    }
4060
    else
4061
    {
4062
        GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
1,012✔
4063

4064
        GTIFFree(hGTIF);
1,012✔
4065
    }
4066
}
4067

4068
/************************************************************************/
4069
/*                         LookForProjection()                          */
4070
/************************************************************************/
4071

4072
void GTiffDataset::LookForProjection()
329,957✔
4073

4074
{
4075
    if (m_bLookedForProjection)
329,957✔
4076
        return;
317,510✔
4077

4078
    m_bLookedForProjection = true;
12,447✔
4079

4080
    IdentifyAuthorizedGeoreferencingSources();
12,447✔
4081

4082
    m_oSRS.Clear();
12,447✔
4083

4084
    std::set<signed char> aoSetPriorities;
24,894✔
4085
    if (m_nINTERNALGeorefSrcIndex >= 0)
12,447✔
4086
        aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
12,440✔
4087
    if (m_nXMLGeorefSrcIndex >= 0)
12,447✔
4088
        aoSetPriorities.insert(m_nXMLGeorefSrcIndex);
12,410✔
4089
    for (const auto nIndex : aoSetPriorities)
37,296✔
4090
    {
4091
        if (m_nINTERNALGeorefSrcIndex == nIndex)
24,849✔
4092
        {
4093
            LookForProjectionFromGeoTIFF();
12,440✔
4094
        }
4095
        else if (m_nXMLGeorefSrcIndex == nIndex)
12,409✔
4096
        {
4097
            LookForProjectionFromXML();
12,410✔
4098
        }
4099
    }
4100
}
4101

4102
/************************************************************************/
4103
/*                      LookForProjectionFromGeoTIFF()                  */
4104
/************************************************************************/
4105

4106
void GTiffDataset::LookForProjectionFromGeoTIFF()
12,440✔
4107
{
4108
    /* -------------------------------------------------------------------- */
4109
    /*      Capture the GeoTIFF projection, if available.                   */
4110
    /* -------------------------------------------------------------------- */
4111

4112
    GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
12,440✔
4113

4114
    if (!hGTIF)
12,440✔
4115
    {
4116
        ReportError(CE_Warning, CPLE_AppDefined,
×
4117
                    "GeoTIFF tags apparently corrupt, they are being ignored.");
4118
    }
4119
    else
4120
    {
4121
        GTIFDefn *psGTIFDefn = GTIFAllocDefn();
12,440✔
4122

4123
        bool bHasErrorBefore = CPLGetLastErrorType() != 0;
12,440✔
4124
        // Collect (PROJ) error messages and remit them later as warnings
4125
        int ret;
4126
        CPLErrorAccumulator oErrorAccumulator;
24,879✔
4127
        {
4128
            auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
12,440✔
4129
            ret = GTIFGetDefn(hGTIF, psGTIFDefn);
12,440✔
4130
        }
4131

4132
        bool bWarnAboutEllipsoid = true;
12,440✔
4133

4134
        if (ret)
12,440✔
4135
        {
4136
            auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
15,526✔
4137

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

4148
            OGRSpatialReferenceH hSRS = GTIFGetOGISDefnAsOSR(hGTIF, psGTIFDefn);
7,763✔
4149

4150
            if (hSRS)
7,763✔
4151
            {
4152
                CPLFree(m_pszXMLFilename);
7,763✔
4153
                m_pszXMLFilename = nullptr;
7,763✔
4154

4155
                m_oSRS = *(OGRSpatialReference::FromHandle(hSRS));
7,763✔
4156
                OSRDestroySpatialReference(hSRS);
7,763✔
4157
            }
4158
        }
4159

4160
        std::set<std::string> oSetErrorMsg;
24,880✔
4161
        for (const auto &oError : oErrorAccumulator.GetErrors())
12,451✔
4162
        {
4163
            if (!bWarnAboutEllipsoid &&
13✔
4164
                oError.msg.find("ellipsoid not found") != std::string::npos)
1✔
4165
            {
4166
                continue;
1✔
4167
            }
4168

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

4179
        if (!bHasErrorBefore && oSetErrorMsg.empty())
12,440✔
4180
        {
4181
            CPLErrorReset();
12,370✔
4182
        }
4183

4184
        if (ret && m_oSRS.IsCompound())
12,439✔
4185
        {
4186
            const char *pszVertUnit = nullptr;
35✔
4187
            m_oSRS.GetTargetLinearUnits("COMPD_CS|VERT_CS", &pszVertUnit);
35✔
4188
            if (pszVertUnit && !EQUAL(pszVertUnit, "unknown"))
35✔
4189
            {
4190
                CPLFree(m_pszVertUnit);
35✔
4191
                m_pszVertUnit = CPLStrdup(pszVertUnit);
35✔
4192
            }
4193

4194
            int versions[3];
4195
            GTIFDirectoryInfo(hGTIF, versions, nullptr);
35✔
4196

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

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

4209
                m_oSRS.StripVertical();
10✔
4210
            }
4211
        }
4212

4213
        GTIFFreeDefn(psGTIFDefn);
12,439✔
4214

4215
        GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
12,439✔
4216

4217
        GTIFFree(hGTIF);
12,440✔
4218
    }
4219
}
12,439✔
4220

4221
/************************************************************************/
4222
/*                      LookForProjectionFromXML()                      */
4223
/************************************************************************/
4224

4225
void GTiffDataset::LookForProjectionFromXML()
12,410✔
4226
{
4227
    CSLConstList papszSiblingFiles = GetSiblingFiles();
12,410✔
4228

4229
    if (!GDALCanFileAcceptSidecarFile(m_pszFilename))
12,410✔
4230
        return;
12,407✔
4231

4232
    const std::string osXMLFilenameLowerCase =
4233
        CPLResetExtensionSafe(m_pszFilename, "xml");
12,409✔
4234

4235
    CPLString osXMLFilename;
12,409✔
4236
    if (papszSiblingFiles &&
24,789✔
4237
        GDALCanReliablyUseSiblingFileList(osXMLFilenameLowerCase.c_str()))
12,379✔
4238
    {
4239
        const int iSibling = CSLFindString(
12,379✔
4240
            papszSiblingFiles, CPLGetFilename(osXMLFilenameLowerCase.c_str()));
4241
        if (iSibling >= 0)
12,380✔
4242
        {
4243
            osXMLFilename = m_pszFilename;
4✔
4244
            osXMLFilename.resize(strlen(m_pszFilename) -
8✔
4245
                                 strlen(CPLGetFilename(m_pszFilename)));
4✔
4246
            osXMLFilename += papszSiblingFiles[iSibling];
4✔
4247
        }
4248
        else
4249
        {
4250
            return;
12,376✔
4251
        }
4252
    }
4253

4254
    if (osXMLFilename.empty())
35✔
4255
    {
4256
        VSIStatBufL sStatBuf;
4257
        bool bGotXML = VSIStatExL(osXMLFilenameLowerCase.c_str(), &sStatBuf,
30✔
4258
                                  VSI_STAT_EXISTS_FLAG) == 0;
30✔
4259

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

4276
        if (osXMLFilename.empty())
30✔
4277
        {
4278
            return;
30✔
4279
        }
4280
    }
4281

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

4304
    CPLFree(m_pszXMLFilename);
2✔
4305
    m_pszXMLFilename = CPLStrdup(osXMLFilename.c_str());
2✔
4306
}
4307

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

4316
void GTiffDataset::ApplyPamInfo()
14,371✔
4317

4318
{
4319
    bool bGotGTFromPAM = false;
14,371✔
4320

4321
    if (m_nPAMGeorefSrcIndex >= 0 &&
14,371✔
4322
        ((m_bGeoTransformValid &&
14,371✔
4323
          m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
8,968✔
4324
         m_nGeoTransformGeorefSrcIndex < 0 || !m_bGeoTransformValid))
5,413✔
4325
    {
4326
        GDALGeoTransform pamGT;
14,360✔
4327
        if (GDALPamDataset::GetGeoTransform(pamGT) == CE_None)
14,360✔
4328
        {
4329
            if (m_nGeoTransformGeorefSrcIndex == m_nWORLDFILEGeorefSrcIndex)
44✔
4330
            {
4331
                CPLFree(m_pszGeorefFilename);
12✔
4332
                m_pszGeorefFilename = nullptr;
12✔
4333
            }
4334
            m_gt = pamGT;
44✔
4335
            m_bGeoTransformValid = true;
44✔
4336
            bGotGTFromPAM = true;
44✔
4337
        }
4338
    }
4339

4340
    if (m_nPAMGeorefSrcIndex >= 0)
14,373✔
4341
    {
4342
        if ((m_nTABFILEGeorefSrcIndex < 0 ||
14,372✔
4343
             m_nPAMGeorefSrcIndex < m_nTABFILEGeorefSrcIndex) &&
14,337✔
4344
            (m_nINTERNALGeorefSrcIndex < 0 ||
14,370✔
4345
             m_nPAMGeorefSrcIndex < m_nINTERNALGeorefSrcIndex))
14,355✔
4346
        {
4347
            const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
14,358✔
4348
            if (poPamSRS)
14,357✔
4349
            {
4350
                m_oSRS = *poPamSRS;
46✔
4351
                m_bLookedForProjection = true;
46✔
4352
                // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4353
            }
14,357✔
4354
        }
4355
        else
4356
        {
4357
            if (m_nINTERNALGeorefSrcIndex >= 0)
14✔
4358
                LookForProjection();
12✔
4359
            if (m_oSRS.IsEmpty())
14✔
4360
            {
4361
                const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
8✔
4362
                if (poPamSRS)
8✔
4363
                {
4364
                    m_oSRS = *poPamSRS;
8✔
4365
                    m_bLookedForProjection = true;
8✔
4366
                    // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4367
                }
4368
            }
4369
        }
4370
    }
4371

4372
    int nPamGCPCount;
4373
    if (m_nPAMGeorefSrcIndex >= 0 && !oMDMD.GetMetadata("xml:ESRI") &&
14,371✔
4374
        (nPamGCPCount = GDALPamDataset::GetGCPCount()) > 0 &&
28,762✔
4375
        ((!m_aoGCPs.empty() &&
19✔
4376
          m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
11✔
4377
         m_nGeoTransformGeorefSrcIndex < 0 || m_aoGCPs.empty()))
10✔
4378
    {
4379
        m_aoGCPs = gdal::GCP::fromC(GDALPamDataset::GetGCPs(), nPamGCPCount);
17✔
4380

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

4388
        // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
4389

4390
        const auto *poPamGCPSRS = GDALPamDataset::GetGCPSpatialRef();
17✔
4391
        if (poPamGCPSRS)
17✔
4392
            m_oSRS = *poPamGCPSRS;
15✔
4393
        else
4394
            m_oSRS.Clear();
2✔
4395

4396
        m_bLookedForProjection = true;
17✔
4397
    }
4398

4399
    if (m_nPAMGeorefSrcIndex >= 0)
14,371✔
4400
    {
4401
        CPLXMLNode *psValueAsXML = nullptr;
14,372✔
4402
        CPLXMLNode *psGeodataXform = nullptr;
14,372✔
4403
        char **papszXML = oMDMD.GetMetadata("xml:ESRI");
14,372✔
4404
        if (CSLCount(papszXML) == 1)
14,371✔
4405
        {
4406
            psValueAsXML = CPLParseXMLString(papszXML[0]);
9✔
4407
            if (psValueAsXML)
9✔
4408
                psGeodataXform = CPLGetXMLNode(psValueAsXML, "=GeodataXform");
9✔
4409
        }
4410

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

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

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

4489
        if (psValueAsXML)
14,372✔
4490
            CPLDestroyXMLNode(psValueAsXML);
9✔
4491
    }
4492

4493
    /* -------------------------------------------------------------------- */
4494
    /*      Copy any PAM metadata into our GeoTIFF context, and with        */
4495
    /*      the PAM info overriding the GeoTIFF context.                    */
4496
    /* -------------------------------------------------------------------- */
4497
    CSLConstList papszPamDomains = oMDMD.GetDomainList();
14,371✔
4498

4499
    for (int iDomain = 0;
14,410✔
4500
         papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
14,410✔
4501
    {
4502
        const char *pszDomain = papszPamDomains[iDomain];
39✔
4503
        char **papszGT_MD = CSLDuplicate(m_oGTiffMDMD.GetMetadata(pszDomain));
39✔
4504
        char **papszPAM_MD = oMDMD.GetMetadata(pszDomain);
39✔
4505

4506
        papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
39✔
4507

4508
        m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
39✔
4509
        CSLDestroy(papszGT_MD);
39✔
4510
    }
4511

4512
    for (int i = 1; i <= GetRasterCount(); ++i)
397,720✔
4513
    {
4514
        GTiffRasterBand *poBand =
4515
            cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
383,350✔
4516
        papszPamDomains = poBand->oMDMD.GetDomainList();
383,351✔
4517

4518
        for (int iDomain = 0;
383,421✔
4519
             papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
383,421✔
4520
        {
4521
            const char *pszDomain = papszPamDomains[iDomain];
72✔
4522
            char **papszGT_MD =
4523
                CSLDuplicate(poBand->m_oGTiffMDMD.GetMetadata(pszDomain));
72✔
4524
            char **papszPAM_MD = poBand->oMDMD.GetMetadata(pszDomain);
72✔
4525

4526
            papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
72✔
4527

4528
            poBand->m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
72✔
4529
            CSLDestroy(papszGT_MD);
72✔
4530
        }
4531
    }
4532

4533
    for (int i = 1; i <= nBands; ++i)
397,719✔
4534
    {
4535
        GTiffRasterBand *poBand =
4536
            cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
383,349✔
4537

4538
        /* Load scale, offset and unittype from PAM if available */
4539
        int nHaveOffsetScale = false;
383,351✔
4540
        double dfScale = poBand->GDALPamRasterBand::GetScale(&nHaveOffsetScale);
383,351✔
4541
        if (nHaveOffsetScale)
383,349✔
4542
        {
4543
            poBand->m_bHaveOffsetScale = true;
2✔
4544
            poBand->m_dfScale = dfScale;
2✔
4545
            poBand->m_dfOffset = poBand->GDALPamRasterBand::GetOffset();
2✔
4546
        }
4547

4548
        const char *pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
383,349✔
4549
        if (pszUnitType && pszUnitType[0])
383,349✔
4550
            poBand->m_osUnitType = pszUnitType;
15✔
4551

4552
        const char *pszDescription =
4553
            poBand->GDALPamRasterBand::GetDescription();
383,349✔
4554
        if (pszDescription && pszDescription[0])
383,351✔
4555
            poBand->m_osDescription = pszDescription;
19✔
4556

4557
        GDALColorInterp ePAMColorInterp =
4558
            poBand->GDALPamRasterBand::GetColorInterpretation();
383,351✔
4559
        if (ePAMColorInterp != GCI_Undefined)
383,350✔
4560
            poBand->m_eBandInterp = ePAMColorInterp;
51✔
4561

4562
        if (i == 1)
383,350✔
4563
        {
4564
            const auto poCT = poBand->GDALPamRasterBand::GetColorTable();
14,371✔
4565
            if (poCT)
14,370✔
4566
            {
4567
                m_poColorTable.reset(poCT->Clone());
4✔
4568
            }
4569
        }
4570
    }
4571
}
14,370✔
4572

4573
/************************************************************************/
4574
/*                              OpenDir()                               */
4575
/*                                                                      */
4576
/*      Open a specific directory as encoded into a filename.           */
4577
/************************************************************************/
4578

4579
GDALDataset *GTiffDataset::OpenDir(GDALOpenInfo *poOpenInfo)
25✔
4580

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

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

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

4602
    if (STARTS_WITH_CI(pszFilename, "off:"))
20✔
4603
    {
4604
        bAbsolute = true;
2✔
4605
        pszFilename += 4;
2✔
4606
    }
4607

4608
    toff_t nOffset = atol(pszFilename);
20✔
4609
    pszFilename += 1;
20✔
4610

4611
    while (*pszFilename != '\0' && pszFilename[-1] != ':')
44✔
4612
        ++pszFilename;
24✔
4613

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

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

4630
    /* -------------------------------------------------------------------- */
4631
    /*      Try opening the dataset.                                        */
4632
    /* -------------------------------------------------------------------- */
4633
    GTiffOneTimeInit();
20✔
4634

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

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

4666
        nOffset = TIFFCurrentDirOffset(l_hTIFF);
18✔
4667
    }
4668

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

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

4686
    if (poOpenInfo->AreSiblingFilesLoaded())
20✔
4687
        poDS->oOvManager.TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
20✔
4688

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

4696
    return poDS;
19✔
4697
}
4698

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

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

4717
    return sValue;
21✔
4718
}
4719

4720
/************************************************************************/
4721
/*                             LoadICCProfile()                         */
4722
/*                                                                      */
4723
/*      Load ICC Profile or colorimetric data into metadata             */
4724
/************************************************************************/
4725

4726
void GTiffDataset::LoadICCProfile()
4,917✔
4727
{
4728
    if (m_bICCMetadataLoaded)
4,917✔
4729
        return;
4,444✔
4730
    m_bICCMetadataLoaded = true;
486✔
4731

4732
    uint32_t nEmbedLen = 0;
486✔
4733
    uint8_t *pEmbedBuffer = nullptr;
486✔
4734

4735
    if (TIFFGetField(m_hTIFF, TIFFTAG_ICCPROFILE, &nEmbedLen, &pEmbedBuffer))
486✔
4736
    {
4737
        char *pszBase64Profile = CPLBase64Encode(
12✔
4738
            nEmbedLen, reinterpret_cast<const GByte *>(pEmbedBuffer));
4739

4740
        m_oGTiffMDMD.SetMetadataItem("SOURCE_ICC_PROFILE", pszBase64Profile,
12✔
4741
                                     "COLOR_PROFILE");
4742

4743
        CPLFree(pszBase64Profile);
12✔
4744

4745
        return;
12✔
4746
    }
4747

4748
    // Check for colorimetric tiff.
4749
    float *pCHR = nullptr;
474✔
4750
    float *pWP = nullptr;
474✔
4751
    uint16_t *pTFR = nullptr;
474✔
4752
    uint16_t *pTFG = nullptr;
474✔
4753
    uint16_t *pTFB = nullptr;
474✔
4754
    uint16_t *pTransferRange = nullptr;
474✔
4755

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

4768
            const int TIFFTAG_TRANSFERRANGE = 0x0156;
7✔
4769
            TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERRANGE,
7✔
4770
                                  &pTransferRange);
4771

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

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

4799
            // Set transfer function metadata.
4800

4801
            // Get length of table.
4802
            const uint32_t nTransferFunctionLength = 1 << m_nBitsPerSample;
7✔
4803

4804
            m_oGTiffMDMD.SetMetadataItem(
7✔
4805
                "TIFFTAG_TRANSFERFUNCTION_RED",
4806
                ConvertTransferFunctionToString(pTFR, nTransferFunctionLength),
14✔
4807
                "COLOR_PROFILE");
4808

4809
            m_oGTiffMDMD.SetMetadataItem(
7✔
4810
                "TIFFTAG_TRANSFERFUNCTION_GREEN",
4811
                ConvertTransferFunctionToString(pTFG, nTransferFunctionLength),
14✔
4812
                "COLOR_PROFILE");
4813

4814
            m_oGTiffMDMD.SetMetadataItem(
7✔
4815
                "TIFFTAG_TRANSFERFUNCTION_BLUE",
4816
                ConvertTransferFunctionToString(pTFB, nTransferFunctionLength),
14✔
4817
                "COLOR_PROFILE");
4818

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

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

4849
CPLErr GTiffDataset::OpenOffset(TIFF *hTIFFIn, toff_t nDirOffsetIn,
27,081✔
4850
                                GDALAccess eAccessIn, bool bAllowRGBAInterface,
4851
                                bool bReadGeoTransform)
4852

4853
{
4854
    if (!hTIFFIn)
27,081✔
4855
        return CE_Failure;
×
4856

4857
    eAccess = eAccessIn;
27,081✔
4858

4859
    m_hTIFF = hTIFFIn;
27,081✔
4860

4861
    m_nDirOffset = nDirOffsetIn;
27,081✔
4862

4863
    if (!SetDirectory())
27,081✔
4864
        return CE_Failure;
×
4865

4866
    /* -------------------------------------------------------------------- */
4867
    /*      Capture some information from the file that is of interest.     */
4868
    /* -------------------------------------------------------------------- */
4869
    uint32_t nXSize = 0;
27,071✔
4870
    uint32_t nYSize = 0;
27,071✔
4871
    TIFFGetField(m_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
27,071✔
4872
    TIFFGetField(m_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
27,067✔
4873

4874
    // Unlikely to occur, but could happen on a disk full situation.
4875
    if (nXSize == 0 || nYSize == 0)
27,076✔
4876
        return CE_Failure;
2✔
4877

4878
    if (nXSize > INT_MAX || nYSize > INT_MAX)
27,074✔
4879
    {
4880
        // GDAL only supports signed 32bit dimensions.
4881
        ReportError(CE_Failure, CPLE_NotSupported,
2✔
4882
                    "Too large image size: %u x %u", nXSize, nYSize);
4883
        return CE_Failure;
1✔
4884
    }
4885
    nRasterXSize = nXSize;
27,072✔
4886
    nRasterYSize = nYSize;
27,072✔
4887

4888
    if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLESPERPIXEL, &m_nSamplesPerPixel))
27,072✔
4889
        nBands = 1;
6✔
4890
    else
4891
        nBands = m_nSamplesPerPixel;
27,067✔
4892

4893
    if (!TIFFGetField(m_hTIFF, TIFFTAG_BITSPERSAMPLE, &(m_nBitsPerSample)))
27,073✔
4894
        m_nBitsPerSample = 1;
6✔
4895

4896
    if (!TIFFGetField(m_hTIFF, TIFFTAG_PLANARCONFIG, &(m_nPlanarConfig)))
27,075✔
4897
        m_nPlanarConfig = PLANARCONFIG_CONTIG;
×
4898

4899
    if (!TIFFGetField(m_hTIFF, TIFFTAG_PHOTOMETRIC, &(m_nPhotometric)))
27,072✔
4900
        m_nPhotometric = PHOTOMETRIC_MINISBLACK;
9✔
4901

4902
    if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLEFORMAT, &(m_nSampleFormat)))
27,070✔
4903
        m_nSampleFormat = SAMPLEFORMAT_UINT;
149✔
4904

4905
    if (!TIFFGetField(m_hTIFF, TIFFTAG_COMPRESSION, &(m_nCompression)))
27,064✔
4906
        m_nCompression = COMPRESSION_NONE;
×
4907

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

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

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

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

4982
        m_nBlockXSize = nRasterXSize;
23,365✔
4983
        m_nBlockYSize = m_nRowsPerStrip;
23,365✔
4984
    }
4985

4986
    if (!ComputeBlocksPerColRowAndBand(nBands))
27,071✔
4987
        return CE_Failure;
2✔
4988

4989
    /* -------------------------------------------------------------------- */
4990
    /*      Should we handle this using the GTiffBitmapBand?                */
4991
    /* -------------------------------------------------------------------- */
4992
    bool bTreatAsBitmap = false;
27,063✔
4993

4994
    if (m_nBitsPerSample == 1 && nBands == 1)
27,063✔
4995
    {
4996
        bTreatAsBitmap = true;
414✔
4997

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

5009
    /* -------------------------------------------------------------------- */
5010
    /*      Should we treat this via the RGBA interface?                    */
5011
    /* -------------------------------------------------------------------- */
5012
    bool bTreatAsRGBA = false;
27,063✔
5013
    if (
27,077✔
5014
#ifdef DEBUG
5015
        CPLTestBool(CPLGetConfigOption("GTIFF_FORCE_RGBA", "NO")) ||
52,123✔
5016
#endif
5017
        (bAllowRGBAInterface && !bTreatAsBitmap && !(m_nBitsPerSample > 8) &&
25,060✔
5018
         (m_nPhotometric == PHOTOMETRIC_CIELAB ||
19,224✔
5019
          m_nPhotometric == PHOTOMETRIC_LOGL ||
19,223✔
5020
          m_nPhotometric == PHOTOMETRIC_LOGLUV ||
19,223✔
5021
          m_nPhotometric == PHOTOMETRIC_SEPARATED ||
19,223✔
5022
          (m_nPhotometric == PHOTOMETRIC_YCBCR &&
19,213✔
5023
           m_nCompression != COMPRESSION_JPEG))))
243✔
5024
    {
5025
        char szMessage[1024] = {};
35✔
5026

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

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

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

5092
    /* -------------------------------------------------------------------- */
5093
    /*      Should we treat this via the split interface?                   */
5094
    /* -------------------------------------------------------------------- */
5095
    if (!TIFFIsTiled(m_hTIFF) && m_nBitsPerSample == 8 &&
50,447✔
5096
        m_nBlockYSize == nRasterYSize && nRasterYSize > 2000 && !bTreatAsRGBA &&
50,471✔
5097
        CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
24✔
5098
    {
5099
        m_bTreatAsSplit = true;
24✔
5100
    }
5101

5102
    /* -------------------------------------------------------------------- */
5103
    /*      Should we treat this via the odd bits interface?                */
5104
    /* -------------------------------------------------------------------- */
5105
    bool bTreatAsOdd = false;
27,076✔
5106
    if (m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
27,076✔
5107
    {
5108
        if (m_nBitsPerSample == 24)
1,751✔
5109
            bTreatAsOdd = true;
2✔
5110
        else if (m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
1,749✔
5111
                 m_nBitsPerSample != 64)
625✔
5112
        {
5113
            ReportError(CE_Failure, CPLE_AppDefined,
×
5114
                        "Cannot open TIFF file with SampleFormat=IEEEFP "
5115
                        "and BitsPerSample=%d",
5116
                        m_nBitsPerSample);
×
5117
            return CE_Failure;
×
5118
        }
5119
    }
5120
    else if (!bTreatAsRGBA && !bTreatAsBitmap && m_nBitsPerSample != 8 &&
25,325✔
5121
             m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
4,083✔
5122
             m_nBitsPerSample != 64 && m_nBitsPerSample != 128)
1,339✔
5123
    {
5124
        bTreatAsOdd = true;
203✔
5125
    }
5126

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

5158
    const bool bMinIsWhite = m_nPhotometric == PHOTOMETRIC_MINISWHITE;
27,076✔
5159

5160
    /* -------------------------------------------------------------------- */
5161
    /*      Check for NODATA                                                */
5162
    /* -------------------------------------------------------------------- */
5163
    char *pszText = nullptr;
27,076✔
5164
    if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_NODATA, &pszText) &&
28,423✔
5165
        !EQUAL(pszText, ""))
1,347✔
5166
    {
5167
        if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
1,346✔
5168
            m_nSampleFormat == SAMPLEFORMAT_INT)
104✔
5169
        {
5170
            m_bNoDataSetAsInt64 = true;
5✔
5171
            m_nNoDataValueInt64 =
5✔
5172
                static_cast<int64_t>(std::strtoll(pszText, nullptr, 10));
5✔
5173
        }
5174
        else if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
1,341✔
5175
                 m_nSampleFormat == SAMPLEFORMAT_UINT)
99✔
5176
        {
5177
            m_bNoDataSetAsUInt64 = true;
5✔
5178
            m_nNoDataValueUInt64 =
5✔
5179
                static_cast<uint64_t>(std::strtoull(pszText, nullptr, 10));
5✔
5180
        }
5181
        else
5182
        {
5183
            m_bNoDataSet = true;
1,336✔
5184
            m_dfNoDataValue = CPLAtofM(pszText);
1,336✔
5185
            if (m_nBitsPerSample == 32 &&
1,336✔
5186
                m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
193✔
5187
            {
5188
                m_dfNoDataValue =
135✔
5189
                    GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
135✔
5190
                m_dfNoDataValue = static_cast<float>(m_dfNoDataValue);
135✔
5191
            }
5192
        }
5193
    }
5194

5195
    /* -------------------------------------------------------------------- */
5196
    /*      Capture the color table if there is one.                        */
5197
    /* -------------------------------------------------------------------- */
5198
    unsigned short *panRed = nullptr;
27,073✔
5199
    unsigned short *panGreen = nullptr;
27,073✔
5200
    unsigned short *panBlue = nullptr;
27,073✔
5201

5202
    if (bTreatAsRGBA || m_nBitsPerSample > 16 ||
50,076✔
5203
        TIFFGetField(m_hTIFF, TIFFTAG_COLORMAP, &panRed, &panGreen, &panBlue) ==
23,001✔
5204
            0)
5205
    {
5206
        // Build inverted palette if we have inverted photometric.
5207
        // Pixel values remains unchanged.  Avoid doing this for *deep*
5208
        // data types (per #1882)
5209
        if (m_nBitsPerSample <= 16 && m_nPhotometric == PHOTOMETRIC_MINISWHITE)
26,918✔
5210
        {
5211
            m_poColorTable = std::make_unique<GDALColorTable>();
13✔
5212
            const int nColorCount = 1 << m_nBitsPerSample;
13✔
5213

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

5223
            m_nPhotometric = PHOTOMETRIC_PALETTE;
13✔
5224
        }
5225
        else
5226
        {
5227
            m_poColorTable.reset();
26,905✔
5228
        }
5229
    }
5230
    else
5231
    {
5232
        const int nColorCount = 1 << m_nBitsPerSample;
157✔
5233
        m_poColorTable = gdal::tiff_common::TIFFColorMapTagToColorTable(
155✔
5234
            panRed, panGreen, panBlue, nColorCount, m_nColorTableMultiplier,
157✔
5235
            DEFAULT_COLOR_TABLE_MULTIPLIER_257, m_bNoDataSet, m_dfNoDataValue);
157✔
5236
    }
5237

5238
    /* -------------------------------------------------------------------- */
5239
    /*      Create band information objects.                                */
5240
    /* -------------------------------------------------------------------- */
5241
    for (int iBand = 0; iBand < nBands; ++iBand)
756,444✔
5242
    {
5243
        if (bTreatAsRGBA)
729,386✔
5244
            SetBand(iBand + 1, new GTiffRGBABand(this, iBand + 1));
127✔
5245
        else if (m_bTreatAsSplitBitmap)
729,259✔
5246
            SetBand(iBand + 1, new GTiffSplitBitmapBand(this, iBand + 1));
10✔
5247
        else if (m_bTreatAsSplit)
729,249✔
5248
            SetBand(iBand + 1, new GTiffSplitBand(this, iBand + 1));
131,118✔
5249
        else if (bTreatAsBitmap)
598,131✔
5250
            SetBand(iBand + 1, new GTiffBitmapBand(this, iBand + 1));
404✔
5251
        else if (bTreatAsOdd)
597,727✔
5252
            SetBand(iBand + 1, new GTiffOddBitsBand(this, iBand + 1));
346✔
5253
        else
5254
            SetBand(iBand + 1, new GTiffRasterBand(this, iBand + 1));
597,381✔
5255
    }
5256

5257
    if (GetRasterBand(1)->GetRasterDataType() == GDT_Unknown)
27,058✔
5258
    {
5259
        ReportError(CE_Failure, CPLE_NotSupported,
1✔
5260
                    "Unsupported TIFF configuration: BitsPerSample(=%d) and "
5261
                    "SampleType(=%d)",
5262
                    m_nBitsPerSample, m_nSampleFormat);
1✔
5263
        return CE_Failure;
1✔
5264
    }
5265

5266
    m_bReadGeoTransform = bReadGeoTransform;
27,060✔
5267

5268
    /* -------------------------------------------------------------------- */
5269
    /*      Capture some other potentially interesting information.         */
5270
    /* -------------------------------------------------------------------- */
5271
    char szWorkMDI[200] = {};
27,060✔
5272
    uint16_t nShort = 0;
27,060✔
5273

5274
    const auto *pasTIFFTags = GetTIFFTags();
27,060✔
5275
    for (size_t iTag = 0; pasTIFFTags[iTag].pszTagName; ++iTag)
406,044✔
5276
    {
5277
        if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_STRING)
378,973✔
5278
        {
5279
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &pszText))
216,554✔
5280
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
126✔
5281
                                             pszText);
5282
        }
5283
        else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_FLOAT)
162,419✔
5284
        {
5285
            float fVal = 0.0;
54,137✔
5286
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &fVal))
54,137✔
5287
            {
5288
                CPLsnprintf(szWorkMDI, sizeof(szWorkMDI), "%.8g", fVal);
172✔
5289
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
172✔
5290
                                             szWorkMDI);
5291
            }
5292
        }
5293
        else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_SHORT &&
108,282✔
5294
                 pasTIFFTags[iTag].nTagVal != TIFFTAG_RESOLUTIONUNIT)
81,205✔
5295
        {
5296
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nShort))
54,133✔
5297
            {
5298
                snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
8✔
5299
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
8✔
5300
                                             szWorkMDI);
5301
            }
5302
        }
5303
        else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_BYTE_STRING)
54,149✔
5304
        {
5305
            uint32_t nCount = 0;
27,071✔
5306
            if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nCount,
27,071✔
5307
                             &pszText))
27,071✔
5308
            {
5309
                std::string osStr;
2✔
5310
                osStr.assign(pszText, nCount);
1✔
5311
                m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
1✔
5312
                                             osStr.c_str());
5313
            }
5314
        }
5315
    }
5316

5317
    if (TIFFGetField(m_hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort))
27,071✔
5318
    {
5319
        if (nShort == RESUNIT_NONE)
88✔
5320
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (unitless)", nShort);
34✔
5321
        else if (nShort == RESUNIT_INCH)
54✔
5322
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/inch)", nShort);
53✔
5323
        else if (nShort == RESUNIT_CENTIMETER)
1✔
5324
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/cm)", nShort);
1✔
5325
        else
5326
            snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
×
5327
        m_oGTiffMDMD.SetMetadataItem("TIFFTAG_RESOLUTIONUNIT", szWorkMDI);
88✔
5328
    }
5329

5330
    int nTagSize = 0;
27,067✔
5331
    void *pData = nullptr;
27,067✔
5332
    if (TIFFGetField(m_hTIFF, TIFFTAG_XMLPACKET, &nTagSize, &pData))
27,067✔
5333
    {
5334
        char *pszXMP = static_cast<char *>(VSI_MALLOC_VERBOSE(nTagSize + 1));
35✔
5335
        if (pszXMP)
35✔
5336
        {
5337
            memcpy(pszXMP, pData, nTagSize);
35✔
5338
            pszXMP[nTagSize] = '\0';
35✔
5339

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

5343
            CPLFree(pszXMP);
35✔
5344
        }
5345
    }
5346

5347
    if (m_nCompression != COMPRESSION_NONE)
27,072✔
5348
    {
5349
        const char *pszCompressionMethodName =
5350
            GTIFFGetCompressionMethodName(m_nCompression);
3,709✔
5351
        if (pszCompressionMethodName)
3,709✔
5352
        {
5353
            m_oGTiffMDMD.SetMetadataItem(
3,709✔
5354
                "COMPRESSION", pszCompressionMethodName, "IMAGE_STRUCTURE");
5355
        }
5356
        else
5357
        {
5358
            CPLString oComp;
×
5359
            oComp.Printf("%d", m_nCompression);
×
5360
            m_oGTiffMDMD.SetMetadataItem("COMPRESSION", oComp.c_str());
×
5361
        }
5362
    }
5363

5364
    if (m_nCompression == COMPRESSION_JPEG &&
27,072✔
5365
        m_nPhotometric == PHOTOMETRIC_YCBCR)
477✔
5366
    {
5367
        m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "YCbCr JPEG",
265✔
5368
                                     "IMAGE_STRUCTURE");
5369
    }
5370
    else if (m_nCompression == COMPRESSION_LERC)
26,807✔
5371
    {
5372
        uint32_t nLercParamCount = 0;
317✔
5373
        uint32_t *panLercParams = nullptr;
317✔
5374
        if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_PARAMETERS, &nLercParamCount,
317✔
5375
                         &panLercParams) &&
634✔
5376
            nLercParamCount == 2)
317✔
5377
        {
5378
            memcpy(m_anLercAddCompressionAndVersion, panLercParams,
317✔
5379
                   sizeof(m_anLercAddCompressionAndVersion));
5380
        }
5381

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

5413
    if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1)
27,072✔
5414
        m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
2,946✔
5415
    else
5416
        m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
24,126✔
5417

5418
    if ((GetRasterBand(1)->GetRasterDataType() == GDT_Byte &&
27,066✔
5419
         m_nBitsPerSample != 8) ||
21,137✔
5420
        (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 &&
26,568✔
5421
         m_nBitsPerSample != 16) ||
54,727✔
5422
        ((GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 ||
26,473✔
5423
          GetRasterBand(1)->GetRasterDataType() == GDT_Float32) &&
26,088✔
5424
         m_nBitsPerSample != 32))
1,379✔
5425
    {
5426
        for (int i = 0; i < nBands; ++i)
1,382✔
5427
            cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i + 1))
763✔
5428
                ->m_oGTiffMDMD.SetMetadataItem(
763✔
5429
                    "NBITS",
5430
                    CPLString().Printf("%d",
1,526✔
5431
                                       static_cast<int>(m_nBitsPerSample)),
763✔
5432
                    "IMAGE_STRUCTURE");
5433
    }
5434

5435
    if (bMinIsWhite)
27,054✔
5436
        m_oGTiffMDMD.SetMetadataItem("MINISWHITE", "YES", "IMAGE_STRUCTURE");
15✔
5437

5438
    if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
27,054✔
5439
    {
5440
        CPLXMLNode *psRoot = CPLParseXMLString(pszText);
3,188✔
5441
        const CPLXMLNode *psItem =
5442
            psRoot ? CPLGetXMLNode(psRoot, "=GDALMetadata") : nullptr;
3,187✔
5443
        if (psItem)
3,188✔
5444
            psItem = psItem->psChild;
3,187✔
5445
        bool bMaxZErrorFound = false;
3,188✔
5446
        bool bMaxZErrorOverviewFound = false;
3,188✔
5447
        for (; psItem != nullptr; psItem = psItem->psNext)
17,360✔
5448
        {
5449

5450
            if (psItem->eType != CXT_Element ||
14,172✔
5451
                !EQUAL(psItem->pszValue, "Item"))
14,172✔
UNCOV
5452
                continue;
×
5453

5454
            const char *pszKey = CPLGetXMLValue(psItem, "name", nullptr);
14,172✔
5455
            const char *pszValue = CPLGetXMLValue(psItem, nullptr, nullptr);
14,172✔
5456
            int nBand = atoi(CPLGetXMLValue(psItem, "sample", "-1"));
14,172✔
5457
            if (nBand < -1 || nBand > 65535)
14,172✔
5458
                continue;
×
5459
            nBand++;
14,172✔
5460
            const char *pszRole = CPLGetXMLValue(psItem, "role", "");
14,172✔
5461
            const char *pszDomain = CPLGetXMLValue(psItem, "domain", "");
14,172✔
5462

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

5570
            bool bIsXML = false;
13,725✔
5571

5572
            if (STARTS_WITH_CI(pszDomain, "xml:"))
13,725✔
5573
                bIsXML = TRUE;
3✔
5574

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

5652
        if (bMaxZErrorFound && !bMaxZErrorOverviewFound)
3,188✔
5653
        {
5654
            m_dfMaxZErrorOverview = m_dfMaxZError;
27✔
5655
        }
5656

5657
        CPLDestroyXMLNode(psRoot);
3,188✔
5658
    }
5659

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

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

5748
    if (GTIFFSupportsPredictor(m_nCompression))
27,060✔
5749
    {
5750
        uint16_t nPredictor = 0;
2,079✔
5751
        if (TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &nPredictor) &&
4,126✔
5752
            nPredictor > 1)
2,047✔
5753
        {
5754
            m_oGTiffMDMD.SetMetadataItem(
93✔
5755
                "PREDICTOR", CPLSPrintf("%d", nPredictor), "IMAGE_STRUCTURE");
5756
        }
5757
    }
5758

5759
    CPLAssert(m_bReadGeoTransform == bReadGeoTransform);
27,066✔
5760
    CPLAssert(!m_bMetadataChanged);
27,066✔
5761
    m_bMetadataChanged = false;
27,066✔
5762

5763
    return CE_None;
27,066✔
5764
}
5765

5766
/************************************************************************/
5767
/*                         GetSiblingFiles()                            */
5768
/************************************************************************/
5769

5770
CSLConstList GTiffDataset::GetSiblingFiles()
42,330✔
5771
{
5772
    if (m_bHasGotSiblingFiles)
42,330✔
5773
    {
5774
        return oOvManager.GetSiblingFiles();
25,744✔
5775
    }
5776
    if (m_poBaseDS)
16,586✔
5777
    {
5778
        return m_poBaseDS->GetSiblingFiles();
77✔
5779
    }
5780

5781
    m_bHasGotSiblingFiles = true;
16,509✔
5782
    const int nMaxFiles =
5783
        atoi(CPLGetConfigOption("GDAL_READDIR_LIMIT_ON_OPEN", "1000"));
16,509✔
5784
    const std::string osDirname = CPLGetDirnameSafe(m_pszFilename);
33,017✔
5785
    CPLStringList aosSiblingFiles(VSIReadDirEx(osDirname.c_str(), nMaxFiles));
33,014✔
5786
    if (nMaxFiles > 0 && aosSiblingFiles.size() > nMaxFiles)
16,509✔
5787
    {
5788
        CPLDebug("GTiff", "GDAL_READDIR_LIMIT_ON_OPEN reached on %s",
1✔
5789
                 osDirname.c_str());
5790
        aosSiblingFiles.clear();
1✔
5791
    }
5792
    oOvManager.TransferSiblingFiles(aosSiblingFiles.StealList());
16,510✔
5793

5794
    return oOvManager.GetSiblingFiles();
16,508✔
5795
}
5796

5797
/************************************************************************/
5798
/*                   IdentifyAuthorizedGeoreferencingSources()          */
5799
/************************************************************************/
5800

5801
void GTiffDataset::IdentifyAuthorizedGeoreferencingSources()
28,846✔
5802
{
5803
    if (m_bHasIdentifiedAuthorizedGeoreferencingSources)
28,846✔
5804
        return;
12,416✔
5805
    m_bHasIdentifiedAuthorizedGeoreferencingSources = true;
16,430✔
5806
    CPLString osGeorefSources = CSLFetchNameValueDef(
5807
        papszOpenOptions, "GEOREF_SOURCES",
16,430✔
5808
        CPLGetConfigOption("GDAL_GEOREF_SOURCES",
5809
                           "PAM,INTERNAL,TABFILE,WORLDFILE,XML"));
32,859✔
5810
    char **papszTokens = CSLTokenizeString2(osGeorefSources, ",", 0);
16,429✔
5811
    m_nPAMGeorefSrcIndex =
16,430✔
5812
        static_cast<signed char>(CSLFindString(papszTokens, "PAM"));
16,430✔
5813
    m_nINTERNALGeorefSrcIndex =
16,430✔
5814
        static_cast<signed char>(CSLFindString(papszTokens, "INTERNAL"));
16,430✔
5815
    m_nTABFILEGeorefSrcIndex =
16,430✔
5816
        static_cast<signed char>(CSLFindString(papszTokens, "TABFILE"));
16,430✔
5817
    m_nWORLDFILEGeorefSrcIndex =
16,430✔
5818
        static_cast<signed char>(CSLFindString(papszTokens, "WORLDFILE"));
16,430✔
5819
    m_nXMLGeorefSrcIndex =
16,430✔
5820
        static_cast<signed char>(CSLFindString(papszTokens, "XML"));
16,430✔
5821
    CSLDestroy(papszTokens);
16,430✔
5822
}
5823

5824
/************************************************************************/
5825
/*                     LoadGeoreferencingAndPamIfNeeded()               */
5826
/************************************************************************/
5827

5828
void GTiffDataset::LoadGeoreferencingAndPamIfNeeded()
3,169,000✔
5829

5830
{
5831
    if (!m_bReadGeoTransform && !m_bLoadPam)
3,169,000✔
5832
        return;
3,151,640✔
5833

5834
    IdentifyAuthorizedGeoreferencingSources();
17,361✔
5835

5836
    /* -------------------------------------------------------------------- */
5837
    /*      Get the transform or gcps from the GeoTIFF file.                */
5838
    /* -------------------------------------------------------------------- */
5839
    if (m_bReadGeoTransform)
16,398✔
5840
    {
5841
        m_bReadGeoTransform = false;
16,398✔
5842

5843
        char *pszTabWKT = nullptr;
16,398✔
5844
        double *padfTiePoints = nullptr;
16,398✔
5845
        double *padfScale = nullptr;
16,398✔
5846
        double *padfMatrix = nullptr;
16,398✔
5847
        uint16_t nCount = 0;
16,398✔
5848
        bool bPixelIsPoint = false;
16,398✔
5849
        unsigned short nRasterType = 0;
16,398✔
5850
        bool bPointGeoIgnore = false;
16,398✔
5851

5852
        std::set<signed char> aoSetPriorities;
32,795✔
5853
        if (m_nINTERNALGeorefSrcIndex >= 0)
16,398✔
5854
            aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
16,372✔
5855
        if (m_nTABFILEGeorefSrcIndex >= 0)
16,399✔
5856
            aoSetPriorities.insert(m_nTABFILEGeorefSrcIndex);
16,346✔
5857
        if (m_nWORLDFILEGeorefSrcIndex >= 0)
16,400✔
5858
            aoSetPriorities.insert(m_nWORLDFILEGeorefSrcIndex);
16,362✔
5859
        for (const auto nIndex : aoSetPriorities)
33,883✔
5860
        {
5861
            if (m_nINTERNALGeorefSrcIndex == nIndex)
28,045✔
5862
            {
5863
                GTIF *psGTIF =
5864
                    GTiffDataset::GTIFNew(m_hTIFF);  // How expensive this is?
16,365✔
5865

5866
                if (psGTIF)
16,365✔
5867
                {
5868
                    if (GDALGTIFKeyGetSHORT(psGTIF, GTRasterTypeGeoKey,
16,365✔
5869
                                            &nRasterType, 0, 1) == 1 &&
25,983✔
5870
                        nRasterType == static_cast<short>(RasterPixelIsPoint))
9,618✔
5871
                    {
5872
                        bPixelIsPoint = true;
256✔
5873
                        bPointGeoIgnore = CPLTestBool(CPLGetConfigOption(
256✔
5874
                            "GTIFF_POINT_GEO_IGNORE", "FALSE"));
5875
                    }
5876

5877
                    GTIFFree(psGTIF);
16,365✔
5878
                }
5879

5880
                m_gt = GDALGeoTransform();
16,365✔
5881

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

5922
                    if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
10,384✔
5923
                                     &padfTiePoints) &&
20,768✔
5924
                        nCount >= 6)
10,384✔
5925
                    {
5926
                        m_gt[0] = padfTiePoints[3] - padfTiePoints[0] * m_gt[1];
10,383✔
5927
                        m_gt[3] = padfTiePoints[4] - padfTiePoints[1] * m_gt[5];
10,383✔
5928

5929
                        if (bPixelIsPoint && !bPointGeoIgnore)
10,383✔
5930
                        {
5931
                            m_gt[0] -= (m_gt[1] * 0.5 + m_gt[2] * 0.5);
220✔
5932
                            m_gt[3] -= (m_gt[4] * 0.5 + m_gt[5] * 0.5);
220✔
5933
                        }
5934

5935
                        m_bGeoTransformValid = true;
10,383✔
5936
                        m_nGeoTransformGeorefSrcIndex = nIndex;
10,383✔
5937

5938
                        if (nCountScale >= 3 && GetRasterCount() == 1 &&
17,259✔
5939
                            (padfScale[2] != 0.0 || padfTiePoints[2] != 0.0 ||
6,876✔
5940
                             padfTiePoints[5] != 0.0))
6,850✔
5941
                        {
5942
                            LookForProjection();
28✔
5943
                            if (!m_oSRS.IsEmpty() && m_oSRS.IsVertical())
28✔
5944
                            {
5945
                                /* modelTiePointTag = (pixel, line, z0, X, Y,
5946
                                 * Z0) */
5947
                                /* thus Z(some_point) = (z(some_point) - z0) *
5948
                                 * scaleZ + Z0 */
5949
                                /* equivalently written as */
5950
                                /* Z(some_point) = z(some_point) * scaleZ +
5951
                                 * offsetZ with */
5952
                                /* offsetZ = - z0 * scaleZ + Z0 */
5953
                                double dfScale = padfScale[2];
18✔
5954
                                double dfOffset = -padfTiePoints[2] * dfScale +
18✔
5955
                                                  padfTiePoints[5];
18✔
5956
                                GTiffRasterBand *poBand =
5957
                                    cpl::down_cast<GTiffRasterBand *>(
18✔
5958
                                        GetRasterBand(1));
5959
                                poBand->m_bHaveOffsetScale = true;
18✔
5960
                                poBand->m_dfScale = dfScale;
18✔
5961
                                poBand->m_dfOffset = dfOffset;
18✔
5962
                            }
5963
                        }
5964
                    }
5965
                }
5966

5967
                else if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX, &nCount,
5,981✔
5968
                                      &padfMatrix) &&
6,108✔
5969
                         nCount == 16)
128✔
5970
                {
5971
                    m_gt[0] = padfMatrix[3];
128✔
5972
                    m_gt[1] = padfMatrix[0];
128✔
5973
                    m_gt[2] = padfMatrix[1];
128✔
5974
                    m_gt[3] = padfMatrix[7];
128✔
5975
                    m_gt[4] = padfMatrix[4];
128✔
5976
                    m_gt[5] = padfMatrix[5];
128✔
5977

5978
                    if (bPixelIsPoint && !bPointGeoIgnore)
128✔
5979
                    {
5980
                        m_gt[0] -= m_gt[1] * 0.5 + m_gt[2] * 0.5;
5✔
5981
                        m_gt[3] -= m_gt[4] * 0.5 + m_gt[5] * 0.5;
5✔
5982
                    }
5983

5984
                    m_bGeoTransformValid = true;
128✔
5985
                    m_nGeoTransformGeorefSrcIndex = nIndex;
128✔
5986
                }
5987
                if (m_bGeoTransformValid)
16,365✔
5988
                    break;
10,512✔
5989
            }
5990

5991
            /* --------------------------------------------------------------------
5992
             */
5993
            /*      Otherwise try looking for a .tab, .tfw, .tifw or .wld file.
5994
             */
5995
            /* --------------------------------------------------------------------
5996
             */
5997
            if (m_nTABFILEGeorefSrcIndex == nIndex)
17,533✔
5998
            {
5999
                char *pszGeorefFilename = nullptr;
5,836✔
6000

6001
                CSLConstList papszSiblingFiles = GetSiblingFiles();
5,836✔
6002

6003
                // Begin with .tab since it can also have projection info.
6004
                int nGCPCount = 0;
5,836✔
6005
                GDAL_GCP *pasGCPList = nullptr;
5,836✔
6006
                const int bTabFileOK = GDALReadTabFile2(
5,836✔
6007
                    m_pszFilename, m_gt.data(), &pszTabWKT, &nGCPCount,
5,836✔
6008
                    &pasGCPList, papszSiblingFiles, &pszGeorefFilename);
6009

6010
                if (bTabFileOK)
5,836✔
6011
                {
6012
                    m_nGeoTransformGeorefSrcIndex = nIndex;
14✔
6013
                    // if( pszTabWKT )
6014
                    // {
6015
                    //     m_nProjectionGeorefSrcIndex = nIndex;
6016
                    // }
6017
                    m_aoGCPs = gdal::GCP::fromC(pasGCPList, nGCPCount);
14✔
6018
                    if (m_aoGCPs.empty())
14✔
6019
                    {
6020
                        m_bGeoTransformValid = true;
14✔
6021
                    }
6022
                }
6023

6024
                if (nGCPCount)
5,836✔
6025
                {
6026
                    GDALDeinitGCPs(nGCPCount, pasGCPList);
×
6027
                    CPLFree(pasGCPList);
×
6028
                }
6029

6030
                if (pszGeorefFilename)
5,836✔
6031
                {
6032
                    CPLFree(m_pszGeorefFilename);
14✔
6033
                    m_pszGeorefFilename = pszGeorefFilename;
14✔
6034
                    pszGeorefFilename = nullptr;
14✔
6035
                }
6036
                if (m_bGeoTransformValid)
5,836✔
6037
                    break;
14✔
6038
            }
6039

6040
            if (m_nWORLDFILEGeorefSrcIndex == nIndex)
17,519✔
6041
            {
6042
                char *pszGeorefFilename = nullptr;
5,844✔
6043

6044
                CSLConstList papszSiblingFiles = GetSiblingFiles();
5,844✔
6045

6046
                m_bGeoTransformValid = CPL_TO_BOOL(
5,844✔
6047
                    GDALReadWorldFile2(m_pszFilename, nullptr, m_gt,
5,844✔
6048
                                       papszSiblingFiles, &pszGeorefFilename));
6049

6050
                if (!m_bGeoTransformValid)
5,844✔
6051
                {
6052
                    m_bGeoTransformValid = CPL_TO_BOOL(GDALReadWorldFile2(
5,812✔
6053
                        m_pszFilename, "wld", m_gt, papszSiblingFiles,
5,812✔
6054
                        &pszGeorefFilename));
6055
                }
6056
                if (m_bGeoTransformValid)
5,844✔
6057
                    m_nGeoTransformGeorefSrcIndex = nIndex;
37✔
6058

6059
                if (pszGeorefFilename)
5,844✔
6060
                {
6061
                    CPLFree(m_pszGeorefFilename);
37✔
6062
                    m_pszGeorefFilename = pszGeorefFilename;
37✔
6063
                    pszGeorefFilename = nullptr;
37✔
6064
                }
6065
                if (m_bGeoTransformValid)
5,844✔
6066
                    break;
37✔
6067
            }
6068
        }
6069

6070
        /* --------------------------------------------------------------------
6071
         */
6072
        /*      Check for GCPs. */
6073
        /* --------------------------------------------------------------------
6074
         */
6075
        if (m_nINTERNALGeorefSrcIndex >= 0 &&
49,163✔
6076
            TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
16,371✔
6077
                         &padfTiePoints) &&
32,767✔
6078
            !m_bGeoTransformValid)
10,519✔
6079
        {
6080
            m_aoGCPs.clear();
136✔
6081
            const int nNewGCPCount = nCount / 6;
136✔
6082
            for (int iGCP = 0; iGCP < nNewGCPCount; ++iGCP)
640✔
6083
            {
6084
                m_aoGCPs.emplace_back(CPLSPrintf("%d", iGCP + 1), "",
×
6085
                                      /* pixel = */ padfTiePoints[iGCP * 6 + 0],
504✔
6086
                                      /* line = */ padfTiePoints[iGCP * 6 + 1],
504✔
6087
                                      /* X = */ padfTiePoints[iGCP * 6 + 3],
504✔
6088
                                      /* Y = */ padfTiePoints[iGCP * 6 + 4],
504✔
6089
                                      /* Z = */ padfTiePoints[iGCP * 6 + 5]);
504✔
6090

6091
                if (bPixelIsPoint && !bPointGeoIgnore)
504✔
6092
                {
6093
                    m_aoGCPs.back().Pixel() += 0.5;
48✔
6094
                    m_aoGCPs.back().Line() += 0.5;
48✔
6095
                }
6096
            }
6097
            m_nGeoTransformGeorefSrcIndex = m_nINTERNALGeorefSrcIndex;
136✔
6098
        }
6099

6100
        /* --------------------------------------------------------------------
6101
         */
6102
        /*      Did we find a tab file?  If so we will use its coordinate */
6103
        /*      system and give it precedence. */
6104
        /* --------------------------------------------------------------------
6105
         */
6106
        if (pszTabWKT != nullptr && m_oSRS.IsEmpty())
16,396✔
6107
        {
6108
            m_oSRS.importFromWkt(pszTabWKT);
14✔
6109
            m_bLookedForProjection = true;
14✔
6110
        }
6111

6112
        CPLFree(pszTabWKT);
16,396✔
6113
    }
6114

6115
    if (m_bLoadPam && m_nPAMGeorefSrcIndex >= 0)
16,397✔
6116
    {
6117
        /* --------------------------------------------------------------------
6118
         */
6119
        /*      Initialize any PAM information. */
6120
        /* --------------------------------------------------------------------
6121
         */
6122
        CPLAssert(!m_bColorProfileMetadataChanged);
14,370✔
6123
        CPLAssert(!m_bMetadataChanged);
14,370✔
6124
        CPLAssert(!m_bGeoTIFFInfoChanged);
14,370✔
6125
        CPLAssert(!m_bNoDataChanged);
14,370✔
6126

6127
        // We must absolutely unset m_bLoadPam now, otherwise calling
6128
        // GetFileList() on a .tif with a .aux will result in an (almost)
6129
        // endless sequence of calls.
6130
        m_bLoadPam = false;
14,370✔
6131

6132
        TryLoadXML(GetSiblingFiles());
14,370✔
6133
        ApplyPamInfo();
14,372✔
6134

6135
        m_bColorProfileMetadataChanged = false;
14,372✔
6136
        m_bMetadataChanged = false;
14,372✔
6137
        m_bGeoTIFFInfoChanged = false;
14,372✔
6138
        m_bNoDataChanged = false;
14,372✔
6139
    }
6140
    m_bLoadPam = false;
16,399✔
6141
}
6142

6143
/************************************************************************/
6144
/*                          GetSpatialRef()                             */
6145
/************************************************************************/
6146

6147
const OGRSpatialReference *GTiffDataset::GetSpatialRef() const
19,605✔
6148

6149
{
6150
    const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
19,605✔
6151
    if (m_aoGCPs.empty())
19,605✔
6152
    {
6153
        const_cast<GTiffDataset *>(this)->LookForProjection();
19,079✔
6154
    }
6155

6156
    return m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
19,605✔
6157
}
6158

6159
/************************************************************************/
6160
/*                          GetGeoTransform()                           */
6161
/************************************************************************/
6162

6163
CPLErr GTiffDataset::GetGeoTransform(GDALGeoTransform &gt) const
318,555✔
6164

6165
{
6166
    const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
318,555✔
6167

6168
    gt = m_gt;
318,555✔
6169

6170
    if (!m_bGeoTransformValid)
318,555✔
6171
        return CE_Failure;
303,683✔
6172

6173
    // Same logic as in the .gtx driver, for the benefit of
6174
    // GDALOpenVerticalShiftGrid() when used with PROJ-data's US geoids.
6175
    if (CPLFetchBool(papszOpenOptions, "SHIFT_ORIGIN_IN_MINUS_180_PLUS_180",
14,872✔
6176
                     false))
6177
    {
6178
        if (gt[0] < -180.0 - gt[1])
×
6179
            gt[0] += 360.0;
×
6180
        else if (gt[0] > 180.0)
×
6181
            gt[0] -= 360.0;
×
6182
    }
6183

6184
    return CE_None;
14,872✔
6185
}
6186

6187
/************************************************************************/
6188
/*                            GetGCPCount()                             */
6189
/************************************************************************/
6190

6191
int GTiffDataset::GetGCPCount()
6,712✔
6192

6193
{
6194
    LoadGeoreferencingAndPamIfNeeded();
6,712✔
6195

6196
    return static_cast<int>(m_aoGCPs.size());
6,712✔
6197
}
6198

6199
/************************************************************************/
6200
/*                          GetGCPSpatialRef()                          */
6201
/************************************************************************/
6202

6203
const OGRSpatialReference *GTiffDataset::GetGCPSpatialRef() const
626✔
6204

6205
{
6206
    const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
626✔
6207

6208
    if (!m_aoGCPs.empty())
626✔
6209
    {
6210
        const_cast<GTiffDataset *>(this)->LookForProjection();
153✔
6211
    }
6212
    return !m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
626✔
6213
}
6214

6215
/************************************************************************/
6216
/*                               GetGCPs()                              */
6217
/************************************************************************/
6218

6219
const GDAL_GCP *GTiffDataset::GetGCPs()
492✔
6220

6221
{
6222
    LoadGeoreferencingAndPamIfNeeded();
492✔
6223

6224
    return gdal::GCP::c_ptr(m_aoGCPs);
492✔
6225
}
6226

6227
/************************************************************************/
6228
/*                      GetMetadataDomainList()                         */
6229
/************************************************************************/
6230

6231
char **GTiffDataset::GetMetadataDomainList()
33✔
6232
{
6233
    LoadGeoreferencingAndPamIfNeeded();
33✔
6234

6235
    char **papszDomainList = CSLDuplicate(m_oGTiffMDMD.GetDomainList());
33✔
6236
    char **papszBaseList = GDALDataset::GetMetadataDomainList();
33✔
6237

6238
    const int nbBaseDomains = CSLCount(papszBaseList);
33✔
6239

6240
    for (int domainId = 0; domainId < nbBaseDomains; ++domainId)
68✔
6241
    {
6242
        if (CSLFindString(papszDomainList, papszBaseList[domainId]) < 0)
35✔
6243
        {
6244
            papszDomainList =
6245
                CSLAddString(papszDomainList, papszBaseList[domainId]);
33✔
6246
        }
6247
    }
6248

6249
    CSLDestroy(papszBaseList);
33✔
6250

6251
    return BuildMetadataDomainList(papszDomainList, TRUE, "",
33✔
6252
                                   "ProxyOverviewRequest", MD_DOMAIN_RPC,
6253
                                   MD_DOMAIN_IMD, "SUBDATASETS", "EXIF",
6254
                                   "xml:XMP", "COLOR_PROFILE", nullptr);
33✔
6255
}
6256

6257
/************************************************************************/
6258
/*                            GetMetadata()                             */
6259
/************************************************************************/
6260

6261
char **GTiffDataset::GetMetadata(const char *pszDomain)
33,439✔
6262

6263
{
6264
    if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
33,439✔
6265
    {
6266
        GTiffDataset::GetMetadataItem("COMPRESSION_REVERSIBILITY", pszDomain);
126✔
6267
    }
6268
    else
6269
    {
6270
        LoadGeoreferencingAndPamIfNeeded();
33,313✔
6271
    }
6272

6273
    if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
33,439✔
6274
        return GDALPamDataset::GetMetadata(pszDomain);
33✔
6275

6276
    if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
33,406✔
6277
    {
6278
        return GDALDataset::GetMetadata(pszDomain);
6✔
6279
    }
6280

6281
    else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
33,400✔
6282
                                      EQUAL(pszDomain, MD_DOMAIN_IMD) ||
20,882✔
6283
                                      EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
14,654✔
6284
        LoadMetadata();
18,090✔
6285

6286
    else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
15,310✔
6287
        ScanDirectories();
1,236✔
6288

6289
    else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
14,074✔
6290
        LoadEXIFMetadata();
57✔
6291

6292
    else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
14,017✔
6293
        LoadICCProfile();
48✔
6294

6295
    else if (pszDomain == nullptr || EQUAL(pszDomain, ""))
13,969✔
6296
        LoadMDAreaOrPoint();  // To set GDALMD_AREA_OR_POINT.
7,530✔
6297

6298
    return m_oGTiffMDMD.GetMetadata(pszDomain);
33,400✔
6299
}
6300

6301
/************************************************************************/
6302
/*                          GetMetadataItem()                           */
6303
/************************************************************************/
6304

6305
const char *GTiffDataset::GetMetadataItem(const char *pszName,
145,508✔
6306
                                          const char *pszDomain)
6307

6308
{
6309
    if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
145,508✔
6310
    {
6311
        if ((m_nCompression == COMPRESSION_WEBP ||
214,666✔
6312
             m_nCompression == COMPRESSION_JXL ||
70,172✔
6313
             m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
70,171✔
6314
            EQUAL(pszName, "COMPRESSION_REVERSIBILITY") &&
142,496✔
6315
            m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
77✔
6316
                                         "IMAGE_STRUCTURE") == nullptr)
6317
        {
6318
            const char *pszDriverName =
60✔
6319
                m_nCompression == COMPRESSION_WEBP ? "WEBP" : "JPEGXL";
60✔
6320
            auto poTileDriver = GDALGetDriverByName(pszDriverName);
60✔
6321
            if (poTileDriver)
60✔
6322
            {
6323
                vsi_l_offset nOffset = 0;
60✔
6324
                vsi_l_offset nSize = 0;
60✔
6325
                IsBlockAvailable(0, &nOffset, &nSize, nullptr);
60✔
6326
                if (nSize > 0)
60✔
6327
                {
6328
                    const std::string osSubfile(
6329
                        CPLSPrintf("/vsisubfile/" CPL_FRMT_GUIB "_%d,%s",
6330
                                   static_cast<GUIntBig>(nOffset),
6331
                                   static_cast<int>(std::min(
25✔
6332
                                       static_cast<vsi_l_offset>(1024), nSize)),
25✔
6333
                                   m_pszFilename));
50✔
6334
                    const char *const apszDrivers[] = {pszDriverName, nullptr};
25✔
6335
                    auto poWebPDataset =
6336
                        std::unique_ptr<GDALDataset>(GDALDataset::Open(
6337
                            osSubfile.c_str(), GDAL_OF_RASTER, apszDrivers));
50✔
6338
                    if (poWebPDataset)
25✔
6339
                    {
6340
                        const char *pszReversibility =
6341
                            poWebPDataset->GetMetadataItem(
25✔
6342
                                "COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
25✔
6343
                        if (pszReversibility)
25✔
6344
                            m_oGTiffMDMD.SetMetadataItem(
25✔
6345
                                "COMPRESSION_REVERSIBILITY", pszReversibility,
6346
                                "IMAGE_STRUCTURE");
6347
                    }
6348
                }
6349
            }
6350
        }
72,247✔
6351
    }
6352
    else
6353
    {
6354
        LoadGeoreferencingAndPamIfNeeded();
73,261✔
6355
    }
6356

6357
    if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
145,509✔
6358
    {
6359
        return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
4✔
6360
    }
6361
    else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
145,505✔
6362
                                      EQUAL(pszDomain, MD_DOMAIN_IMD) ||
145,452✔
6363
                                      EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
145,450✔
6364
    {
6365
        LoadMetadata();
50✔
6366
    }
6367
    else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
145,455✔
6368
    {
6369
        ScanDirectories();
×
6370
    }
6371
    else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
145,455✔
6372
    {
6373
        LoadEXIFMetadata();
1✔
6374
    }
6375
    else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
145,454✔
6376
    {
6377
        LoadICCProfile();
4,869✔
6378
    }
6379
    else if ((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
140,585✔
6380
             pszName != nullptr && EQUAL(pszName, GDALMD_AREA_OR_POINT))
61,990✔
6381
    {
6382
        LoadMDAreaOrPoint();  // To set GDALMD_AREA_OR_POINT.
8,439✔
6383
    }
6384
    else if (pszDomain != nullptr && EQUAL(pszDomain, "_DEBUG_") &&
132,146✔
6385
             pszName != nullptr)
6386
    {
6387
#ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
6388
        if (EQUAL(pszName, "UNREACHED_VIRTUALMEMIO_CODE_PATH"))
6389
        {
6390
            CPLString osMissing;
6391
            for (int i = 0;
6392
                 i < static_cast<int>(CPL_ARRAYSIZE(anReachedVirtualMemIO));
6393
                 ++i)
6394
            {
6395
                if (!anReachedVirtualMemIO[i])
6396
                {
6397
                    if (!osMissing.empty())
6398
                        osMissing += ",";
6399
                    osMissing += CPLSPrintf("%d", i);
6400
                }
6401
            }
6402
            return (osMissing.size()) ? CPLSPrintf("%s", osMissing.c_str())
6403
                                      : nullptr;
6404
        }
6405
        else
6406
#endif
6407
            if (EQUAL(pszName, "TIFFTAG_EXTRASAMPLES"))
79✔
6408
        {
6409
            CPLString osRet;
18✔
6410
            uint16_t *v = nullptr;
18✔
6411
            uint16_t count = 0;
18✔
6412

6413
            if (TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
18✔
6414
            {
6415
                for (int i = 0; i < static_cast<int>(count); ++i)
53✔
6416
                {
6417
                    if (i > 0)
37✔
6418
                        osRet += ",";
21✔
6419
                    osRet += CPLSPrintf("%d", v[i]);
37✔
6420
                }
6421
            }
6422
            return (osRet.size()) ? CPLSPrintf("%s", osRet.c_str()) : nullptr;
18✔
6423
        }
6424
        else if (EQUAL(pszName, "TIFFTAG_PHOTOMETRIC"))
61✔
6425
        {
6426
            return CPLSPrintf("%d", m_nPhotometric);
6✔
6427
        }
6428

6429
        else if (EQUAL(pszName, "TIFFTAG_GDAL_METADATA"))
55✔
6430
        {
6431
            char *pszText = nullptr;
7✔
6432
            if (!TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
7✔
6433
                return nullptr;
6✔
6434

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

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

6523
    return m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
145,425✔
6524
}
6525

6526
/************************************************************************/
6527
/*                         LoadEXIFMetadata()                           */
6528
/************************************************************************/
6529

6530
void GTiffDataset::LoadEXIFMetadata()
58✔
6531
{
6532
    if (m_bEXIFMetadataLoaded)
58✔
6533
        return;
7✔
6534
    m_bEXIFMetadataLoaded = true;
51✔
6535

6536
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
51✔
6537

6538
    GByte abyHeader[2] = {0};
51✔
6539
    if (VSIFSeekL(fp, 0, SEEK_SET) != 0 || VSIFReadL(abyHeader, 1, 2, fp) != 2)
51✔
6540
        return;
×
6541

6542
    const bool bLittleEndian = abyHeader[0] == 'I' && abyHeader[1] == 'I';
51✔
6543
    const bool bLeastSignificantBit = CPL_IS_LSB != 0;
51✔
6544
    const bool bSwabflag = bLittleEndian != bLeastSignificantBit;  // != is XOR.
51✔
6545

6546
    char **papszMetadata = nullptr;
51✔
6547
    toff_t nOffset = 0;  // TODO(b/28199387): Refactor to simplify casting.
51✔
6548

6549
    if (TIFFGetField(m_hTIFF, TIFFTAG_EXIFIFD, &nOffset))
51✔
6550
    {
6551
        int nExifOffset = static_cast<int>(nOffset);
3✔
6552
        int nInterOffset = 0;
3✔
6553
        int nGPSOffset = 0;
3✔
6554
        EXIFExtractMetadata(papszMetadata, fp, static_cast<int>(nOffset),
3✔
6555
                            bSwabflag, 0, nExifOffset, nInterOffset,
6556
                            nGPSOffset);
6557
    }
6558

6559
    if (TIFFGetField(m_hTIFF, TIFFTAG_GPSIFD, &nOffset))
51✔
6560
    {
6561
        int nExifOffset = 0;  // TODO(b/28199387): Refactor to simplify casting.
3✔
6562
        int nInterOffset = 0;
3✔
6563
        int nGPSOffset = static_cast<int>(nOffset);
3✔
6564
        EXIFExtractMetadata(papszMetadata, fp, static_cast<int>(nOffset),
3✔
6565
                            bSwabflag, 0, nExifOffset, nInterOffset,
6566
                            nGPSOffset);
6567
    }
6568

6569
    if (papszMetadata)
51✔
6570
    {
6571
        m_oGTiffMDMD.SetMetadata(papszMetadata, "EXIF");
3✔
6572
        CSLDestroy(papszMetadata);
3✔
6573
    }
6574
}
6575

6576
/************************************************************************/
6577
/*                           LoadMetadata()                             */
6578
/************************************************************************/
6579
void GTiffDataset::LoadMetadata()
20,649✔
6580
{
6581
    if (m_bIMDRPCMetadataLoaded)
20,649✔
6582
        return;
16,109✔
6583
    m_bIMDRPCMetadataLoaded = true;
4,617✔
6584

6585
    if (EQUAL(CPLGetExtensionSafe(GetDescription()).c_str(), "ovr"))
4,617✔
6586
    {
6587
        // Do not attempt to retrieve metadata files on .tif.ovr files.
6588
        // For example the Pleiades metadata reader might wrongly associate a
6589
        // DIM_xxx.XML file that was meant to be associated with the main
6590
        // TIFF file. The consequence of that wrong association is that if
6591
        // one cleans overviews, then the Delete() method would then delete
6592
        // that DIM_xxx.XML file since it would be reported in the GetFileList()
6593
        // of the overview dataset.
6594
        return;
77✔
6595
    }
6596

6597
    GDALMDReaderManager mdreadermanager;
9,080✔
6598
    GDALMDReaderBase *mdreader = mdreadermanager.GetReader(
4,540✔
6599
        m_pszFilename, oOvManager.GetSiblingFiles(), MDR_ANY);
4,540✔
6600

6601
    if (nullptr != mdreader)
4,540✔
6602
    {
6603
        mdreader->FillMetadata(&m_oGTiffMDMD);
65✔
6604

6605
        if (mdreader->GetMetadataDomain(MD_DOMAIN_RPC) == nullptr)
65✔
6606
        {
6607
            char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
36✔
6608
            if (papszRPCMD)
36✔
6609
            {
6610
                m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
12✔
6611
                CSLDestroy(papszRPCMD);
12✔
6612
            }
6613
        }
6614

6615
        m_papszMetadataFiles = mdreader->GetMetadataFiles();
65✔
6616
    }
6617
    else
6618
    {
6619
        char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
4,475✔
6620
        if (papszRPCMD)
4,475✔
6621
        {
6622
            m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
20✔
6623
            CSLDestroy(papszRPCMD);
20✔
6624
        }
6625
    }
6626
}
6627

6628
/************************************************************************/
6629
/*                     HasOptimizedReadMultiRange()                     */
6630
/************************************************************************/
6631

6632
bool GTiffDataset::HasOptimizedReadMultiRange()
2,892,820✔
6633
{
6634
    if (m_nHasOptimizedReadMultiRange >= 0)
2,892,820✔
6635
        return m_nHasOptimizedReadMultiRange != 0;
2,877,390✔
6636
    m_nHasOptimizedReadMultiRange = static_cast<signed char>(
15,295✔
6637
        VSIHasOptimizedReadMultiRange(m_pszFilename)
15,430✔
6638
        // Config option for debug and testing purposes only
6639
        || CPLTestBool(CPLGetConfigOption(
15,294✔
6640
               "GTIFF_HAS_OPTIMIZED_READ_MULTI_RANGE", "NO")));
6641
    return m_nHasOptimizedReadMultiRange != 0;
15,295✔
6642
}
6643

6644
/************************************************************************/
6645
/*                         CacheMultiRange()                            */
6646
/************************************************************************/
6647

6648
static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
258✔
6649
{
6650
    GByte abyTrailer[4];
6651
    memcpy(abyTrailer, strileData + nStrileSize, 4);
258✔
6652
    GByte abyLastBytes[4] = {};
258✔
6653
    if (nStrileSize >= 4)
258✔
6654
        memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
258✔
6655
    else
6656
    {
6657
        // The last bytes will be zero due to the above {} initialization,
6658
        // and that's what should be in abyTrailer too when the trailer is
6659
        // correct.
6660
        memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
×
6661
    }
6662
    return memcmp(abyTrailer, abyLastBytes, 4) == 0;
258✔
6663
}
6664

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

6703
    struct StrileData
6704
    {
6705
        vsi_l_offset nOffset;
6706
        vsi_l_offset nByteCount;
6707
        bool bTryMask;
6708
    };
6709

6710
    std::map<int, StrileData> oMapStrileToOffsetByteCount;
540✔
6711

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

6812
    // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
6813
    // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
6814
    // mask) from the temporary oMapStrileToOffsetByteCount.
6815
    auto FillCacheStrileToOffsetByteCount =
6816
        [&](const std::vector<vsi_l_offset> &anOffsets,
38✔
6817
            const std::vector<size_t> &anSizes,
6818
            const std::vector<void *> &apData)
6819
    {
6820
        CPLAssert(m_bLeaderSizeAsUInt4);
38✔
6821
        size_t i = 0;
38✔
6822
        vsi_l_offset nLastOffset = 0;
38✔
6823
        for (const auto &entry : oMapStrileToOffsetByteCount)
217✔
6824
        {
6825
            const auto nBlockId = entry.first;
179✔
6826
            const auto nOffset = entry.second.nOffset;
179✔
6827
            const auto nSize = entry.second.nByteCount;
179✔
6828
            if (nOffset == 0)
179✔
6829
            {
6830
                // Sparse tile
6831
                m_oCacheStrileToOffsetByteCount.insert(nBlockId,
6832
                                                       std::pair(0, 0));
23✔
6833
                continue;
77✔
6834
            }
6835

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

6885
            {
6886
                const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
156✔
6887
                const vsi_l_offset nRealSize = nSizeFromLeader;
156✔
6888
#ifdef DEBUG_VERBOSE
6889
                CPLDebug("GTiff",
6890
                         "Block %d found at offset " CPL_FRMT_GUIB
6891
                         " with size " CPL_FRMT_GUIB,
6892
                         nBlockId, nRealOffset, nRealSize);
6893
#endif
6894
                m_oCacheStrileToOffsetByteCount.insert(
6895
                    nBlockId, std::pair(nRealOffset, nRealSize));
156✔
6896
            }
6897

6898
            // Processing of mask
6899
            if (!(entry.second.bTryMask && m_bMaskInterleavedWithImagery &&
258✔
6900
                  GetRasterBand(1)->GetMaskBand() && m_poMaskDS))
102✔
6901
            {
6902
                continue;
54✔
6903
            }
6904

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

6951
                    m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
102✔
6952
                        nBlockId, std::pair(nRealOffset, nRealSize));
102✔
6953
                }
6954
            }
6955
            if (!bOK)
102✔
6956
            {
6957
                CPLDebug("GTiff",
×
6958
                         "Mask for block %d is not properly interleaved with "
6959
                         "imagery block",
6960
                         nBlockId);
6961
            }
6962
        }
6963
        return true;
38✔
6964
    };
270✔
6965

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

6996
                    if (!m_bStreamingIn && m_bBlockOrderRowMajor &&
425✔
6997
                        m_bLeaderSizeAsUInt4)
219✔
6998
                    {
6999
                        OptimizedRetrievalOfOffsetSize(nBand, nBlockId, nOffset,
219✔
7000
                                                       nSize, nTotalSize,
7001
                                                       nMaxRawBlockCacheSize);
7002
                    }
7003
                    else
7004
                    {
7005
                        CPL_IGNORE_RET_VAL(IsBlockAvailable(nBlockId, &nOffset,
206✔
7006
                                                            &nSize, nullptr));
7007
                    }
7008
                    if (nSize)
425✔
7009
                    {
7010
                        if (nTotalSize + nSize < nMaxRawBlockCacheSize)
167✔
7011
                        {
7012
#ifdef DEBUG_VERBOSE
7013
                            CPLDebug(
7014
                                "GTiff",
7015
                                "Precaching for block (%d, %d), " CPL_FRMT_GUIB
7016
                                "-" CPL_FRMT_GUIB,
7017
                                iX, iY, nOffset,
7018
                                nOffset + static_cast<size_t>(nSize) - 1);
7019
#endif
7020
                            aOffsetSize.push_back(
167✔
7021
                                std::pair(nOffset, static_cast<size_t>(nSize)));
167✔
7022
                            nTotalSize += static_cast<size_t>(nSize);
167✔
7023
                        }
7024
                        else
7025
                        {
7026
                            bGoOn = false;
×
7027
                        }
7028
                    }
7029
                }
7030
            }
7031
        }
7032

7033
        std::sort(aOffsetSize.begin(), aOffsetSize.end());
236✔
7034

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

7093
                VSILFILE *fp = VSI_TIFFGetVSILFile(th);
43✔
7094

7095
                // An error in VSIFReadMultiRangeL() will not be critical,
7096
                // as this method is an optimization, and if it fails,
7097
                // tile-by-tile data acquisition will be done, so we can
7098
                // temporary turn failures into warnings.
7099
                bool ok;
7100
                {
7101
                    CPLTurnFailureIntoWarningBackuper
7102
                        oFailureToWarningBackuper{};
43✔
7103
                    ok = VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
43✔
7104
                                             &apData[0], &anOffsets[0],
43✔
7105
                                             &anSizes[0], fp) == 0;
43✔
7106
                }
7107

7108
                if (ok)
43✔
7109
                {
7110
                    if (!oMapStrileToOffsetByteCount.empty() &&
81✔
7111
                        !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
38✔
7112
                                                          apData))
7113
                    {
7114
                        // Retry without optimization
7115
                        CPLFree(pBufferedData);
×
7116
                        m_bLeaderSizeAsUInt4 = false;
×
7117
                        void *pRet = CacheMultiRange(
×
7118
                            nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
7119
                            panBandMap, nBandCount, psExtraArg);
7120
                        m_bLeaderSizeAsUInt4 = true;
×
7121
                        return pRet;
×
7122
                    }
7123

7124
                    VSI_TIFFSetCachedRanges(
43✔
7125
                        th, static_cast<int>(anSizes.size()), &apData[0],
43✔
7126
                        &anOffsets[0], &anSizes[0]);
43✔
7127
                }
7128
                else
7129
                {
7130
                    CPLFree(pBufferedData);
×
7131
                    pBufferedData = nullptr;
×
7132
                }
7133
            }
7134
        }
7135
    }
7136
    return pBufferedData;
270✔
7137
}
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