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

OSGeo / gdal / 13813968540

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

Pull #11951

github

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

553276 of 785573 relevant lines covered (70.43%)

222076.27 hits per line

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

87.9
/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,376✔
35

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

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

45
    if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_pszFilename))
3,367✔
46
        return nullptr;
×
47
    const std::string osVATDBF =
48
        std::string(m_poGDS->m_pszFilename) + ".vat.dbf";
10,101✔
49
    CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
3,367✔
50
    if (papszSiblingFiles &&
6,700✔
51
        // cppcheck-suppress knownConditionTrueFalse
52
        GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
3,333✔
53
    {
54
        int iSibling =
55
            CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
3,333✔
56
        if (iSibling >= 0)
3,333✔
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,333✔
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
/*                       IGetDataCoverageStatus()                       */
635
/************************************************************************/
636

637
int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
815✔
638
                                            int nYSize, int nMaskFlagStop,
639
                                            double *pdfDataPct)
640
{
641
    if (eAccess == GA_Update)
815✔
642
        m_poGDS->FlushCache(false);
91✔
643

644
    const int iXBlockStart = nXOff / nBlockXSize;
815✔
645
    const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
815✔
646
    const int iYBlockStart = nYOff / nBlockYSize;
815✔
647
    const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
815✔
648
    int nStatus = 0;
815✔
649
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
815✔
650
    GIntBig nPixelsData = 0;
815✔
651
    for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
2,413✔
652
    {
653
        for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
4,223✔
654
        {
655
            const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
2,625✔
656
            int nBlockId = nBlockIdBand0;
2,625✔
657
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
2,625✔
658
                nBlockId =
109✔
659
                    nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
109✔
660
            vsi_l_offset nOffset = 0;
2,625✔
661
            vsi_l_offset nLength = 0;
2,625✔
662
            bool bHasData = false;
2,625✔
663
            bool bError = false;
2,625✔
664
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
2,625✔
665
                                           &bError))
666
            {
667
                if (bError)
1,866✔
668
                    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
753✔
669
                nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
1,866✔
670
            }
671
            else
672
            {
673
                if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
759✔
674
                    m_poGDS->eAccess == GA_ReadOnly &&
668✔
675
                    ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
630✔
676
                      !m_bNoDataSetAsUInt64) ||
630✔
677
                     (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
×
678
                     (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
×
679
                     (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
×
680
                {
681
                    VSIRangeStatus eStatus =
682
                        VSIFGetRangeStatusL(fp, nOffset, nLength);
630✔
683
                    if (eStatus == VSI_RANGE_STATUS_HOLE)
630✔
684
                    {
685
                        nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
×
686
                    }
687
                    else
688
                    {
689
                        bHasData = true;
630✔
690
                    }
630✔
691
                }
692
                else
693
                {
694
                    bHasData = true;
129✔
695
                }
696
            }
697
            if (bHasData)
2,625✔
698
            {
699
                const int nXBlockRight =
759✔
700
                    (iX * nBlockXSize > INT_MAX - nBlockXSize)
759✔
701
                        ? INT_MAX
759✔
702
                        : (iX + 1) * nBlockXSize;
759✔
703
                const int nYBlockBottom =
759✔
704
                    (iY * nBlockYSize > INT_MAX - nBlockYSize)
759✔
705
                        ? INT_MAX
759✔
706
                        : (iY + 1) * nBlockYSize;
759✔
707

708
                nPixelsData += (static_cast<GIntBig>(
1,518✔
709
                                    std::min(nXBlockRight, nXOff + nXSize)) -
759✔
710
                                std::max(iX * nBlockXSize, nXOff)) *
759✔
711
                               (std::min(nYBlockBottom, nYOff + nYSize) -
759✔
712
                                std::max(iY * nBlockYSize, nYOff));
759✔
713
                nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
759✔
714
            }
715
            if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
2,625✔
716
            {
717
                if (pdfDataPct)
753✔
718
                    *pdfDataPct = -1.0;
×
719
                return nStatus;
753✔
720
            }
721
        }
722
    }
723
    if (pdfDataPct)
62✔
724
        *pdfDataPct =
8✔
725
            100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
8✔
726
    return nStatus;
62✔
727
}
728

729
/************************************************************************/
730
/*                             IReadBlock()                             */
731
/************************************************************************/
732

733
CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
2,205,390✔
734

735
{
736
    m_poGDS->Crystalize();
2,205,390✔
737

738
    GPtrDiff_t nBlockBufSize = 0;
2,205,300✔
739
    if (TIFFIsTiled(m_poGDS->m_hTIFF))
2,205,300✔
740
    {
741
        nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
55,656✔
742
    }
743
    else
744
    {
745
        CPLAssert(nBlockXOff == 0);
2,149,520✔
746
        nBlockBufSize =
747
            static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
2,149,520✔
748
    }
749

750
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
2,205,220✔
751

752
    /* -------------------------------------------------------------------- */
753
    /*      The bottom most partial tiles and strips are sometimes only     */
754
    /*      partially encoded.  This code reduces the requested data so     */
755
    /*      an error won't be reported in this case. (#1179)                */
756
    /* -------------------------------------------------------------------- */
757
    auto nBlockReqSize = nBlockBufSize;
2,205,260✔
758

759
    if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
2,205,260✔
760
    {
761
        nBlockReqSize =
6,187✔
762
            (nBlockBufSize / nBlockYSize) *
6,187✔
763
            (nBlockYSize -
6,187✔
764
             static_cast<int>(
765
                 (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
6,187✔
766
                 nRasterYSize));
6,187✔
767
    }
768

769
    /* -------------------------------------------------------------------- */
770
    /*      Handle the case of a strip or tile that doesn't exist yet.      */
771
    /*      Just set to zeros and return.                                   */
772
    /* -------------------------------------------------------------------- */
773
    vsi_l_offset nOffset = 0;
2,205,260✔
774
    bool bErrOccurred = false;
2,205,260✔
775
    if (nBlockId != m_poGDS->m_nLoadedBlock &&
4,375,000✔
776
        !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
2,169,610✔
777
    {
778
        NullBlock(pImage);
50,087✔
779
        if (bErrOccurred)
50,087✔
780
            return CE_Failure;
1✔
781
        return CE_None;
50,086✔
782
    }
783

784
    if (m_poGDS->m_bStreamingIn &&
2,155,300✔
785
        !(m_poGDS->nBands > 1 &&
10,936✔
786
          m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
10,423✔
787
          nBlockId == m_poGDS->m_nLoadedBlock))
10,048✔
788
    {
789
        if (nOffset < VSIFTellL(m_poGDS->m_fpL))
3,436✔
790
        {
791
            ReportError(CE_Failure, CPLE_NotSupported,
2,000✔
792
                        "Trying to load block %d at offset " CPL_FRMT_GUIB
793
                        " whereas current pos is " CPL_FRMT_GUIB
794
                        " (backward read not supported)",
795
                        nBlockId, static_cast<GUIntBig>(nOffset),
796
                        static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
1,000✔
797
            return CE_Failure;
1,000✔
798
        }
799
    }
800

801
    /* -------------------------------------------------------------------- */
802
    /*      Handle simple case (separate, onesampleperpixel)                */
803
    /* -------------------------------------------------------------------- */
804
    CPLErr eErr = CE_None;
2,154,300✔
805
    if (m_poGDS->nBands == 1 ||
2,154,300✔
806
        m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
110,023✔
807
    {
808
        if (nBlockReqSize < nBlockBufSize)
2,056,160✔
809
            memset(pImage, 0, nBlockBufSize);
2,465✔
810

811
        if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
2,056,160✔
812
        {
813
            memset(pImage, 0, nBlockBufSize);
62✔
814
            return CE_Failure;
62✔
815
        }
816
    }
817
    else
818
    {
819
        /* --------------------------------------------------------------------
820
         */
821
        /*      Load desired block */
822
        /* --------------------------------------------------------------------
823
         */
824
        eErr = m_poGDS->LoadBlockBuf(nBlockId);
98,146✔
825
        if (eErr != CE_None)
98,150✔
826
        {
827
            memset(pImage, 0,
41✔
828
                   static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
82✔
829
                       GDALGetDataTypeSizeBytes(eDataType));
41✔
830
            return eErr;
41✔
831
        }
832

833
        bool bDoCopyWords = true;
98,109✔
834
        if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
63,995✔
835
            eAccess == GA_ReadOnly &&
58,470✔
836
            (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
48,956✔
837
            ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
48,513✔
838
             (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
1,302✔
839
             (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
162,372✔
840
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
95,798✔
841
                    GDALGetDataTypeSizeBytes(eDataType) <
47,902✔
842
                GDALGetCacheMax64() / m_poGDS->nBands)
47,896✔
843
        {
844
            bDoCopyWords = false;
47,895✔
845
            void *ppDestBuffers[4];
846
            GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
47,895✔
847
                                                   nullptr};
848
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
203,004✔
849
            {
850
                if (iBand == nBand)
155,109✔
851
                {
852
                    ppDestBuffers[iBand - 1] = pImage;
47,895✔
853
                }
854
                else
855
                {
856
                    GDALRasterBlock *poBlock =
857
                        m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
107,214✔
858
                            nBlockXOff, nBlockYOff, true);
107,216✔
859
                    if (poBlock == nullptr)
107,213✔
860
                    {
861
                        bDoCopyWords = true;
×
862
                        break;
×
863
                    }
864
                    ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
107,213✔
865
                    apoLockedBlocks[iBand - 1] = poBlock;
107,214✔
866
                }
867
            }
868
            if (!bDoCopyWords)
47,895✔
869
            {
870
                GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
47,895✔
871
                                 m_poGDS->nBands, ppDestBuffers, eDataType,
47,895✔
872
                                 static_cast<size_t>(nBlockXSize) *
47,895✔
873
                                     nBlockYSize);
47,895✔
874
            }
875
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
203,007✔
876
            {
877
                if (apoLockedBlocks[iBand - 1])
155,111✔
878
                {
879
                    apoLockedBlocks[iBand - 1]->DropLock();
107,217✔
880
                }
881
            }
882
        }
883

884
        if (bDoCopyWords)
98,103✔
885
        {
886
            const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
50,208✔
887
            GByte *pabyImage =
50,208✔
888
                m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
50,208✔
889

890
            GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
50,208✔
891
                            pImage, eDataType, nWordBytes,
892
                            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
50,208✔
893

894
            eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
50,241✔
895
        }
896
    }
897

898
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
2,154,100✔
899

900
    return eErr;
2,154,240✔
901
}
902

903
/************************************************************************/
904
/*                           CacheMaskForBlock()                       */
905
/************************************************************************/
906

907
void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
2,156,630✔
908

909
{
910
    // Preload mask data if layout compatible and we have cached ranges
911
    if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
2,156,600✔
912
        VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
109✔
913
    {
914
        auto poBand = cpl::down_cast<GTiffRasterBand *>(
98✔
915
            m_poGDS->m_poMaskDS->GetRasterBand(1));
98✔
916
        if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
294✔
917
                poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
98✔
918
        {
919
            GDALRasterBlock *poBlock =
920
                poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
94✔
921
            if (poBlock)
94✔
922
                poBlock->DropLock();
94✔
923
        }
924
    }
925
}
2,156,490✔
926

927
/************************************************************************/
928
/*                       FillCacheForOtherBands()                       */
929
/************************************************************************/
930

931
CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
50,456✔
932

933
{
934
    /* -------------------------------------------------------------------- */
935
    /*      In the fairly common case of pixel interleaved 8bit data        */
936
    /*      that is multi-band, lets push the rest of the data into the     */
937
    /*      block cache too, to avoid (hopefully) having to redecode it.    */
938
    /*                                                                      */
939
    /*      Our following logic actually depends on the fact that the       */
940
    /*      this block is already loaded, so subsequent calls will end      */
941
    /*      up back in this method and pull from the loaded block.          */
942
    /*                                                                      */
943
    /*      Be careful not entering this portion of code from               */
944
    /*      the other bands, otherwise we'll get very deep nested calls     */
945
    /*      and O(nBands^2) performance !                                   */
946
    /*                                                                      */
947
    /*      If there are many bands and the block cache size is not big     */
948
    /*      enough to accommodate the size of all the blocks, don't enter   */
949
    /* -------------------------------------------------------------------- */
950
    CPLErr eErr = CE_None;
50,456✔
951
    if (m_poGDS->nBands != 1 &&
151,353✔
952
        m_poGDS->nBands <
50,454✔
953
            128 &&  // avoid caching for datasets with too many bands
50,447✔
954
        !m_poGDS->m_bLoadingOtherBands &&
114,027✔
955
        static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
26,260✔
956
                GDALGetDataTypeSizeBytes(eDataType) <
13,130✔
957
            GDALGetCacheMax64() / m_poGDS->nBands)
13,130✔
958
    {
959
        m_poGDS->m_bLoadingOtherBands = true;
13,125✔
960

961
        for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
54,535✔
962
        {
963
            if (iOtherBand == nBand)
41,404✔
964
                continue;
13,128✔
965

966
            GDALRasterBlock *poBlock =
967
                m_poGDS->GetRasterBand(iOtherBand)
28,276✔
968
                    ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
28,277✔
969
            if (poBlock == nullptr)
28,281✔
970
            {
971
                eErr = CE_Failure;
×
972
                break;
×
973
            }
974
            poBlock->DropLock();
28,281✔
975
        }
976

977
        m_poGDS->m_bLoadingOtherBands = false;
13,131✔
978
    }
979

980
    return eErr;
50,449✔
981
}
982

983
/************************************************************************/
984
/*                           GetDescription()                           */
985
/************************************************************************/
986

987
const char *GTiffRasterBand::GetDescription() const
206,003✔
988
{
989
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
206,003✔
990

991
    return m_osDescription;
206,003✔
992
}
993

994
/************************************************************************/
995
/*                             GetOffset()                              */
996
/************************************************************************/
997

998
double GTiffRasterBand::GetOffset(int *pbSuccess)
213,411✔
999

1000
{
1001
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
213,411✔
1002

1003
    if (pbSuccess)
213,411✔
1004
        *pbSuccess = m_bHaveOffsetScale;
6,910✔
1005
    return m_dfOffset;
213,411✔
1006
}
1007

1008
/************************************************************************/
1009
/*                              GetScale()                              */
1010
/************************************************************************/
1011

1012
double GTiffRasterBand::GetScale(int *pbSuccess)
213,414✔
1013

1014
{
1015
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
213,414✔
1016

1017
    if (pbSuccess)
213,414✔
1018
        *pbSuccess = m_bHaveOffsetScale;
6,913✔
1019
    return m_dfScale;
213,414✔
1020
}
1021

1022
/************************************************************************/
1023
/*                            GetUnitType()                             */
1024
/************************************************************************/
1025

1026
const char *GTiffRasterBand::GetUnitType()
205,211✔
1027

1028
{
1029
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
205,211✔
1030
    if (m_osUnitType.empty())
205,211✔
1031
    {
1032
        m_poGDS->LookForProjection();
205,132✔
1033
        if (m_poGDS->m_pszVertUnit)
205,132✔
1034
            return m_poGDS->m_pszVertUnit;
9✔
1035
    }
1036

1037
    return m_osUnitType.c_str();
205,202✔
1038
}
1039

1040
/************************************************************************/
1041
/*                      GetMetadataDomainList()                         */
1042
/************************************************************************/
1043

1044
char **GTiffRasterBand::GetMetadataDomainList()
12✔
1045
{
1046
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
12✔
1047

1048
    return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
12✔
1049
}
1050

1051
/************************************************************************/
1052
/*                            GetMetadata()                             */
1053
/************************************************************************/
1054

1055
char **GTiffRasterBand::GetMetadata(const char *pszDomain)
16,009✔
1056

1057
{
1058
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
16,009✔
1059
    {
1060
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
15,845✔
1061
    }
1062

1063
    return m_oGTiffMDMD.GetMetadata(pszDomain);
16,009✔
1064
}
1065

1066
/************************************************************************/
1067
/*                          GetMetadataItem()                           */
1068
/************************************************************************/
1069

1070
const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
31,349✔
1071
                                             const char *pszDomain)
1072

1073
{
1074
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
31,349✔
1075
    {
1076
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
8,231✔
1077
    }
1078

1079
    if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
31,349✔
1080
    {
1081
        int nBlockXOff = 0;
5,259✔
1082
        int nBlockYOff = 0;
5,259✔
1083

1084
        if (EQUAL(pszName, "JPEGTABLES"))
5,259✔
1085
        {
1086
            uint32_t nJPEGTableSize = 0;
11✔
1087
            void *pJPEGTable = nullptr;
11✔
1088
            if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
11✔
1089
                             &nJPEGTableSize, &pJPEGTable) != 1 ||
11✔
1090
                pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
11✔
1091
            {
1092
                return nullptr;
×
1093
            }
1094
            char *const pszHex = CPLBinaryToHex(
11✔
1095
                nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1096
            const char *pszReturn = CPLSPrintf("%s", pszHex);
11✔
1097
            CPLFree(pszHex);
11✔
1098

1099
            return pszReturn;
11✔
1100
        }
1101

1102
        if (EQUAL(pszName, "IFD_OFFSET"))
5,248✔
1103
        {
1104
            return CPLSPrintf(CPL_FRMT_GUIB,
186✔
1105
                              static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
93✔
1106
        }
1107

1108
        if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
5,155✔
1109
            2)
1110
        {
1111
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
4,422✔
1112
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
4,421✔
1113
                return nullptr;
19✔
1114

1115
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
4,403✔
1116
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
4,403✔
1117
            {
1118
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
3,571✔
1119
            }
1120

1121
            vsi_l_offset nOffset = 0;
4,403✔
1122
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
4,403✔
1123
                                           nullptr))
1124
            {
1125
                return nullptr;
190✔
1126
            }
1127

1128
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
4,213✔
1129
        }
1130

1131
        if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
733✔
1132
        {
1133
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
733✔
1134
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
732✔
1135
                return nullptr;
2✔
1136

1137
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
731✔
1138
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
731✔
1139
            {
1140
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
244✔
1141
            }
1142

1143
            vsi_l_offset nByteCount = 0;
731✔
1144
            if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
731✔
1145
                                           nullptr))
1146
            {
1147
                return nullptr;
89✔
1148
            }
1149

1150
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
642✔
1151
        }
×
1152
    }
