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

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 hits per line

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

88.55
/frmts/gtiff/gtiffrasterband_read.cpp
1
/******************************************************************************
2
 *
3
 * Project:  GeoTIFF Driver
4
 * Purpose:  Read/get operations on GTiffRasterBand
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 "gtiffrasterband.h"
15
#include "gtiffdataset.h"
16
#include "gtiffjpegoverviewds.h"
17

18
#include <algorithm>
19
#include <cassert>
20
#include <limits>
21
#include <map>
22
#include <set>
23
#include <utility>
24

25
#include "cpl_vsi_virtual.h"
26
#include "fetchbufferdirectio.h"
27
#include "gtiff.h"
28
#include "tifvsi.h"
29

30
/************************************************************************/
31
/*                           GetDefaultRAT()                            */
32
/************************************************************************/
33

34
GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
3,300✔
35

36
{
37
    if (m_poRAT)
3,300✔
38
        return m_poRAT.get();
2✔
39

40
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
3,298✔
41
    auto poRAT = GDALPamRasterBand::GetDefaultRAT();
3,298✔
42
    if (poRAT)
3,298✔
43
        return poRAT;
7✔
44

45
    if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_pszFilename))
3,291✔
46
        return nullptr;
×
47
    const std::string osVATDBF =
48
        std::string(m_poGDS->m_pszFilename) + ".vat.dbf";
9,873✔
49
    CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
3,291✔
50
    if (papszSiblingFiles &&
6,548✔
51
        // cppcheck-suppress knownConditionTrueFalse
52
        GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
3,257✔
53
    {
54
        int iSibling =
55
            CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
3,257✔
56
        if (iSibling >= 0)
3,257✔
57
        {
58
            CPLString osFilename = m_poGDS->m_pszFilename;
2✔
59
            osFilename.resize(strlen(m_poGDS->m_pszFilename) -
4✔
60
                              strlen(CPLGetFilename(m_poGDS->m_pszFilename)));
2✔
61
            osFilename += papszSiblingFiles[iSibling];
2✔
62
            m_poRAT = GDALLoadVATDBF(osFilename.c_str());
2✔
63
        }
64
        return m_poRAT.get();
3,257✔
65
    }
66
    VSIStatBufL sStatBuf;
67
    if (VSIStatL(osVATDBF.c_str(), &sStatBuf) == 0)
34✔
68
        m_poRAT = GDALLoadVATDBF(osVATDBF.c_str());
1✔
69
    return m_poRAT.get();
34✔
70
}
71

72
/************************************************************************/
73
/*                           GetHistogram()                             */
74
/************************************************************************/
75

76
CPLErr GTiffRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
20✔
77
                                     GUIntBig *panHistogram,
78
                                     int bIncludeOutOfRange, int bApproxOK,
79
                                     GDALProgressFunc pfnProgress,
80
                                     void *pProgressData)
81
{
82
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
20✔
83
    return GDALPamRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
20✔
84
                                           bIncludeOutOfRange, bApproxOK,
85
                                           pfnProgress, pProgressData);
20✔
86
}
87

88
/************************************************************************/
89
/*                       GetDefaultHistogram()                          */
90
/************************************************************************/
91

92
CPLErr GTiffRasterBand::GetDefaultHistogram(
21✔
93
    double *pdfMin, double *pdfMax, int *pnBuckets, GUIntBig **ppanHistogram,
94
    int bForce, GDALProgressFunc pfnProgress, void *pProgressData)
95
{
96
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
21✔
97
    return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
21✔
98
                                                  ppanHistogram, bForce,
99
                                                  pfnProgress, pProgressData);
21✔
100
}
101

102
/************************************************************************/
103
/*                           DirectIO()                                 */
104
/************************************************************************/
105

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

112
int GTiffRasterBand::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2,098✔
113
                              int nXSize, int nYSize, void *pData,
114
                              int nBufXSize, int nBufYSize,
115
                              GDALDataType eBufType, GSpacing nPixelSpace,
116
                              GSpacing nLineSpace,
117
                              GDALRasterIOExtraArg *psExtraArg)
118
{
119
    const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
2,098✔
120
    if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
4,196✔
121
          (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
2,098✔
122
           m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
795✔
123
           m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
×
124
          IsBaseGTiffClass()))
2,098✔
125
    {
126
        return -1;
×
127
    }
128
    m_poGDS->Crystalize();
2,098✔
129

130
    // Only know how to deal with nearest neighbour in this optimized routine.
131
    if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
2,098✔
132
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
447✔
133
    {
134
        return -1;
66✔
135
    }
136

137
#if DEBUG_VERBOSE
138
    CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
139
             nYSize, nBufXSize, nBufYSize);
140
#endif
141

142
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
143
    if (m_poGDS->GetAccess() == GA_Update)
2,032✔
144
    {
145
        m_poGDS->FlushCache(false);
×
146
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
×
147
    }
148

149
    if (TIFFIsTiled(m_poGDS->m_hTIFF))
2,032✔
150
    {
151
        const int nDTSize = nDTSizeBits / 8;
504✔
152
        const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
504✔
153
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize * nDTSize *
1,008✔
154
            (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands
504✔
155
                                                             : 1));
156
        if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
504✔
157
        {
158
            m_poGDS->m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
28✔
159
                VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
14✔
160
            if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
14✔
161
                return CE_Failure;
×
162
        }
163

164
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
504✔
165
        FetchBufferDirectIO oFetcher(fp,
166
                                     m_poGDS->m_pTempBufferForCommonDirectIO,
504✔
167
                                     nTempBufferForCommonDirectIOSize);
504✔
168

169
        return m_poGDS->CommonDirectIOClassic(
1,008✔
170
            oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
171
            eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0);
504✔
172
    }
173

174
    // Get strip offsets.
175
    toff_t *panTIFFOffsets = nullptr;
1,528✔
176
    if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
1,528✔
177
                      &panTIFFOffsets) ||
3,056✔
178
        panTIFFOffsets == nullptr)
1,528✔
179
    {
180
        return CE_Failure;
×
181
    }
182

183
    // Sub-sampling or over-sampling can only be done at last stage.
184
    int nReqXSize = nXSize;
1,528✔
185
    // Can do sub-sampling at the extraction stage.
186
    const int nReqYSize = std::min(nBufYSize, nYSize);
1,528✔
187
    // TODO(schwehr): Make ppData be GByte**.
188
    void **ppData =
189
        static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
1,528✔
190
    vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
191
        VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
1,528✔
192
    size_t *panSizes =
193
        static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
1,528✔
194
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
1,528✔
195
    void *pTmpBuffer = nullptr;
1,528✔
196
    int eErr = CE_None;
1,528✔
197
    int nContigBands =
1,528✔
198
        m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
1,528✔
199
    int nSrcPixelSize = nDTSize * nContigBands;
1,528✔
200

201
    if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
1,528✔
202
        eErr = CE_Failure;
×
203
    else if (nXSize != nBufXSize || nYSize != nBufYSize ||
1,295✔
204
             eBufType != eDataType ||
1,295✔
205
             nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
2,823✔
206
             nContigBands > 1)
207
    {
208
        // We need a temporary buffer for over-sampling/sub-sampling
209
        // and/or data type conversion.
210
        pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
1,388✔
211
        if (pTmpBuffer == nullptr)
1,388✔
212
            eErr = CE_Failure;
×
213
    }
214

215
    // Prepare data extraction.
216
    const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
1,528✔
217

218
    for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
41,509✔
219
    {
220
        if (pTmpBuffer == nullptr)
39,981✔
221
            ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
10,980✔
222
        else
223
            ppData[iLine] =
29,001✔
224
                static_cast<GByte *>(pTmpBuffer) +
29,001✔
225
                static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
29,001✔
226
        int nSrcLine = 0;
39,981✔
227
        if (nBufYSize < nYSize)  // Sub-sampling in y.
39,981✔
228
            nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
2,440✔
229
        else
230
            nSrcLine = nYOff + iLine;
37,541✔
231

232
        const int nBlockXOff = 0;
39,981✔
233
        const int nBlockYOff = nSrcLine / nBlockYSize;
39,981✔
234
        const int nYOffsetInBlock = nSrcLine % nBlockYSize;
39,981✔
235
        const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
39,981✔
236

237
        panOffsets[iLine] = panTIFFOffsets[nBlockId];
39,981✔
238
        if (panOffsets[iLine] == 0)  // We don't support sparse files.
39,981✔
239
            eErr = -1;
1,047✔
240

241
        panOffsets[iLine] +=
39,981✔
242
            (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
39,981✔
243
            nSrcPixelSize;
39,981✔
244
        panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
39,981✔
245
    }
246

247
    // Extract data from the file.
248
    if (eErr == CE_None)
1,528✔
249
    {
250
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
481✔
251
        const int nRet =
252
            VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
481✔
253
        if (nRet != 0)
481✔
254
            eErr = CE_Failure;
12✔
255
    }
256

257
    // Byte-swap if necessary.
258
    if (eErr == CE_None && TIFFIsByteSwapped(m_poGDS->m_hTIFF))
1,528✔
259
    {
260
        for (int iLine = 0; iLine < nReqYSize; ++iLine)
4,144✔
261
        {
262
            if (GDALDataTypeIsComplex(eDataType))
4,094✔
263
                GDALSwapWords(ppData[iLine], nDTSize / 2,
2,396✔
264
                              2 * nReqXSize * nContigBands, nDTSize / 2);
2,396✔
265
            else
266
                GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
1,698✔
267
                              nDTSize);
268
        }
269
    }
270

271
    // Over-sampling/sub-sampling and/or data type conversion.
272
    const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
1,528✔
273
    if (eErr == CE_None && pTmpBuffer != nullptr)
1,528✔
274
    {
275
        const bool bOneByteCopy =
364✔
276
            (eDataType == eBufType &&
656✔
277
             (eDataType == GDT_Byte || eDataType == GDT_Int8));
292✔
278
        for (int iY = 0; iY < nBufYSize; ++iY)
96,459✔
279
        {
280
            const int iSrcY = nBufYSize <= nYSize
192,190✔
281
                                  ? iY
96,095✔
282
                                  : static_cast<int>((iY + 0.5) * dfSrcYInc);
73,872✔
283

284
            GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
192,190✔
285
                                 (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
96,095✔
286
            GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
96,095✔
287
            if (nBufXSize == nXSize)
96,095✔
288
            {
289
                GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
19,798✔
290
                              pabyDstData, eBufType,
291
                              static_cast<int>(nPixelSpace), nBufXSize);
292
            }
293
            else
294
            {
295
                if (bOneByteCopy)
76,297✔
296
                {
297
                    double dfSrcX = 0.5 * dfSrcXInc;
25,435✔
298
                    for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
2,147,110✔
299
                    {
300
                        const int iSrcX = static_cast<int>(dfSrcX);
2,121,670✔
301
                        pabyDstData[iX * nPixelSpace] =
2,121,670✔
302
                            pabySrcData[iSrcX * nSrcPixelSize];
2,121,670✔
303
                    }
304
                }
305
                else
306
                {
307
                    double dfSrcX = 0.5 * dfSrcXInc;
50,862✔
308
                    for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
4,293,180✔
309
                    {
310
                        const int iSrcX = static_cast<int>(dfSrcX);
4,242,320✔
311
                        GDALCopyWords(
4,242,320✔
312
                            pabySrcData + iSrcX * nSrcPixelSize, eDataType, 0,
4,242,320✔
313
                            pabyDstData + iX * nPixelSpace, eBufType, 0, 1);
4,242,320✔
314
                    }
315
                }
316
            }
317
        }
318
    }
319

320
    // Cleanup.
321
    CPLFree(pTmpBuffer);
1,528✔
322
    CPLFree(ppData);
1,528✔
323
    CPLFree(panOffsets);
1,528✔
324
    CPLFree(panSizes);
1,528✔
325

326
    return eErr;
1,528✔
327
}
328

329
/************************************************************************/
330
/*                           GetVirtualMemAuto()                        */
331
/************************************************************************/
332

333
CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
17✔
334
                                                  int *pnPixelSpace,
335
                                                  GIntBig *pnLineSpace,
336
                                                  char **papszOptions)
337
{
338
    const char *pszImpl = CSLFetchNameValueDef(
17✔
339
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
340
    if (EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") || EQUAL(pszImpl, "1") ||
17✔
341
        EQUAL(pszImpl, "TRUE"))
16✔
342
    {
343
        return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
1✔
344
                                                 pnLineSpace, papszOptions);
1✔
345
    }
346

347
    CPLVirtualMem *psRet = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace,
16✔
348
                                                     pnLineSpace, papszOptions);
349
    if (psRet != nullptr)
16✔
350
    {
351
        CPLDebug("GTiff", "GetVirtualMemAuto(): Using memory file mapping");
14✔
352
        return psRet;
14✔
353
    }
354

355
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
2✔
356
        EQUAL(pszImpl, "FALSE"))
1✔
357
    {
358
        return nullptr;
1✔
359
    }
360

361
    CPLDebug("GTiff", "GetVirtualMemAuto(): Defaulting to base implementation");
1✔
362
    return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
1✔
363
                                             papszOptions);
1✔
364
}
365

366
/************************************************************************/
367
/*                     DropReferenceVirtualMem()                        */
368
/************************************************************************/
369

370
void GTiffRasterBand::DropReferenceVirtualMem(void *pUserData)
8✔
371
{
372
    // This function may also be called when the dataset and rasterband
373
    // objects have been destroyed.
374
    // If they are still alive, it updates the reference counter of the
375
    // base mapping to invalidate the pointer to it if needed.
376

377
    GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(pUserData);
8✔
378
    GTiffRasterBand *poSelf = *ppoSelf;
8✔
379

380
    if (poSelf != nullptr)
8✔
381
    {
382
        if (--(poSelf->m_poGDS->m_nRefBaseMapping) == 0)
8✔
383
        {
384
            poSelf->m_poGDS->m_pBaseMapping = nullptr;
4✔
385
        }
386
        poSelf->m_aSetPSelf.erase(ppoSelf);
8✔
387
    }
388
    CPLFree(pUserData);
8✔
389
}
8✔
390

391
/************************************************************************/
392
/*                     GetVirtualMemAutoInternal()                      */
393
/************************************************************************/
394

395
CPLVirtualMem *GTiffRasterBand::GetVirtualMemAutoInternal(GDALRWFlag eRWFlag,
20✔
396
                                                          int *pnPixelSpace,
397
                                                          GIntBig *pnLineSpace,
398
                                                          char **papszOptions)
399
{
400
    int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
20✔
401
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
20✔
402
        nLineSize *= m_poGDS->nBands;
14✔
403

404
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
20✔
405
    {
406
        // In case of a pixel interleaved file, we save virtual memory space
407
        // by reusing a base mapping that embraces the whole imagery.
408
        if (m_poGDS->m_pBaseMapping != nullptr)
14✔
409
        {
410
            // Offset between the base mapping and the requested mapping.
411
            vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
8✔
412
                                   GDALGetDataTypeSizeBytes(eDataType);
8✔
413

414
            GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
415
                CPLCalloc(1, sizeof(GTiffRasterBand *)));
8✔
416
            *ppoSelf = this;
8✔
417

418
            CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
24✔
419
                m_poGDS->m_pBaseMapping, nOffset,
8✔
420
                CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
8✔
421
                GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
422
            if (pVMem == nullptr)
8✔
423
            {
424
                CPLFree(ppoSelf);
×
425
                return nullptr;
×
426
            }
427

428
            // Mechanism used so that the memory mapping object can be
429
            // destroyed after the raster band.
430
            m_aSetPSelf.insert(ppoSelf);
8✔
431
            ++m_poGDS->m_nRefBaseMapping;
8✔
432
            *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
8✔
433
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
8✔
434
                *pnPixelSpace *= m_poGDS->nBands;
8✔
435
            *pnLineSpace = nLineSize;
8✔
436
            return pVMem;
8✔
437
        }
438
    }
439

440
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
12✔
441

442
    vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
12✔
443

444
    if (!(CPLIsVirtualMemFileMapAvailable() &&
24✔
445
          VSIFGetNativeFileDescriptorL(fp) != nullptr &&
12✔
446
#if SIZEOF_VOIDP == 4
447
          nLength == static_cast<size_t>(nLength) &&
448
#endif
449
          m_poGDS->m_nCompression == COMPRESSION_NONE &&
10✔
450
          (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
10✔
451
           m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
×
452
           m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
×
453
          m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
10✔
454
          !TIFFIsTiled(m_poGDS->m_hTIFF) &&
10✔
455
          !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
10✔
456
    {
457
        return nullptr;
2✔
458
    }
459

460
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
461
    if (m_poGDS->GetAccess() == GA_Update)
10✔
462
    {
463
        m_poGDS->FlushCache(false);
7✔
464
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
7✔
465
    }
466

467
    // Get strip offsets.
468
    toff_t *panTIFFOffsets = nullptr;
10✔
469
    if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
10✔
470
                      &panTIFFOffsets) ||
20✔
471
        panTIFFOffsets == nullptr)
10✔
472
    {
473
        return nullptr;
×
474
    }
475

476
    GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
10✔
477
                            GDALGetDataTypeSizeBytes(eDataType);
10✔
478
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
10✔
479
        nBlockSize *= m_poGDS->nBands;
4✔
480

481
    int nBlocks = m_poGDS->m_nBlocksPerBand;
10✔
482
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
10✔
483
        nBlocks *= m_poGDS->nBands;
6✔
484
    int i = 0;  // Used after for.
10✔
485
    for (; i < nBlocks; ++i)
103✔
486
    {
487
        if (panTIFFOffsets[i] != 0)
100✔
488
            break;
7✔
489
    }
490
    if (i == nBlocks)
10✔
491
    {
492
        // All zeroes.
493
        if (m_poGDS->eAccess == GA_Update)
3✔
494
        {
495
            // Initialize the file with empty blocks so that the file has
496
            // the appropriate size.
497

498
            toff_t *panByteCounts = nullptr;
3✔
499
            if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
3✔
500
                              &panByteCounts) ||
6✔
501
                panByteCounts == nullptr)
3✔
502
            {
503
                return nullptr;
×
504
            }
505
            if (VSIFSeekL(fp, 0, SEEK_END) != 0)
3✔
506
                return nullptr;
×
507
            vsi_l_offset nBaseOffset = VSIFTellL(fp);
3✔
508

509
            // Just write one tile with libtiff to put it in appropriate state.
510
            GByte *pabyData =
511
                static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
3✔
512
            if (pabyData == nullptr)
3✔
513
            {
514
                return nullptr;
×
515
            }
516
            const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
3✔
517
                                                   pabyData, nBlockSize);
518
            VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
3✔
519
            VSIFree(pabyData);