1153
    else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
26,090✔
1154
    {
1155
        if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
131✔
1156
            return HasBlockCache() ? "1" : "0";
131✔
1157
    }
1158

1159
    const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
25,959✔
1160

1161
    if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
25,959✔
1162
        EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
23,628✔
1163
    {
1164
        // to get a chance of emitting the warning about this legacy usage
1165
        pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
5,154✔
1166
    }
1167
    return pszRet;
25,959✔
1168
}
1169

1170
/************************************************************************/
1171
/*                       GetColorInterpretation()                       */
1172
/************************************************************************/
1173

1174
GDALColorInterp GTiffRasterBand::GetColorInterpretation()
226,159✔
1175

1176
{
1177
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
226,159✔
1178

1179
    return m_eBandInterp;
226,160✔
1180
}
1181

1182
/************************************************************************/
1183
/*                           GetColorTable()                            */
1184
/************************************************************************/
1185

1186
GDALColorTable *GTiffRasterBand::GetColorTable()
11,589✔
1187

1188
{
1189
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
11,589✔
1190

1191
    if (nBand == 1)
11,589✔
1192
        return m_poGDS->m_poColorTable.get();
9,851✔
1193

1194
    return nullptr;
1,738✔
1195
}
1196

1197
/************************************************************************/
1198
/*                           GetNoDataValue()                           */
1199
/************************************************************************/
1200