3✔
520
            if (ret != nBlockSize)
3✔
521
            {
522
                return nullptr;
×
523
            }
524
            CPLAssert(panTIFFOffsets[0] == nBaseOffset);
3✔
525
            CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
3✔
526

527
            // Now simulate the writing of other blocks.
528
            assert(nBlocks > 0);
3✔
529
            assert(static_cast<vsi_l_offset>(nBlockSize) <
3✔
530
                   std::numeric_limits<vsi_l_offset>::max() / nBlocks);
531
            const vsi_l_offset nDataSize =
3✔
532
                static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
3✔
533
            if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
3✔
534
                return nullptr;
×
535

536
            for (i = 1; i < nBlocks; ++i)
93✔
537
            {
538
                panTIFFOffsets[i] =
90✔
539
                    nBaseOffset + i * static_cast<toff_t>(nBlockSize);
90✔
540
                panByteCounts[i] = nBlockSize;
90✔
541
            }
542
        }
543
        else
544
        {
545
            CPLDebug("GTiff", "Sparse files not supported in file mapping");
×
546
            return nullptr;
×
547
        }
548
    }
549

550
    GIntBig nBlockSpacing = 0;
10✔
551
    bool bCompatibleSpacing = true;
10✔
552
    toff_t nPrevOffset = 0;
10✔
553
    for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
229✔
554
    {
555
        toff_t nCurOffset = 0;
219✔
556
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
219✔
557
            nCurOffset =
96✔
558
                panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
96✔
559
        else
560
            nCurOffset = panTIFFOffsets[i];
123✔
561
        if (nCurOffset == 0)
219✔
562
        {
563
            bCompatibleSpacing = false;
×
564
            break;
×
565
        }
566
        if (i > 0)
219✔
567
        {
568
            const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
209✔
569
            if (i == 1)
209✔
570
            {
571
                if (nCurSpacing !=
10✔
572
                    static_cast<GIntBig>(nBlockYSize) * nLineSize)
10✔
573
                {
574
                    bCompatibleSpacing = false;
×
575
                    break;
×
576
                }
577
                nBlockSpacing = nCurSpacing;
10✔
578
            }
579
            else if (nBlockSpacing != nCurSpacing)
199✔
580
            {
581
                bCompatibleSpacing = false;
×
582
                break;
×
583
            }
584
        }
585
        nPrevOffset = nCurOffset;
219✔
586
    }
587

588
    if (!bCompatibleSpacing)
10✔
589
    {
590
        return nullptr;
×
591
    }
592

593
    vsi_l_offset nOffset = 0;
10✔
594
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
10✔
595
    {
596
        CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
4✔
597
        nOffset = panTIFFOffsets[0];
4✔
598
    }
599
    else
600
    {
601
        nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
6✔
602
    }
603
    CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
10✔
604
        fp, nOffset, nLength,
605
        eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
606
        nullptr, nullptr);
607
    if (pVMem == nullptr)
10✔
608
    {
609
        return nullptr;
×
610
    }
611

612
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
10✔
613
    {
614
        // TODO(schwehr): Revisit this block.
615
        m_poGDS->m_pBaseMapping = pVMem;
4✔
616
        pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
4✔
617
                                          papszOptions);
618
        // Drop ref on base mapping.
619
        CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
4✔
620
        if (pVMem == nullptr)
4✔
621
            m_poGDS->m_pBaseMapping = nullptr;
×
622
    }
623
    else
624
    {
625
        *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
6✔
626
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
6✔
627
            *pnPixelSpace *= m_poGDS->nBands;
×
628
        *pnLineSpace = nLineSize;
6✔
629
    }
630
    return pVMem;
10✔
631
}
632

633
/************************************************************************/
634
/*                         CacheMultiRange()                            */
635
/************************************************************************/
636

637
static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
234✔
638
{
639
    GByte abyTrailer[4];
640
    memcpy(abyTrailer, strileData + nStrileSize, 4);
234✔
641
    GByte abyLastBytes[4] = {};
234✔
642
    if (nStrileSize >= 4)
234✔
643
        memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
234✔
644
    else
645
    {
646
        // The last bytes will be zero due to the above {} initialization,
647
        // and that's what should be in abyTrailer too when the trailer is
648
        // correct.
649
        memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
×
650
    }
651
    return memcmp(abyTrailer, abyLastBytes, 4) == 0;
234✔
652
}
653

654
void *GTiffRasterBand::CacheMultiRange(int nXOff, int nYOff, int nXSize,
262✔
655
                                       int nYSize, int nBufXSize, int nBufYSize,
656
                                       GDALRasterIOExtraArg *psExtraArg)