1201
double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
817,000✔
1202

1203
{
1204
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
817,000✔
1205

1206
    int bSuccess = FALSE;
816,826✔
1207
    double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
816,826✔
1208
    if (bSuccess)
814,835✔
1209
    {
1210
        if (pbSuccess)
4✔
1211
            *pbSuccess = TRUE;
4✔
1212

1213
        return dfNoDataValue;
4✔
1214
    }
1215

1216
    if (m_bNoDataSet)
814,831✔
1217
    {
1218
        if (pbSuccess)
2,301✔
1219
            *pbSuccess = TRUE;
2,268✔
1220

1221
        return m_dfNoDataValue;
2,301✔
1222
    }
1223

1224
    if (m_poGDS->m_bNoDataSet)
812,530✔
1225
    {
1226
        if (pbSuccess)
422,911✔
1227
            *pbSuccess = TRUE;
422,757✔
1228

1229
        return m_poGDS->m_dfNoDataValue;
422,911✔
1230
    }
1231

1232
    if (m_bNoDataSetAsInt64)
389,619✔
1233
    {
1234
        if (pbSuccess)
×
1235
            *pbSuccess = TRUE;
×
1236

1237
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
×
1238
    }
1239

1240
    if (m_poGDS->m_bNoDataSetAsInt64)
389,619✔
1241
    {
1242
        if (pbSuccess)
×
1243
            *pbSuccess = TRUE;
×
1244

1245
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
×
1246
    }
1247

1248
    if (m_bNoDataSetAsUInt64)
389,619✔
1249
    {
1250
        if (pbSuccess)
×
1251
            *pbSuccess = TRUE;
×
1252

1253
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
×
1254
    }
1255

1256
    if (m_poGDS->m_bNoDataSetAsUInt64)
389,619✔
1257
    {
1258
        if (pbSuccess)
×
1259
            *pbSuccess = TRUE;
×
1260

1261
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
×
1262
    }
1263

1264
    if (pbSuccess)
389,619✔
1265
        *pbSuccess = FALSE;
390,866✔
1266
    return dfNoDataValue;
389,619✔
1267
}
1268