657
{
658
    void *pBufferedData = nullptr;
262✔
659
    // Same logic as in GDALRasterBand::IRasterIO()
660
    double dfXOff = nXOff;
262✔
661
    double dfYOff = nYOff;
262✔
662
    double dfXSize = nXSize;
262✔
663
    double dfYSize = nYSize;
262✔
664
    if (psExtraArg->bFloatingPointWindowValidity)
262✔
665
    {
666
        dfXOff = psExtraArg->dfXOff;
48✔
667
        dfYOff = psExtraArg->dfYOff;
48✔
668
        dfXSize = psExtraArg->dfXSize;
48✔
669
        dfYSize = psExtraArg->dfYSize;
48✔
670
    }
671
    const double dfSrcXInc = dfXSize / static_cast<double>(nBufXSize);
262✔
672
    const double dfSrcYInc = dfYSize / static_cast<double>(nBufYSize);
262✔
673
    const double EPS = 1e-10;
262✔
674
    const int nBlockX1 =
675
        static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
262✔
676
        nBlockXSize;
262✔
677
    const int nBlockY1 =
678
        static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
262✔
679
        nBlockYSize;
262✔
680
    const int nBlockX2 =
681
        static_cast<int>(
262✔
682
            std::min(static_cast<double>(nRasterXSize - 1),
524✔
683
                     (nBufXSize - 1 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
262✔
684
        nBlockXSize;
262✔
685
    const int nBlockY2 =
686
        static_cast<int>(
262✔
687
            std::min(static_cast<double>(nRasterYSize - 1),
524✔
688
                     (nBufYSize - 1 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
262✔
689
        nBlockYSize;
262✔
690

691
    const int nBlockCount = nBlocksPerRow * nBlocksPerColumn;
262✔
692

693
    struct StrileData
694
    {
695
        vsi_l_offset nOffset;
696
        vsi_l_offset nByteCount;
697
        bool bTryMask;
698
    };
699

700
    std::map<int, StrileData> oMapStrileToOffsetByteCount;
524✔
701

702
    // Dedicated method to retrieved the offset and size in an efficient way
703
    // when m_bBlockOrderRowMajor and m_bLeaderSizeAsUInt4 conditions are
704
    // met.
705
    // Except for the last block, we just read the offset from the TIFF offset
706
    // array, and retrieve the size in the leader 4 bytes that come before the
707
    // payload.
708
    auto OptimizedRetrievalOfOffsetSize =
709
        [&](int nBlockId, vsi_l_offset &nOffset, vsi_l_offset &nSize,
195✔
710
            size_t nTotalSize, size_t nMaxRawBlockCacheSize)
711
    {
712
        bool bTryMask = m_poGDS->m_bMaskInterleavedWithImagery;
438✔
713
        nOffset = TIFFGetStrileOffset(m_poGDS->m_hTIFF, nBlockId);
195✔
714
        if (nOffset >= 4)
195✔
715
        {
716
            if (nBlockId == nBlockCount - 1)
132✔
717
            {
718
                // Special case for the last block. As there is no next block
719
                // from which to retrieve an offset, use the good old method
720
                // that consists in reading the ByteCount array.
721
                if (bTryMask && m_poGDS->GetRasterBand(1)->GetMaskBand() &&
49✔
722
                    m_poGDS->m_poMaskDS)
23✔
723
                {
724
                    auto nMaskOffset = TIFFGetStrileOffset(
46✔
725
                        m_poGDS->m_poMaskDS->m_hTIFF, nBlockId);
23✔
726
                    if (nMaskOffset)
23✔
727
                    {
728
                        nSize = nMaskOffset +
23✔
729
                                TIFFGetStrileByteCount(
46✔
730
                                    m_poGDS->m_poMaskDS->m_hTIFF, nBlockId) -
23✔
731
                                nOffset;
23✔
732
                    }
733
                    else
734
                    {
735
                        bTryMask = false;
×
736
                    }
737
                }
738
                if (nSize == 0)
26✔
739
                {
740
                    nSize = TIFFGetStrileByteCount(m_poGDS->m_hTIFF, nBlockId);
3✔
741
                }
742
                if (nSize && m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
26✔
743
                {
744
                    nSize += 4;
26✔
745
                }
746
            }
747
            else
748
            {
749
                auto nOffsetNext =
750
                    TIFFGetStrileOffset(m_poGDS->m_hTIFF, nBlockId + 1);
106✔
751
                if (nOffsetNext > nOffset)
106✔
752
                {
753
                    nSize = nOffsetNext - nOffset;
98✔
754
                }
755
                else
756
                {
757
                    // Shouldn't happen for a compliant file
758
                    if (nOffsetNext != 0)
8✔
759
                    {
760
                        CPLDebug("GTiff", "Tile %d is not located after %d",
×
761
                                 nBlockId + 1, nBlockId);
762
                    }
763
                    bTryMask = false;
8✔
764
                    nSize = TIFFGetStrileByteCount(m_poGDS->m_hTIFF, nBlockId);
8✔
765
                    if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
8✔
766
                        nSize += 4;
8✔
767
                }
768
            }
769
            if (nSize)
132✔
770
            {
771
                nOffset -= 4;
132✔
772
                nSize += 4;
132✔
773
                if (nTotalSize + nSize < nMaxRawBlockCacheSize)
132✔
774
                {
775
                    StrileData data;
776
                    data.nOffset = nOffset;
132✔
777
                    data.nByteCount = nSize;
132✔
778
                    data.bTryMask = bTryMask;
132✔
779
                    oMapStrileToOffsetByteCount[nBlockId] = data;
132✔
780
                }
781
            }
782
        }
783
        else
784
        {
785
            // Sparse tile
786
            StrileData data;
787
            data.nOffset = 0;
63✔
788
            data.nByteCount = 0;
63✔
789
            data.bTryMask = false;
63✔
790
            oMapStrileToOffsetByteCount[nBlockId] = data;
63✔
791
        }
792
    };
195✔
793

794
    // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
795
    // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
796
    // mask) from the temporary oMapStrileToOffsetByteCount.
797
    auto FillCacheStrileToOffsetByteCount =
798
        [&](const std::vector<vsi_l_offset> &anOffsets,
36✔
799
            const std::vector<size_t> &anSizes,
800
            const std::vector<void *> &apData)
801
    {
802
        CPLAssert(m_poGDS->m_bLeaderSizeAsUInt4);
36✔
803
        size_t i = 0;
36✔
804
        vsi_l_offset nLastOffset = 0;
36✔
805
        for (const auto &entry : oMapStrileToOffsetByteCount)
191✔
806
        {
807
            const auto nBlockId = entry.first;
155✔
808
            const auto nOffset = entry.second.nOffset;
155✔
809
            const auto nSize = entry.second.nByteCount;
155✔
810
            if (nOffset == 0)
155✔
811
            {
812
                // Sparse tile
813
                m_poGDS->m_oCacheStrileToOffsetByteCount.insert(
23✔
814
                    nBlockId, std::pair(0, 0));
23✔
815
                continue;
53✔
816
            }
817

818
            if (nOffset < nLastOffset)
132✔
819
            {
820
                // shouldn't happen normally if tiles are sorted
821
                i = 0;
×
822
            }
823
            nLastOffset = nOffset;
132✔
824
            while (i < anOffsets.size() &&
272✔
825
                   !(nOffset >= anOffsets[i] &&
136✔
826
                     nOffset + nSize <= anOffsets[i] + anSizes[i]))
136✔
827
            {
828
                i++;
4✔
829
            }
830
            CPLAssert(i < anOffsets.size());
132✔
831
            CPLAssert(nOffset >= anOffsets[i]);
132✔
832
            CPLAssert(nOffset + nSize <= anOffsets[i] + anSizes[i]);
132✔
833
            GUInt32 nSizeFromLeader;
834
            memcpy(&nSizeFromLeader,
132✔
835
                   // cppcheck-suppress containerOutOfBounds
836
                   static_cast<GByte *>(apData[i]) + nOffset - anOffsets[i],
132✔
837
                   sizeof(nSizeFromLeader));
838
            CPL_LSBPTR32(&nSizeFromLeader);
132✔
839
            bool bOK = true;
132✔
840
            constexpr int nLeaderSize = 4;
132✔
841
            const int nTrailerSize =
132✔
842
                (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated ? 4 : 0);
132✔
843
            if (nSizeFromLeader > nSize - nLeaderSize - nTrailerSize)
132✔
844
            {
845
                CPLDebug("GTiff",
×
846
                         "Inconsistent block size from in leader of block %d",
847
                         nBlockId);
848
                bOK = false;
×
849
            }
850
            else if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
132✔
851
            {
852
                // Check trailer consistency
853
                const GByte *strileData = static_cast<GByte *>(apData[i]) +
132✔
854
                                          nOffset - anOffsets[i] + nLeaderSize;
132✔
855
                if (!CheckTrailer(strileData, nSizeFromLeader))
132✔
856
                {
857
                    CPLDebug("GTiff", "Inconsistent trailer of block %d",
×
858
                             nBlockId);
859
                    bOK = false;
×
860
                }
861
            }
862
            if (!bOK)
132✔
863
            {
864
                return false;
×
865
            }
866

867
            {
868
                const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
132✔
869
                const vsi_l_offset nRealSize = nSizeFromLeader;
132✔
870
#ifdef DEBUG_VERBOSE
871
                CPLDebug("GTiff",
872
                         "Block %d found at offset " CPL_FRMT_GUIB
873
                         " with size " CPL_FRMT_GUIB,
874
                         nBlockId, nRealOffset, nRealSize);
875
#endif
876
                m_poGDS->m_oCacheStrileToOffsetByteCount.insert(
132✔
877
                    nBlockId, std::pair(nRealOffset, nRealSize));
132✔
878
            }
879

880
            // Processing of mask
881
            if (!(entry.second.bTryMask &&
234✔
882
                  m_poGDS->m_bMaskInterleavedWithImagery &&
102✔
883
                  m_poGDS->GetRasterBand(1)->GetMaskBand() &&
102✔
884
                  m_poGDS->m_poMaskDS))
102✔
885
            {
886
                continue;
30✔
887
            }
888

889
            bOK = false;
102✔
890
            const vsi_l_offset nMaskOffsetWithLeader =
102✔
891
                nOffset + nLeaderSize + nSizeFromLeader + nTrailerSize;
102✔
892
            if (nMaskOffsetWithLeader + nLeaderSize <=
204✔
893
                anOffsets[i] + anSizes[i])
102✔
894
            {
895
                GUInt32 nMaskSizeFromLeader;
896
                memcpy(&nMaskSizeFromLeader,
102✔
897
                       static_cast<GByte *>(apData[i]) + nMaskOffsetWithLeader -
102✔
898
                           anOffsets[i],
102✔
899
                       sizeof(nMaskSizeFromLeader));
900
                CPL_LSBPTR32(&nMaskSizeFromLeader);
102✔
901
                if (nMaskOffsetWithLeader + nLeaderSize + nMaskSizeFromLeader +
204✔
902
                        nTrailerSize <=
204✔
903
                    anOffsets[i] + anSizes[i])
102✔
904
                {
905
                    bOK = true;
102✔
906
                    if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
102✔
907
                    {
908
                        // Check trailer consistency
909
                        const GByte *strileMaskData =
910
                            static_cast<GByte *>(apData[i]) + nOffset -
102✔
911
                            anOffsets[i] + nLeaderSize + nSizeFromLeader +
204✔
912
                            nTrailerSize + nLeaderSize;
102✔
913
                        if (!CheckTrailer(strileMaskData, nMaskSizeFromLeader))
102✔
914
                        {
915
                            CPLDebug("GTiff",
×
916
                                     "Inconsistent trailer of mask of block %d",
917
                                     nBlockId);
918
                            bOK = false;
×
919
                        }
920
                    }
921
                }
922
                if (bOK)
102✔
923
                {
924
                    const vsi_l_offset nRealOffset = nOffset + nLeaderSize +
102✔
925
                                                     nSizeFromLeader +
102✔
926
                                                     nTrailerSize + nLeaderSize;
102✔
927
                    const vsi_l_offset nRealSize = nMaskSizeFromLeader;
102✔
928
#ifdef DEBUG_VERBOSE
929
                    CPLDebug("GTiff",
930
                             "Mask of block %d found at offset " CPL_FRMT_GUIB
931
                             " with size " CPL_FRMT_GUIB,
932
                             nBlockId, nRealOffset, nRealSize);
933
#endif
934

935
                    m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
102✔
936
                        nBlockId, std::pair(nRealOffset, nRealSize));
102✔
937
                }
938
            }
939
            if (!bOK)
102✔
940
            {
941
                CPLDebug("GTiff",
×
942
                         "Mask for block %d is not properly interleaved with "
943
                         "imagery block",
944
                         nBlockId);
945
            }
946
        }
947
        return true;
36✔
948
    };
262✔
949

950
    thandle_t th = TIFFClientdata(m_poGDS->m_hTIFF);
262✔
951
    if (!VSI_TIFFHasCachedRanges(th))
262✔
952
    {
953
        std::vector<std::pair<vsi_l_offset, size_t>> aOffsetSize;
234✔
954
        size_t nTotalSize = 0;
234✔
955
        const unsigned int nMaxRawBlockCacheSize = atoi(
234✔
956
            CPLGetConfigOption("GDAL_MAX_RAW_BLOCK_CACHE_SIZE", "10485760"));
234✔
957
        bool bGoOn = true;
234✔
958
        for (int iY = nBlockY1; bGoOn && iY <= nBlockY2; iY++)
543✔
959
        {
960
            for (int iX = nBlockX1; bGoOn && iX <= nBlockX2; iX++)
1,010✔
961
            {
962
                GDALRasterBlock *poBlock = TryGetLockedBlockRef(iX, iY);
701✔
963
                if (poBlock != nullptr)
701✔
964
                {
965
                    poBlock->DropLock();
300✔
966
                    continue;
300✔
967
                }
968
                int nBlockId = iX + iY * nBlocksPerRow;
401✔
969
                if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
401✔
970
                    nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
×
971
                vsi_l_offset nOffset = 0;
401✔
972
                vsi_l_offset nSize = 0;
401✔
973

974
                if ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ||
401✔
975
                     m_poGDS->nBands == 1) &&
×
976
                    !m_poGDS->m_bStreamingIn &&
401✔
977
                    m_poGDS->m_bBlockOrderRowMajor &&
401✔
978
                    m_poGDS->m_bLeaderSizeAsUInt4)
195✔
979
                {
980
                    OptimizedRetrievalOfOffsetSize(nBlockId, nOffset, nSize,
195✔
981
                                                   nTotalSize,
982
                                                   nMaxRawBlockCacheSize);
983
                }
984
                else
985
                {
986
                    CPL_IGNORE_RET_VAL(m_poGDS->IsBlockAvailable(
206✔
987
                        nBlockId, &nOffset, &nSize, nullptr));
988
                }
989
                if (nSize)
401✔
990
                {
991
                    if (nTotalSize + nSize < nMaxRawBlockCacheSize)
143✔
992
                    {
993
#ifdef DEBUG_VERBOSE
994
                        CPLDebug("GTiff",
995
                                 "Precaching for block (%d, %d), " CPL_FRMT_GUIB
996
                                 "-" CPL_FRMT_GUIB,
997
                                 iX, iY, nOffset,
998
                                 nOffset + static_cast<size_t>(nSize) - 1);
999
#endif
1000
                        aOffsetSize.push_back(
143✔
1001
                            std::pair(nOffset, static_cast<size_t>(nSize)));
143✔
1002
                        nTotalSize += static_cast<size_t>(nSize);
143✔
1003
                    }
1004
                    else
1005
                    {
1006
                        bGoOn = false;
×
1007
                    }
1008
                }
1009
            }
1010
        }
1011

1012
        std::sort(aOffsetSize.begin(), aOffsetSize.end());
234✔
1013

1014
        if (nTotalSize > 0)
234✔
1015
        {
1016
            pBufferedData = VSI_MALLOC_VERBOSE(nTotalSize);
41✔
1017
            if (pBufferedData)
41✔
1018
            {
1019
                std::vector<vsi_l_offset> anOffsets;
41✔
1020
                std::vector<size_t> anSizes;
41✔
1021
                std::vector<void *> apData;
41✔
1022
                anOffsets.push_back(aOffsetSize[0].first);
41✔
1023
                apData.push_back(static_cast<GByte *>(pBufferedData));
41✔
1024
                size_t nChunkSize = aOffsetSize[0].second;
41✔
1025
                size_t nAccOffset = 0;
41✔
1026
                // Try to merge contiguous or slightly overlapping ranges
1027
                for (size_t i = 0; i < aOffsetSize.size() - 1; i++)
143✔
1028
                {
1029
                    if (aOffsetSize[i].first < aOffsetSize[i + 1].first &&
204✔
1030
                        aOffsetSize[i].first + aOffsetSize[i].second >=
102✔
1031
                            aOffsetSize[i + 1].first)
102✔
1032
                    {
1033
                        const auto overlap = aOffsetSize[i].first +
98✔
1034
                                             aOffsetSize[i].second -
98✔
1035
                                             aOffsetSize[i + 1].first;
98✔
1036
                        // That should always be the case for well behaved
1037
                        // TIFF files.
1038
                        if (aOffsetSize[i + 1].second > overlap)
98✔
1039
                        {
1040
                            nChunkSize += static_cast<size_t>(
98✔
1041
                                aOffsetSize[i + 1].second - overlap);
98✔
1042
                        }
1043
                    }
1044
                    else
1045
                    {
1046
                        // terminate current block
1047
                        anSizes.push_back(nChunkSize);
4✔
1048
#ifdef DEBUG_VERBOSE
1049
                        CPLDebug("GTiff",
1050
                                 "Requesting range [" CPL_FRMT_GUIB
1051
                                 "-" CPL_FRMT_GUIB "]",
1052
                                 anOffsets.back(),
1053
                                 anOffsets.back() + anSizes.back() - 1);
1054
#endif
1055
                        nAccOffset += nChunkSize;
4✔
1056
                        // start a new range
1057
                        anOffsets.push_back(aOffsetSize[i + 1].first);
4✔
1058
                        apData.push_back(static_cast<GByte *>(pBufferedData) +
4✔
1059
                                         nAccOffset);
1060
                        nChunkSize = aOffsetSize[i + 1].second;
4✔
1061
                    }
1062
                }
1063
                // terminate last block
1064
                anSizes.push_back(nChunkSize);
41✔
1065
#ifdef DEBUG_VERBOSE
1066
                CPLDebug(
1067
                    "GTiff",
1068
                    "Requesting range [" CPL_FRMT_GUIB "-" CPL_FRMT_GUIB "]",
1069
                    anOffsets.back(), anOffsets.back() + anSizes.back() - 1);
1070
#endif
1071

1072
                VSILFILE *fp = VSI_TIFFGetVSILFile(th);
41✔
1073

1074
                // An error in VSIFReadMultiRangeL() will not be critical,
1075
                // as this method is an optimization, and if it fails,
1076
                // tile-by-tile data acquisition will be done, so we can
1077
                // temporary turn failures into warnings.
1078
                CPLTurnFailureIntoWarning(true);
41✔
1079
                const bool ok =
1080
                    VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
41✔
1081
                                        &apData[0], &anOffsets[0], &anSizes[0],
41✔
1082
                                        fp) == 0;
41✔
1083
                CPLTurnFailureIntoWarning(false);
41✔
1084
                if (ok)
41✔
1085
                {
1086
                    if (!oMapStrileToOffsetByteCount.empty() &&
77✔
1087
                        !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
36✔
1088
                                                          apData))
1089
                    {
1090
                        // Retry without optimization
1091
                        CPLFree(pBufferedData);
×
1092
                        m_poGDS->m_bLeaderSizeAsUInt4 = false;
×
1093
                        void *pRet =
1094
                            CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
×
1095
                                            nBufXSize, nBufYSize, psExtraArg);
1096
                        m_poGDS->m_bLeaderSizeAsUInt4 = true;
×
1097
                        return pRet;
×
1098
                    }
1099

1100
                    VSI_TIFFSetCachedRanges(
41✔
1101
                        th, static_cast<int>(anSizes.size()), &apData[0],
41✔
1102
                        &anOffsets[0], &anSizes[0]);
41✔
1103
                }
1104
                else
1105
                {
1106
                    CPLFree(pBufferedData);
×
1107
                    pBufferedData = nullptr;
×
1108
                }
1109
            }
1110
        }
1111
    }
1112
    return pBufferedData;
262✔
1113
}
1114

1115
/************************************************************************/
1116
/*                       IGetDataCoverageStatus()                       */
1117
/************************************************************************/
1118

1119
int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
810✔
1120
                                            int nYSize, int nMaskFlagStop,
1121
                                            double *pdfDataPct)
1122
{
1123
    if (eAccess == GA_Update)
810✔
1124
        m_poGDS->FlushCache(false);
89✔
1125

1126
    const int iXBlockStart = nXOff / nBlockXSize;
810✔
1127
    const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
810✔
1128
    const int iYBlockStart = nYOff / nBlockYSize;
810✔
1129
    const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
810✔
1130
    int nStatus = 0;
810✔
1131
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
810✔
1132
    GIntBig nPixelsData = 0;
810✔
1133
    for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
2,408✔
1134
    {
1135
        for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
4,218✔
1136
        {
1137
            const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
2,620✔
1138
            int nBlockId = nBlockIdBand0;
2,620✔
1139
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
2,620✔
1140
                nBlockId =
112✔
1141
                    nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
112✔
1142
            vsi_l_offset nOffset = 0;
2,620✔
1143
            vsi_l_offset nLength = 0;
2,620✔
1144
            bool bHasData = false;
2,620✔
1145
            bool bError = false;
2,620✔
1146
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
2,620✔
1147
                                           &bError))
1148
            {
1149
                if (bError)
1,866✔
1150
                    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
748✔
1151
                nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
1,866✔
1152
            }
1153
            else
1154
            {
1155
                if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
754✔
1156
                    m_poGDS->eAccess == GA_ReadOnly &&
666✔
1157
                    ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
630✔
1158
                      !m_bNoDataSetAsUInt64) ||
630✔
1159
                     (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
×
1160
                     (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
×
1161
                     (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
×
1162
                {
1163
                    VSIRangeStatus eStatus =
1164
                        VSIFGetRangeStatusL(fp, nOffset, nLength);
630✔
1165
                    if (eStatus == VSI_RANGE_STATUS_HOLE)
630✔
1166
                    {
1167
                        nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
×
1168
                    }
1169
                    else
1170
                    {
1171
                        bHasData = true;
630✔
1172
                    }
630✔
1173
                }
1174
                else
1175
                {
1176
                    bHasData = true;
124✔
1177
                }
1178
            }
1179
            if (bHasData)
2,620✔
1180
            {
1181
                const int nXBlockRight =
754✔
1182
                    (iX * nBlockXSize > INT_MAX - nBlockXSize)
754✔
1183
                        ? INT_MAX
754✔
1184
                        : (iX + 1) * nBlockXSize;
754✔
1185
                const int nYBlockBottom =
754✔
1186
                    (iY * nBlockYSize > INT_MAX - nBlockYSize)
754✔
1187
                        ? INT_MAX
754✔
1188
                        : (iY + 1) * nBlockYSize;
754✔
1189

1190
                nPixelsData += (static_cast<GIntBig>(
1,508✔
1191
                                    std::min(nXBlockRight, nXOff + nXSize)) -
754✔
1192
                                std::max(iX * nBlockXSize, nXOff)) *
754✔
1193
                               (std::min(nYBlockBottom, nYOff + nYSize) -
754✔
1194
                                std::max(iY * nBlockYSize, nYOff));
754✔
1195
                nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
754✔
1196
            }
1197
            if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
2,620✔
1198
            {
1199
                if (pdfDataPct)
748✔
1200
                    *pdfDataPct = -1.0;
×
1201
                return nStatus;
748✔
1202
            }
1203
        }
1204
    }
1205
    if (pdfDataPct)
62✔
1206
        *pdfDataPct =
8✔
1207
            100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
8✔
1208
    return nStatus;
62✔
1209
}
1210