1269
/************************************************************************/
1270
/*                       GetNoDataValueAsInt64()                        */
1271
/************************************************************************/
1272

1273
int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
25✔
1274

1275
{
1276
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
25✔
1277

1278
    if (eDataType == GDT_UInt64)
25✔
1279
    {
1280
        CPLError(CE_Failure, CPLE_AppDefined,
×
1281
                 "GetNoDataValueAsUInt64() should be called instead");
1282
        if (pbSuccess)
×
1283
            *pbSuccess = FALSE;
×
1284
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
×
1285
    }
1286
    if (eDataType != GDT_Int64)
25✔
1287
    {
1288
        CPLError(CE_Failure, CPLE_AppDefined,
×
1289
                 "GetNoDataValue() should be called instead");
1290
        if (pbSuccess)
×
1291
            *pbSuccess = FALSE;
×
1292
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
×
1293
    }
1294

1295
    int bSuccess = FALSE;
25✔
1296
    const auto nNoDataValue =
1297
        GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
25✔
1298
    if (bSuccess)
25✔
1299
    {
1300
        if (pbSuccess)
×
1301
            *pbSuccess = TRUE;
×
1302

1303
        return nNoDataValue;
×
1304
    }
1305

1306
    if (m_bNoDataSetAsInt64)
25✔
1307
    {
1308
        if (pbSuccess)
2✔
1309
            *pbSuccess = TRUE;
2✔
1310

1311
        return m_nNoDataValueInt64;
2✔
1312
    }
1313

1314
    if (m_poGDS->m_bNoDataSetAsInt64)
23✔
1315
    {
1316
        if (pbSuccess)
7✔
1317
            *pbSuccess = TRUE;
6✔
1318

1319
        return m_poGDS->m_nNoDataValueInt64;
7✔
1320
    }
1321

1322
    if (pbSuccess)
16✔
1323
        *pbSuccess = FALSE;
16✔
1324
    return nNoDataValue;
16✔
1325
}
1326