1211
/************************************************************************/
1212
/*                             IReadBlock()                             */
1213
/************************************************************************/
1214

1215
CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
2,199,020✔
1216

1217
{
1218
    m_poGDS->Crystalize();
2,199,020✔
1219

1220
    GPtrDiff_t nBlockBufSize = 0;
2,199,030✔
1221
    if (TIFFIsTiled(m_poGDS->m_hTIFF))
2,199,030✔
1222
    {
1223
        nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
55,762✔
1224
    }
1225
    else
1226
    {
1227
        CPLAssert(nBlockXOff == 0);
2,143,230✔
1228
        nBlockBufSize =
1229
            static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
2,143,230✔
1230
    }
1231

1232
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
2,198,970✔
1233

1234
    /* -------------------------------------------------------------------- */
1235
    /*      The bottom most partial tiles and strips are sometimes only     */
1236
    /*      partially encoded.  This code reduces the requested data so     */
1237
    /*      an error won't be reported in this case. (#1179)                */
1238
    /* -------------------------------------------------------------------- */
1239
    auto nBlockReqSize = nBlockBufSize;
2,199,000✔
1240

1241
    if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
2,199,000✔
1242
    {
1243
        nBlockReqSize =
6,016✔
1244
            (nBlockBufSize / nBlockYSize) *
6,016✔
1245
            (nBlockYSize -
6,016✔
1246
             static_cast<int>(
1247
                 (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
6,016✔
1248
                 nRasterYSize));
6,016✔
1249
    }
1250

1251
    /* -------------------------------------------------------------------- */
1252
    /*      Handle the case of a strip or tile that doesn't exist yet.      */
1253
    /*      Just set to zeros and return.                                   */
1254
    /* -------------------------------------------------------------------- */
1255
    vsi_l_offset nOffset = 0;
2,199,000✔
1256
    bool bErrOccurred = false;
2,199,000✔
1257
    if (nBlockId != m_poGDS->m_nLoadedBlock &&
4,364,710✔
1258
        !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
2,165,730✔
1259
    {
1260
        NullBlock(pImage);
49,302✔
1261
        if (bErrOccurred)
49,302✔
1262
            return CE_Failure;
1✔
1263
        return CE_None;
49,301✔
1264
    }
1265

1266
    if (m_poGDS->m_bStreamingIn &&
2,149,680✔
1267
        !(m_poGDS->nBands > 1 &&
10,936✔
1268
          m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
10,423✔
1269
          nBlockId == m_poGDS->m_nLoadedBlock))
10,048✔
1270
    {
1271
        if (nOffset < VSIFTellL(m_poGDS->m_fpL))
3,436✔
1272
        {
1273
            ReportError(CE_Failure, CPLE_NotSupported,
2,000✔
1274
                        "Trying to load block %d at offset " CPL_FRMT_GUIB
1275
                        " whereas current pos is " CPL_FRMT_GUIB
1276
                        " (backward read not supported)",
1277
                        nBlockId, static_cast<GUIntBig>(nOffset),
1278
                        static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
1,000✔
1279
            return CE_Failure;
1,000✔
1280
        }
1281
    }
1282

1283
    /* -------------------------------------------------------------------- */
1284
    /*      Handle simple case (separate, onesampleperpixel)                */
1285
    /* -------------------------------------------------------------------- */
1286
    CPLErr eErr = CE_None;
2,148,680✔
1287
    if (m_poGDS->nBands == 1 ||
2,148,680✔
1288
        m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
104,573✔
1289
    {
1290
        if (nBlockReqSize < nBlockBufSize)
2,055,690✔
1291
            memset(pImage, 0, nBlockBufSize);
2,362✔
1292

1293
        if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
2,055,690✔
1294
        {
1295
            memset(pImage, 0, nBlockBufSize);
62✔
1296
            return CE_Failure;
62✔
1297
        }
1298
    }
1299
    else
1300
    {
1301
        /* --------------------------------------------------------------------
1302
         */
1303
        /*      Load desired block */
1304
        /* --------------------------------------------------------------------
1305
         */
1306
        eErr = m_poGDS->LoadBlockBuf(nBlockId);
92,991✔
1307
        if (eErr != CE_None)
93,028✔
1308
        {
1309
            memset(pImage, 0,
41✔
1310
                   static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
82✔
1311
                       GDALGetDataTypeSizeBytes(eDataType));
41✔
1312
            return eErr;
41✔
1313
        }
1314

1315
        bool bDoCopyWords = true;
92,987✔
1316
        if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
61,196✔
1317
            eAccess == GA_ReadOnly &&
55,756✔
1318
            (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
47,204✔
1319
            ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
46,849✔
1320
             (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
1,285✔
1321
             (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
154,452✔
1322
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
92,529✔
1323
                    GDALGetDataTypeSizeBytes(eDataType) <
46,278✔
1324
                GDALGetCacheMax64() / m_poGDS->nBands)
46,251✔
1325
        {
1326
            bDoCopyWords = false;
46,236✔
1327
            void *ppDestBuffers[4];
1328
            GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
46,236✔
1329
                                                   nullptr};
1330
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
196,281✔
1331
            {
1332
                if (iBand == nBand)
150,009✔
1333
                {
1334
                    ppDestBuffers[iBand - 1] = pImage;
46,244✔
1335
                }
1336
                else
1337
                {
1338
                    GDALRasterBlock *poBlock =
1339
                        m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
103,765✔
1340
                            nBlockXOff, nBlockYOff, true);
103,759✔
1341
                    if (poBlock == nullptr)
103,805✔
1342
                    {
1343
                        bDoCopyWords = true;
×
1344
                        break;
×
1345
                    }
1346
                    ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
103,805✔
1347
                    apoLockedBlocks[iBand - 1] = poBlock;
103,801✔
1348
                }
1349
            }
1350
            if (!bDoCopyWords)
46,272✔
1351
            {
1352
                GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
46,264✔
1353
                                 m_poGDS->nBands, ppDestBuffers, eDataType,
46,264✔
1354
                                 static_cast<size_t>(nBlockXSize) *
46,264✔
1355
                                     nBlockYSize);
46,264✔
1356
            }
1357
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
196,328✔
1358
            {
1359
                if (apoLockedBlocks[iBand - 1])
150,065✔
1360
                {
1361
                    apoLockedBlocks[iBand - 1]->DropLock();
103,805✔
1362
                }
1363
            }
1364
        }
1365

1366
        if (bDoCopyWords)
92,985✔
1367
        {
1368
            const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
46,715✔
1369
            GByte *pabyImage =
46,715✔
1370
                m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
46,715✔
1371

1372
            GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
46,715✔
1373
                            pImage, eDataType, nWordBytes,
1374
                            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
46,715✔
1375

1376
            eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
46,735✔
1377
        }
1378
    }
1379

1380
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
2,148,630✔
1381

1382
    return eErr;
2,148,630✔
1383
}
1384

1385
/************************************************************************/
1386
/*                           CacheMaskForBlock()                       */
1387
/************************************************************************/
1388

1389
void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
2,149,520✔
1390

1391
{
1392
    // Preload mask data if layout compatible and we have cached ranges
1393
    if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
2,149,630✔
1394
        VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
109✔
1395
    {
1396
        auto poBand = cpl::down_cast<GTiffRasterBand *>(
98✔
1397
            m_poGDS->m_poMaskDS->GetRasterBand(1));
98✔
1398
        if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
294✔
1399
                poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
98✔
1400
        {
1401
            GDALRasterBlock *poBlock =
1402
                poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
94✔
1403
            if (poBlock)
94✔
1404
                poBlock->DropLock();
94✔
1405
        }
1406
    }
1407
}
2,149,520✔
1408

1409
/************************************************************************/
1410
/*                       FillCacheForOtherBands()                       */
1411
/************************************************************************/
1412

1413
CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
46,949✔
1414

1415
{
1416
    /* -------------------------------------------------------------------- */
1417
    /*      In the fairly common case of pixel interleaved 8bit data        */
1418
    /*      that is multi-band, lets push the rest of the data into the     */
1419
    /*      block cache too, to avoid (hopefully) having to redecode it.    */
1420
    /*                                                                      */
1421
    /*      Our following logic actually depends on the fact that the       */
1422
    /*      this block is already loaded, so subsequent calls will end      */
1423
    /*      up back in this method and pull from the loaded block.          */
1424
    /*                                                                      */
1425
    /*      Be careful not entering this portion of code from               */
1426
    /*      the other bands, otherwise we'll get very deep nested calls     */
1427
    /*      and O(nBands^2) performance !                                   */
1428
    /*                                                                      */
1429
    /*      If there are many bands and the block cache size is not big     */
1430
    /*      enough to accommodate the size of all the blocks, don't enter   */
1431
    /* -------------------------------------------------------------------- */
1432
    CPLErr eErr = CE_None;
46,949✔
1433
    if (m_poGDS->nBands != 1 &&
140,839✔
1434
        m_poGDS->nBands <
46,947✔
1435
            128 &&  // avoid caching for datasets with too many bands
46,946✔
1436
        !m_poGDS->m_bLoadingOtherBands &&
105,866✔
1437
        static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
23,952✔
1438
                GDALGetDataTypeSizeBytes(eDataType) <
11,976✔
1439
            GDALGetCacheMax64() / m_poGDS->nBands)
11,976✔
1440
    {
1441
        m_poGDS->m_bLoadingOtherBands = true;
11,974✔
1442

1443
        for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
49,881✔
1444
        {
1445
            if (iOtherBand == nBand)
37,901✔
1446
                continue;
11,974✔
1447

1448
            GDALRasterBlock *poBlock =
1449
                m_poGDS->GetRasterBand(iOtherBand)
25,927✔
1450
                    ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
25,931✔
1451
            if (poBlock == nullptr)
25,932✔
1452
            {
1453
                eErr = CE_Failure;
×
1454
                break;
×
1455
            }
1456
            poBlock->DropLock();
25,932✔
1457
        }
1458

1459
        m_poGDS->m_bLoadingOtherBands = false;
11,980✔
1460
    }
1461

1462
    return eErr;
46,949✔
1463
}
1464

1465
/************************************************************************/
1466
/*                           GetDescription()                           */
1467
/************************************************************************/
1468

1469
const char *GTiffRasterBand::GetDescription() const
205,680✔
1470
{
1471
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
205,680✔
1472

1473
    return m_osDescription;
205,680✔
1474
}
1475

1476
/************************************************************************/
1477
/*                             GetOffset()                              */
1478
/************************************************************************/
1479

1480
double GTiffRasterBand::GetOffset(int *pbSuccess)
212,770✔
1481

1482
{
1483
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
212,770✔
1484

1485
    if (pbSuccess)
212,770✔
1486
        *pbSuccess = m_bHaveOffsetScale;
6,620✔
1487
    return m_dfOffset;
212,770✔
1488
}
1489

1490
/************************************************************************/
1491
/*                              GetScale()                              */
1492
/************************************************************************/
1493

1494
double GTiffRasterBand::GetScale(int *pbSuccess)
212,771✔
1495

1496
{
1497
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
212,771✔
1498

1499
    if (pbSuccess)
212,771✔
1500
        *pbSuccess = m_bHaveOffsetScale;
6,621✔
1501
    return m_dfScale;
212,771✔
1502
}
1503

1504
/************************************************************************/
1505
/*                            GetUnitType()                             */
1506
/************************************************************************/
1507

1508
const char *GTiffRasterBand::GetUnitType()
204,912✔
1509

1510
{
1511
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
204,912✔
1512
    if (m_osUnitType.empty())
204,912✔
1513
    {
1514
        m_poGDS->LookForProjection();
204,833✔
1515
        if (m_poGDS->m_pszVertUnit)
204,833✔
1516
            return m_poGDS->m_pszVertUnit;
9✔
1517
    }
1518

1519
    return m_osUnitType.c_str();
204,903✔
1520
}
1521

1522
/************************************************************************/
1523
/*                      GetMetadataDomainList()                         */
1524
/************************************************************************/
1525

1526
char **GTiffRasterBand::GetMetadataDomainList()
12✔
1527
{
1528
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
12✔
1529

1530
    return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
12✔
1531
}
1532

1533
/************************************************************************/
1534
/*                            GetMetadata()                             */
1535
/************************************************************************/
1536

1537
char **GTiffRasterBand::GetMetadata(const char *pszDomain)
15,757✔
1538

1539
{
1540
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
15,757✔
1541
    {
1542
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
15,593✔
1543
    }
1544

1545
    return m_oGTiffMDMD.GetMetadata(pszDomain);
15,757✔
1546
}
1547

1548
/************************************************************************/
1549
/*                          GetMetadataItem()                           */
1550
/************************************************************************/
1551

1552
const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
30,076✔
1553
                                             const char *pszDomain)
1554

1555
{
1556
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
30,076✔
1557
    {
1558
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
7,125✔
1559
    }
1560

1561
    if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
30,076✔
1562
    {
1563
        int nBlockXOff = 0;
4,196✔
1564
        int nBlockYOff = 0;
4,196✔
1565

1566
        if (EQUAL(pszName, "JPEGTABLES"))
4,196✔
1567
        {
1568
            uint32_t nJPEGTableSize = 0;
11✔
1569
            void *pJPEGTable = nullptr;
11✔
1570
            if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
11✔
1571
                             &nJPEGTableSize, &pJPEGTable) != 1 ||
11✔
1572
                pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
11✔
1573
            {
1574
                return nullptr;
×
1575
            }
1576
            char *const pszHex = CPLBinaryToHex(
11✔
1577
                nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1578
            const char *pszReturn = CPLSPrintf("%s", pszHex);
11✔
1579
            CPLFree(pszHex);
11✔
1580

1581
            return pszReturn;
11✔
1582
        }
1583

1584
        if (EQUAL(pszName, "IFD_OFFSET"))
4,185✔
1585
        {
1586
            return CPLSPrintf(CPL_FRMT_GUIB,
158✔
1587
                              static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
79✔
1588
        }
1589

1590
        if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
4,106✔
1591
            2)
1592
        {
1593
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
3,687✔
1594
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
3,686✔
1595
                return nullptr;
19✔
1596

1597
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
3,668✔
1598
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
3,668✔
1599
            {
1600
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
2,870✔
1601
            }
1602

1603
            vsi_l_offset nOffset = 0;
3,668✔
1604
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
3,668✔
1605
                                           nullptr))
1606
            {
1607
                return nullptr;
190✔
1608
            }
1609

1610
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
3,478✔
1611
        }
1612

1613
        if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
419✔
1614
        {
1615
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
419✔
1616
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
418✔
1617
                return nullptr;
2✔
1618

1619
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
417✔
1620
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
417✔
1621
            {
1622
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1✔
1623
            }
1624

1625
            vsi_l_offset nByteCount = 0;
417✔
1626
            if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
417✔
1627
                                           nullptr))
1628
            {
1629
                return nullptr;
89✔
1630
            }
1631

1632
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
328✔
1633
        }
×
1634
    }
1635
    else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
25,880✔
1636
    {
1637
        if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
131✔
1638
            return HasBlockCache() ? "1" : "0";
131✔
1639
    }
1640

1641
    const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
25,749✔
1642

1643
    if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
25,749✔
1644
        EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
23,456✔
1645
    {
1646
        // to get a chance of emitting the warning about this legacy usage
1647
        pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
5,158✔
1648
    }
1649
    return pszRet;
25,749✔
1650
}
1651

1652
/************************************************************************/
1653
/*                       GetColorInterpretation()                       */
1654
/************************************************************************/
1655

1656
GDALColorInterp GTiffRasterBand::GetColorInterpretation()
225,514✔
1657

1658
{
1659
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
225,514✔
1660

1661
    return m_eBandInterp;
225,514✔
1662
}
1663

1664
/************************************************************************/
1665
/*                           GetColorTable()                            */
1666
/************************************************************************/
1667

1668
GDALColorTable *GTiffRasterBand::GetColorTable()
11,556✔
1669

1670
{
1671
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
11,556✔
1672

1673
    if (nBand == 1)
11,556✔
1674
        return m_poGDS->m_poColorTable.get();
9,872✔
1675

1676
    return nullptr;
1,684✔
1677
}
1678

1679
/************************************************************************/
1680
/*                           GetNoDataValue()                           */
1681
/************************************************************************/
1682

1683
double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
815,733✔
1684

1685
{
1686
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
815,733✔
1687

1688
    int bSuccess = FALSE;
815,393✔
1689
    double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
815,393✔
1690
    if (bSuccess)
815,426✔
1691
    {
1692
        if (pbSuccess)
4✔
1693
            *pbSuccess = TRUE;
4✔
1694

1695
        return dfNoDataValue;
4✔
1696
    }
1697

1698
    if (m_bNoDataSet)
815,422✔
1699
    {
1700
        if (pbSuccess)
2,243✔
1701
            *pbSuccess = TRUE;
2,210✔
1702

1703
        return m_dfNoDataValue;
2,243✔
1704
    }
1705

1706
    if (m_poGDS->m_bNoDataSet)
813,179✔
1707
    {
1708
        if (pbSuccess)
422,850✔
1709
            *pbSuccess = TRUE;
422,708✔
1710

1711
        return m_poGDS->m_dfNoDataValue;
422,850✔
1712
    }
1713

1714
    if (m_bNoDataSetAsInt64)
390,329✔
1715
    {
1716
        if (pbSuccess)
×
1717
            *pbSuccess = TRUE;
×
1718

1719
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
×
1720
    }
1721

1722
    if (m_poGDS->m_bNoDataSetAsInt64)
390,329✔
1723
    {
1724
        if (pbSuccess)
×
1725
            *pbSuccess = TRUE;
×
1726

1727
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
×
1728
    }
1729

1730
    if (m_bNoDataSetAsUInt64)
390,329✔
1731
    {
1732
        if (pbSuccess)
×
1733
            *pbSuccess = TRUE;
×
1734

1735
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
×
1736
    }
1737

1738
    if (m_poGDS->m_bNoDataSetAsUInt64)
390,329✔
1739
    {
1740
        if (pbSuccess)
×
1741
            *pbSuccess = TRUE;
×
1742

1743
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
×
1744
    }
1745

1746
    if (pbSuccess)
390,329✔
1747
        *pbSuccess = FALSE;
390,533✔
1748
    return dfNoDataValue;
390,329✔
1749
}
1750