1327
/************************************************************************/
1328
/*                      GetNoDataValueAsUInt64()                        */
1329
/************************************************************************/
1330

1331
uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
16✔
1332

1333
{
1334
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
16✔
1335

1336
    if (eDataType == GDT_Int64)
16✔
1337
    {
1338
        CPLError(CE_Failure, CPLE_AppDefined,
×
1339
                 "GetNoDataValueAsInt64() should be called instead");
1340
        if (pbSuccess)
×
1341
            *pbSuccess = FALSE;
×
1342
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
×
1343
    }
1344
    if (eDataType != GDT_UInt64)
16✔
1345
    {
1346
        CPLError(CE_Failure, CPLE_AppDefined,
×
1347
                 "GetNoDataValue() should be called instead");
1348
        if (pbSuccess)
×
1349
            *pbSuccess = FALSE;
×
1350
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
×
1351
    }
1352

1353
    int bSuccess = FALSE;
16✔
1354
    const auto nNoDataValue =
1355
        GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
16✔
1356
    if (bSuccess)
16✔
1357
    {
1358
        if (pbSuccess)
×
1359
            *pbSuccess = TRUE;
×
1360

1361
        return nNoDataValue;
×
1362
    }
1363

1364
    if (m_bNoDataSetAsUInt64)
16✔
1365
    {
1366
        if (pbSuccess)
×
1367
            *pbSuccess = TRUE;
×
1368

1369
        return m_nNoDataValueUInt64;
×
1370
    }
1371

1372
    if (m_poGDS->m_bNoDataSetAsUInt64)
16✔
1373
    {
1374
        if (pbSuccess)
7✔
1375
            *pbSuccess = TRUE;
6✔
1376

1377
        return m_poGDS->m_nNoDataValueUInt64;
7✔
1378
    }
1379

1380
    if (pbSuccess)
9✔
1381
        *pbSuccess = FALSE;
9✔
1382
    return nNoDataValue;
9✔
1383
}
1384

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