1751
/************************************************************************/
1752
/*                       GetNoDataValueAsInt64()                        */
1753
/************************************************************************/
1754

1755
int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
25✔
1756

1757
{
1758
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
25✔
1759

1760
    if (eDataType == GDT_UInt64)
25✔
1761
    {
1762
        CPLError(CE_Failure, CPLE_AppDefined,
×
1763
                 "GetNoDataValueAsUInt64() should be called instead");
1764
        if (pbSuccess)
×
1765
            *pbSuccess = FALSE;
×
1766
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
×
1767
    }
1768
    if (eDataType != GDT_Int64)
25✔
1769
    {
1770
        CPLError(CE_Failure, CPLE_AppDefined,
×
1771
                 "GetNoDataValue() should be called instead");
1772
        if (pbSuccess)
×
1773
            *pbSuccess = FALSE;
×
1774
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
×
1775
    }
1776

1777
    int bSuccess = FALSE;
25✔
1778
    const auto nNoDataValue =
1779
        GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
25✔
1780
    if (bSuccess)
25✔
1781
    {
1782
        if (pbSuccess)
×
1783
            *pbSuccess = TRUE;
×
1784

1785
        return nNoDataValue;
×
1786
    }
1787

1788
    if (m_bNoDataSetAsInt64)
25✔
1789
    {
1790
        if (pbSuccess)
2✔
1791
            *pbSuccess = TRUE;
2✔
1792

1793
        return m_nNoDataValueInt64;
2✔
1794
    }
1795

1796
    if (m_poGDS->m_bNoDataSetAsInt64)
23✔
1797
    {
1798
        if (pbSuccess)
7✔
1799
            *pbSuccess = TRUE;
6✔
1800

1801
        return m_poGDS->m_nNoDataValueInt64;
7✔
1802
    }
1803

1804
    if (pbSuccess)
16✔
1805
        *pbSuccess = FALSE;
16✔
1806
    return nNoDataValue;
16✔
1807
}
1808

1809
/************************************************************************/
1810
/*                      GetNoDataValueAsUInt64()                        */
1811
/************************************************************************/
1812

1813
uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
16✔
1814

1815
{
1816
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
16✔
1817

1818
    if (eDataType == GDT_Int64)
16✔
1819
    {
1820
        CPLError(CE_Failure, CPLE_AppDefined,
×
1821
                 "GetNoDataValueAsInt64() should be called instead");
1822
        if (pbSuccess)
×
1823
            *pbSuccess = FALSE;
×
1824
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
×
1825
    }
1826
    if (eDataType != GDT_UInt64)
16✔
1827
    {
1828
        CPLError(CE_Failure, CPLE_AppDefined,
×
1829
                 "GetNoDataValue() should be called instead");
1830
        if (pbSuccess)
×
1831
            *pbSuccess = FALSE;
×
1832
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
×
1833
    }
1834

1835
    int bSuccess = FALSE;
16✔
1836
    const auto nNoDataValue =
1837
        GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
16✔
1838
    if (bSuccess)
16✔
1839
    {
1840
        if (pbSuccess)
×
1841
            *pbSuccess = TRUE;
×
1842

1843
        return nNoDataValue;
×
1844
    }
1845

1846
    if (m_bNoDataSetAsUInt64)
16✔
1847
    {
1848
        if (pbSuccess)
×
1849
            *pbSuccess = TRUE;
×
1850

1851
        return m_nNoDataValueUInt64;
×
1852
    }
1853

1854
    if (m_poGDS->m_bNoDataSetAsUInt64)
16✔
1855
    {
1856
        if (pbSuccess)
7✔
1857
            *pbSuccess = TRUE;
6✔
1858

1859
        return m_poGDS->m_nNoDataValueUInt64;
7✔
1860
    }
1861

1862
    if (pbSuccess)
9✔
1863
        *pbSuccess = FALSE;
9✔
1864
    return nNoDataValue;
9✔
1865
}
1866

1867
/************************************************************************/
1868
/*                          GetOverviewCount()                          */
1869
/************************************************************************/
1870

1871
int GTiffRasterBand::GetOverviewCount()
655,410✔
1872

1873
{
1874
    if (!m_poGDS->AreOverviewsEnabled())
655,410✔
1875
        return 0;
30✔
1876

1877
    m_poGDS->ScanDirectories();
655,380✔
1878

1879
    if (m_poGDS->m_nOverviewCount > 0)
655,380✔
1880
    {
1881
        return m_poGDS->m_nOverviewCount;
4,849✔
1882
    }
1883

1884
    const int nOverviewCount = GDALRasterBand::GetOverviewCount();
650,531✔
1885
    if (nOverviewCount > 0)
650,531✔
1886
        return nOverviewCount;
368✔
1887

1888
    // Implicit JPEG overviews are normally hidden, except when doing
1889
    // IRasterIO() operations.
1890
    if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
650,163✔
1891
        return m_poGDS->GetJPEGOverviewCount();
643,432✔
1892

1893
    return 0;
6,731✔
1894
}
1895

1896
/************************************************************************/
1897
/*                            GetOverview()                             */
1898
/************************************************************************/
1899

1900
GDALRasterBand *GTiffRasterBand::GetOverview(int i)
8,375✔
1901

1902
{
1903
    m_poGDS->ScanDirectories();
8,375✔
1904

1905
    if (m_poGDS->m_nOverviewCount > 0)
8,375✔
1906
    {
1907
        // Do we have internal overviews?
1908
        if (i < 0 || i >= m_poGDS->m_nOverviewCount)
7,806✔
1909
            return nullptr;
8✔
1910

1911
        return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
7,798✔
1912
    }
1913

1914
    GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
569✔
1915
    if (poOvrBand != nullptr)
569✔
1916
        return poOvrBand;
366✔
1917

1918
    // For consistency with GetOverviewCount(), we should also test
1919
    // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1920
    // to query them for testing purposes.
1921
    if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
203✔
1922
        return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
164✔
1923

1924
    return nullptr;
39✔
1925
}
1926

1927
/************************************************************************/
1928
/*                           GetMaskFlags()                             */
1929
/************************************************************************/
1930

1931
int GTiffRasterBand::GetMaskFlags()
18,282✔
1932
{
1933
    m_poGDS->ScanDirectories();
18,282✔
1934

1935
    if (m_poGDS->m_poExternalMaskDS != nullptr)
18,282✔
1936
    {
1937
        return GMF_PER_DATASET;
×
1938
    }
1939

1940
    if (m_poGDS->m_poMaskDS != nullptr)
18,282✔
1941
    {
1942
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
179✔
1943
        {
1944
            return GMF_PER_DATASET;
172✔
1945
        }
1946

1947
        return 0;
7✔
1948
    }
1949

1950
    if (m_poGDS->m_bIsOverview)
18,103✔
1951
    {
1952
        return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
382✔
1953
    }
1954

1955
    return GDALPamRasterBand::GetMaskFlags();
17,721✔
1956
}
1957

1958
/************************************************************************/
1959
/*                            GetMaskBand()                             */
1960
/************************************************************************/
1961

1962
GDALRasterBand *GTiffRasterBand::GetMaskBand()
116,930✔
1963
{
1964
    m_poGDS->ScanDirectories();
116,930✔
1965

1966
    if (m_poGDS->m_poExternalMaskDS != nullptr)
117,788✔
1967
    {
1968
        return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
×
1969
    }
1970

1971
    if (m_poGDS->m_poMaskDS != nullptr)
118,412✔
1972
    {
1973
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
641✔
1974
            return m_poGDS->m_poMaskDS->GetRasterBand(1);
627✔
1975

1976
        return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
14✔
1977
    }
1978

1979
    if (m_poGDS->m_bIsOverview)
117,771✔
1980
    {
1981
        GDALRasterBand *poBaseMask =
1982
            m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
114✔
1983
        if (poBaseMask)
114✔
1984
        {
1985
            const int nOverviews = poBaseMask->GetOverviewCount();
114✔
1986
            for (int i = 0; i < nOverviews; i++)
159✔
1987
            {
1988
                GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
93✔
1989
                if (poOvr && poOvr->GetXSize() == GetXSize() &&
141✔
1990
                    poOvr->GetYSize() == GetYSize())
48✔
1991
                {
1992
                    return poOvr;
48✔
1993
                }
1994
            }
1995
        }
1996
    }
1997

1998
    return GDALPamRasterBand::GetMaskBand();
117,723✔
1999
}
2000

2001
/************************************************************************/
2002
/*                            IsMaskBand()                              */
2003
/************************************************************************/
2004

2005
bool GTiffRasterBand::IsMaskBand() const
9,090✔
2006
{
2007
    return (m_poGDS->m_poImageryDS != nullptr &&
9,121✔
2008
            m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
31✔
2009
           m_eBandInterp == GCI_AlphaBand ||
16,101✔
2010
           m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
16,070✔
2011
}
2012

2013
/************************************************************************/
2014
/*                         GetMaskValueRange()                          */
2015
/************************************************************************/
2016

2017
GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
×
2018
{
2019
    if (!IsMaskBand())
×
2020
        return GMVR_UNKNOWN;
×
2021
    if (m_poGDS->m_nBitsPerSample == 1)
×
2022
        return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
×
2023
                                          : GMVR_0_AND_1_ONLY;
×
2024
    return GMVR_UNKNOWN;
×
2025
}
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