1389
int GTiffRasterBand::GetOverviewCount()
655,763✔
1390

1391
{
1392
    if (!m_poGDS->AreOverviewsEnabled())
655,763✔
1393
        return 0;
30✔
1394

1395
    m_poGDS->ScanDirectories();
655,733✔
1396

1397
    if (m_poGDS->m_nOverviewCount > 0)
655,733✔
1398
    {
1399
        return m_poGDS->m_nOverviewCount;
4,993✔
1400
    }
1401

1402
    const int nOverviewCount = GDALRasterBand::GetOverviewCount();
650,740✔
1403
    if (nOverviewCount > 0)
650,740✔
1404
        return nOverviewCount;
370✔
1405

1406
    // Implicit JPEG overviews are normally hidden, except when doing
1407
    // IRasterIO() operations.
1408
    if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
650,370✔
1409
        return m_poGDS->GetJPEGOverviewCount();
643,434✔
1410

1411
    return 0;
6,936✔
1412
}
1413

1414
/************************************************************************/
1415
/*                            GetOverview()                             */
1416
/************************************************************************/
1417

1418
GDALRasterBand *GTiffRasterBand::GetOverview(int i)
8,658✔
1419

1420
{
1421
    m_poGDS->ScanDirectories();
8,658✔
1422

1423
    if (m_poGDS->m_nOverviewCount > 0)
8,655✔
1424
    {
1425
        // Do we have internal overviews?
1426
        if (i < 0 || i >= m_poGDS->m_nOverviewCount)
8,085✔
1427
            return nullptr;
8✔
1428

1429
        return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
8,077✔
1430
    }
1431

1432
    GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
570✔
1433
    if (poOvrBand != nullptr)
571✔
1434
        return poOvrBand;
366✔
1435

1436
    // For consistency with GetOverviewCount(), we should also test
1437
    // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1438
    // to query them for testing purposes.
1439
    if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
205✔
1440
        return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
164✔
1441

1442
    return nullptr;
41✔
1443
}
1444

1445
/************************************************************************/
1446
/*                           GetMaskFlags()                             */
1447
/************************************************************************/
1448

1449
int GTiffRasterBand::GetMaskFlags()
18,467✔
1450
{
1451
    m_poGDS->ScanDirectories();
18,467✔
1452

1453
    if (m_poGDS->m_poExternalMaskDS != nullptr)
18,467✔
1454
    {
1455
        return GMF_PER_DATASET;
×
1456
    }
1457

1458
    if (m_poGDS->m_poMaskDS != nullptr)
18,467✔
1459
    {
1460
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
204✔
1461
        {
1462
            return GMF_PER_DATASET;
197✔
1463
        }
1464

1465
        return 0;
7✔
1466
    }
1467

1468
    if (m_poGDS->m_bIsOverview)
18,263✔
1469
    {
1470
        return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
392✔
1471
    }
1472

1473
    return GDALPamRasterBand::GetMaskFlags();
17,871✔
1474
}
1475

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

1480
GDALRasterBand *GTiffRasterBand::GetMaskBand()
115,511✔
1481
{
1482
    m_poGDS->ScanDirectories();
115,511✔
1483

1484
    if (m_poGDS->m_poExternalMaskDS != nullptr)
115,347✔
1485
    {
1486
        return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
×
1487
    }
1488

1489
    if (m_poGDS->m_poMaskDS != nullptr)
115,353✔
1490
    {
1491
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
679✔
1492
            return m_poGDS->m_poMaskDS->GetRasterBand(1);
665✔
1493

1494
        return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
14✔
1495
    }
1496

1497
    if (m_poGDS->m_bIsOverview)
114,674✔
1498
    {
1499
        GDALRasterBand *poBaseMask =
1500
            m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
116✔
1501
        if (poBaseMask)
116✔
1502
        {
1503
            const int nOverviews = poBaseMask->GetOverviewCount();
116✔
1504
            for (int i = 0; i < nOverviews; i++)
161✔
1505
            {
1506
                GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
93✔
1507
                if (poOvr && poOvr->GetXSize() == GetXSize() &&
141✔
1508
                    poOvr->GetYSize() == GetYSize())
48✔
1509
                {
1510
                    return poOvr;
48✔
1511
                }
1512
            }
1513
        }
1514
    }
1515

1516
    return GDALPamRasterBand::GetMaskBand();
114,626✔
1517
}
1518

1519
/************************************************************************/
1520
/*                            IsMaskBand()                              */
1521
/************************************************************************/
1522

1523
bool GTiffRasterBand::IsMaskBand() const
9,118✔
1524
{
1525
    return (m_poGDS->m_poImageryDS != nullptr &&
9,149✔
1526
            m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
31✔
1527
           m_eBandInterp == GCI_AlphaBand ||
16,157✔
1528
           m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
16,126✔
1529
}
1530

1531
/************************************************************************/
1532
/*                         GetMaskValueRange()                          */
1533
/************************************************************************/
1534

1535
GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
×
1536
{
1537
    if (!IsMaskBand())
×
1538
        return GMVR_UNKNOWN;
×
1539
    if (m_poGDS->m_nBitsPerSample == 1)
×
1540
        return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
×
1541
                                          : GMVR_0_AND_1_ONLY;
×
1542
    return GMVR_UNKNOWN;
×
1543
}
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