Coverage Report

Created: 2026-02-14 06:52

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/gtiff/gtiffrasterband_read.cpp
Line
Count
Source
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 "gdal_priv.h"
28
#include "gdal_mdreader.h"
29
#include "gtiff.h"
30
#include "tifvsi.h"
31
32
/************************************************************************/
33
/*                           GetDefaultRAT()                            */
34
/************************************************************************/
35
36
GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
37
38
0
{
39
0
    if (m_poGDS->m_poBaseDS != nullptr)
40
0
        return m_poRAT.get();
41
42
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
43
44
    // RAT from PAM has priority over RAT in GDAL_METADATA TIFF tag
45
0
    if (!m_bRATTriedReadingFromPAM)
46
0
    {
47
0
        m_bRATTriedReadingFromPAM = true;
48
0
        auto poRAT = GDALPamRasterBand::GetDefaultRAT();
49
0
        if (poRAT)
50
0
        {
51
0
            m_bRATSet = true;
52
0
            m_poRAT.reset(poRAT->Clone());
53
0
            return m_poRAT.get();
54
0
        }
55
0
    }
56
57
0
    if (m_bRATSet)
58
0
        return m_poRAT.get();
59
60
0
    m_bRATSet = true;
61
62
    // Try reading from a .vat.dbf side car file
63
0
    if (!GDALCanFileAcceptSidecarFile(m_poGDS->m_osFilename.c_str()))
64
0
        return nullptr;
65
0
    const std::string osVATDBF = m_poGDS->m_osFilename + ".vat.dbf";
66
0
    CSLConstList papszSiblingFiles = m_poGDS->GetSiblingFiles();
67
0
    if (papszSiblingFiles &&
68
        // cppcheck-suppress knownConditionTrueFalse
69
0
        GDALCanReliablyUseSiblingFileList(osVATDBF.c_str()))
70
0
    {
71
0
        int iSibling =
72
0
            CSLFindString(papszSiblingFiles, CPLGetFilename(osVATDBF.c_str()));
73
0
        if (iSibling >= 0)
74
0
        {
75
0
            CPLString osFilename = m_poGDS->m_osFilename;
76
0
            osFilename.resize(
77
0
                m_poGDS->m_osFilename.size() -
78
0
                strlen(CPLGetFilename(m_poGDS->m_osFilename.c_str())));
79
0
            osFilename += papszSiblingFiles[iSibling];
80
0
            m_poRAT = GDALLoadVATDBF(osFilename.c_str());
81
0
        }
82
0
        return m_poRAT.get();
83
0
    }
84
0
    VSIStatBufL sStatBuf;
85
0
    if (VSIStatL(osVATDBF.c_str(), &sStatBuf) == 0)
86
0
        m_poRAT = GDALLoadVATDBF(osVATDBF.c_str());
87
0
    return m_poRAT.get();
88
0
}
89
90
/************************************************************************/
91
/*                            GetHistogram()                            */
92
/************************************************************************/
93
94
CPLErr GTiffRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
95
                                     GUIntBig *panHistogram,
96
                                     int bIncludeOutOfRange, int bApproxOK,
97
                                     GDALProgressFunc pfnProgress,
98
                                     void *pProgressData)
99
0
{
100
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
101
0
    return GDALPamRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
102
0
                                           bIncludeOutOfRange, bApproxOK,
103
0
                                           pfnProgress, pProgressData);
104
0
}
105
106
/************************************************************************/
107
/*                        GetDefaultHistogram()                         */
108
/************************************************************************/
109
110
CPLErr GTiffRasterBand::GetDefaultHistogram(
111
    double *pdfMin, double *pdfMax, int *pnBuckets, GUIntBig **ppanHistogram,
112
    int bForce, GDALProgressFunc pfnProgress, void *pProgressData)
113
0
{
114
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
115
0
    return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
116
0
                                                  ppanHistogram, bForce,
117
0
                                                  pfnProgress, pProgressData);
118
0
}
119
120
/************************************************************************/
121
/*                              DirectIO()                              */
122
/************************************************************************/
123
124
// Reads directly bytes from the file using ReadMultiRange(), and by-pass
125
// block reading. Restricted to simple TIFF configurations
126
// (uncompressed data, standard data types). Particularly useful to extract
127
// sub-windows of data on a large /vsicurl dataset).
128
// Returns -1 if DirectIO() can't be supported on that file.
129
130
int GTiffRasterBand::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
131
                              int nXSize, int nYSize, void *pData,
132
                              int nBufXSize, int nBufYSize,
133
                              GDALDataType eBufType, GSpacing nPixelSpace,
134
                              GSpacing nLineSpace,
135
                              GDALRasterIOExtraArg *psExtraArg)
136
0
{
137
0
    const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
138
0
    if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
139
0
          (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
140
0
           m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
141
0
           m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
142
0
          IsBaseGTiffClass()))
143
0
    {
144
0
        return -1;
145
0
    }
146
0
    m_poGDS->Crystalize();
147
148
    // Only know how to deal with nearest neighbour in this optimized routine.
149
0
    if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
150
0
        psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
151
0
    {
152
0
        return -1;
153
0
    }
154
155
#if DEBUG_VERBOSE
156
    CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
157
             nYSize, nBufXSize, nBufYSize);
158
#endif
159
160
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
161
0
    if (m_poGDS->GetAccess() == GA_Update)
162
0
    {
163
0
        m_poGDS->FlushCache(false);
164
0
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
165
0
    }
166
167
0
    if (TIFFIsTiled(m_poGDS->m_hTIFF))
168
0
    {
169
0
        const int nDTSize = nDTSizeBits / 8;
170
0
        const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
171
0
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize * nDTSize *
172
0
            (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands
173
0
                                                             : 1));
174
0
        if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
175
0
        {
176
0
            m_poGDS->m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
177
0
                VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
178
0
            if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
179
0
                return CE_Failure;
180
0
        }
181
182
0
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
183
0
        FetchBufferDirectIO oFetcher(fp,
184
0
                                     m_poGDS->m_pTempBufferForCommonDirectIO,
185
0
                                     nTempBufferForCommonDirectIOSize);
186
187
0
        return m_poGDS->CommonDirectIOClassic(
188
0
            oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
189
0
            eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0);
190
0
    }
191
192
    // Get strip offsets.
193
0
    toff_t *panTIFFOffsets = nullptr;
194
0
    if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
195
0
                      &panTIFFOffsets) ||
196
0
        panTIFFOffsets == nullptr)
197
0
    {
198
0
        return CE_Failure;
199
0
    }
200
201
    // Sub-sampling or over-sampling can only be done at last stage.
202
0
    int nReqXSize = nXSize;
203
    // Can do sub-sampling at the extraction stage.
204
0
    const int nReqYSize = std::min(nBufYSize, nYSize);
205
    // TODO(schwehr): Make ppData be GByte**.
206
0
    void **ppData =
207
0
        static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
208
0
    vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
209
0
        VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
210
0
    size_t *panSizes =
211
0
        static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
212
0
    const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
213
0
    void *pTmpBuffer = nullptr;
214
0
    int eErr = CE_None;
215
0
    int nContigBands =
216
0
        m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
217
0
    int nSrcPixelSize = nDTSize * nContigBands;
218
219
0
    if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
220
0
        eErr = CE_Failure;
221
0
    else if (nXSize != nBufXSize || nYSize != nBufYSize ||
222
0
             eBufType != eDataType ||
223
0
             nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
224
0
             nContigBands > 1)
225
0
    {
226
        // We need a temporary buffer for over-sampling/sub-sampling
227
        // and/or data type conversion.
228
0
        pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
229
0
        if (pTmpBuffer == nullptr)
230
0
            eErr = CE_Failure;
231
0
    }
232
233
    // Prepare data extraction.
234
0
    const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
235
236
0
    for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
237
0
    {
238
0
        if (pTmpBuffer == nullptr)
239
0
            ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
240
0
        else
241
0
            ppData[iLine] =
242
0
                static_cast<GByte *>(pTmpBuffer) +
243
0
                static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
244
0
        int nSrcLine = 0;
245
0
        if (nBufYSize < nYSize)  // Sub-sampling in y.
246
0
            nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
247
0
        else
248
0
            nSrcLine = nYOff + iLine;
249
250
0
        const int nBlockXOff = 0;
251
0
        const int nBlockYOff = nSrcLine / nBlockYSize;
252
0
        const int nYOffsetInBlock = nSrcLine % nBlockYSize;
253
0
        const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
254
255
0
        panOffsets[iLine] = panTIFFOffsets[nBlockId];
256
0
        if (panOffsets[iLine] == 0)  // We don't support sparse files.
257
0
            eErr = -1;
258
259
0
        panOffsets[iLine] +=
260
0
            (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
261
0
            nSrcPixelSize;
262
0
        panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
263
0
    }
264
265
    // Extract data from the file.
266
0
    if (eErr == CE_None)
267
0
    {
268
0
        VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
269
0
        const int nRet =
270
0
            VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
271
0
        if (nRet != 0)
272
0
            eErr = CE_Failure;
273
0
    }
274
275
    // Byte-swap if necessary.
276
0
    if (eErr == CE_None && TIFFIsByteSwapped(m_poGDS->m_hTIFF))
277
0
    {
278
0
        for (int iLine = 0; iLine < nReqYSize; ++iLine)
279
0
        {
280
0
            if (GDALDataTypeIsComplex(eDataType))
281
0
                GDALSwapWords(ppData[iLine], nDTSize / 2,
282
0
                              2 * nReqXSize * nContigBands, nDTSize / 2);
283
0
            else
284
0
                GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
285
0
                              nDTSize);
286
0
        }
287
0
    }
288
289
    // Over-sampling/sub-sampling and/or data type conversion.
290
0
    const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
291
0
    if (eErr == CE_None && pTmpBuffer != nullptr)
292
0
    {
293
0
        const bool bOneByteCopy =
294
0
            (eDataType == eBufType &&
295
0
             (eDataType == GDT_UInt8 || eDataType == GDT_Int8));
296
0
        for (int iY = 0; iY < nBufYSize; ++iY)
297
0
        {
298
0
            const int iSrcY = nBufYSize <= nYSize
299
0
                                  ? iY
300
0
                                  : static_cast<int>((iY + 0.5) * dfSrcYInc);
301
302
0
            GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
303
0
                                 (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
304
0
            GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
305
0
            if (nBufXSize == nXSize)
306
0
            {
307
0
                GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
308
0
                              pabyDstData, eBufType,
309
0
                              static_cast<int>(nPixelSpace), nBufXSize);
310
0
            }
311
0
            else
312
0
            {
313
0
                if (bOneByteCopy)
314
0
                {
315
0
                    double dfSrcX = 0.5 * dfSrcXInc;
316
0
                    for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
317
0
                    {
318
0
                        const int iSrcX = static_cast<int>(dfSrcX);
319
0
                        pabyDstData[iX * nPixelSpace] =
320
0
                            pabySrcData[iSrcX * nSrcPixelSize];
321
0
                    }
322
0
                }
323
0
                else
324
0
                {
325
0
                    double dfSrcX = 0.5 * dfSrcXInc;
326
0
                    for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
327
0
                    {
328
0
                        const int iSrcX = static_cast<int>(dfSrcX);
329
0
                        GDALCopyWords(
330
0
                            pabySrcData + iSrcX * nSrcPixelSize, eDataType, 0,
331
0
                            pabyDstData + iX * nPixelSpace, eBufType, 0, 1);
332
0
                    }
333
0
                }
334
0
            }
335
0
        }
336
0
    }
337
338
    // Cleanup.
339
0
    CPLFree(pTmpBuffer);
340
0
    CPLFree(ppData);
341
0
    CPLFree(panOffsets);
342
0
    CPLFree(panSizes);
343
344
0
    return eErr;
345
0
}
346
347
/************************************************************************/
348
/*                         GetVirtualMemAuto()                          */
349
/************************************************************************/
350
351
CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
352
                                                  int *pnPixelSpace,
353
                                                  GIntBig *pnLineSpace,
354
                                                  CSLConstList papszOptions)
355
0
{
356
0
    const char *pszImpl = CSLFetchNameValueDef(
357
0
        papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
358
0
    if (EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") || EQUAL(pszImpl, "1") ||
359
0
        EQUAL(pszImpl, "TRUE"))
360
0
    {
361
0
        return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
362
0
                                                 pnLineSpace, papszOptions);
363
0
    }
364
365
0
    CPLVirtualMem *psRet = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace,
366
0
                                                     pnLineSpace, papszOptions);
367
0
    if (psRet != nullptr)
368
0
    {
369
0
        CPLDebug("GTiff", "GetVirtualMemAuto(): Using memory file mapping");
370
0
        return psRet;
371
0
    }
372
373
0
    if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
374
0
        EQUAL(pszImpl, "FALSE"))
375
0
    {
376
0
        return nullptr;
377
0
    }
378
379
0
    CPLDebug("GTiff", "GetVirtualMemAuto(): Defaulting to base implementation");
380
0
    return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
381
0
                                             papszOptions);
382
0
}
383
384
/************************************************************************/
385
/*                      DropReferenceVirtualMem()                       */
386
/************************************************************************/
387
388
void GTiffRasterBand::DropReferenceVirtualMem(void *pUserData)
389
0
{
390
    // This function may also be called when the dataset and rasterband
391
    // objects have been destroyed.
392
    // If they are still alive, it updates the reference counter of the
393
    // base mapping to invalidate the pointer to it if needed.
394
395
0
    GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(pUserData);
396
0
    GTiffRasterBand *poSelf = *ppoSelf;
397
398
0
    if (poSelf != nullptr)
399
0
    {
400
0
        if (--(poSelf->m_poGDS->m_nRefBaseMapping) == 0)
401
0
        {
402
0
            poSelf->m_poGDS->m_pBaseMapping = nullptr;
403
0
        }
404
0
        poSelf->m_aSetPSelf.erase(ppoSelf);
405
0
    }
406
0
    CPLFree(pUserData);
407
0
}
408
409
/************************************************************************/
410
/*                     GetVirtualMemAutoInternal()                      */
411
/************************************************************************/
412
413
CPLVirtualMem *GTiffRasterBand::GetVirtualMemAutoInternal(
414
    GDALRWFlag eRWFlag, int *pnPixelSpace, GIntBig *pnLineSpace,
415
    CSLConstList papszOptions)
416
0
{
417
0
    int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
418
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
419
0
        nLineSize *= m_poGDS->nBands;
420
421
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
422
0
    {
423
        // In case of a pixel interleaved file, we save virtual memory space
424
        // by reusing a base mapping that embraces the whole imagery.
425
0
        if (m_poGDS->m_pBaseMapping != nullptr)
426
0
        {
427
            // Offset between the base mapping and the requested mapping.
428
0
            vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
429
0
                                   GDALGetDataTypeSizeBytes(eDataType);
430
431
0
            GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
432
0
                CPLCalloc(1, sizeof(GTiffRasterBand *)));
433
0
            *ppoSelf = this;
434
435
0
            CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
436
0
                m_poGDS->m_pBaseMapping, nOffset,
437
0
                CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
438
0
                GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
439
0
            if (pVMem == nullptr)
440
0
            {
441
0
                CPLFree(ppoSelf);
442
0
                return nullptr;
443
0
            }
444
445
            // Mechanism used so that the memory mapping object can be
446
            // destroyed after the raster band.
447
0
            m_aSetPSelf.insert(ppoSelf);
448
0
            ++m_poGDS->m_nRefBaseMapping;
449
0
            *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
450
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
451
0
                *pnPixelSpace *= m_poGDS->nBands;
452
0
            *pnLineSpace = nLineSize;
453
0
            return pVMem;
454
0
        }
455
0
    }
456
457
0
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
458
459
0
    vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
460
461
0
    if (!(CPLIsVirtualMemFileMapAvailable() &&
462
0
          VSIFGetNativeFileDescriptorL(fp) != nullptr &&
463
#if SIZEOF_VOIDP == 4
464
          nLength == static_cast<size_t>(nLength) &&
465
#endif
466
0
          m_poGDS->m_nCompression == COMPRESSION_NONE &&
467
0
          (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
468
0
           m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
469
0
           m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
470
0
          m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
471
0
          !TIFFIsTiled(m_poGDS->m_hTIFF) &&
472
0
          !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
473
0
    {
474
0
        return nullptr;
475
0
    }
476
477
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
478
0
    if (m_poGDS->GetAccess() == GA_Update)
479
0
    {
480
0
        m_poGDS->FlushCache(false);
481
0
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
482
0
    }
483
484
    // Get strip offsets.
485
0
    toff_t *panTIFFOffsets = nullptr;
486
0
    if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
487
0
                      &panTIFFOffsets) ||
488
0
        panTIFFOffsets == nullptr)
489
0
    {
490
0
        return nullptr;
491
0
    }
492
493
0
    GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
494
0
                            GDALGetDataTypeSizeBytes(eDataType);
495
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
496
0
        nBlockSize *= m_poGDS->nBands;
497
498
0
    int nBlocks = m_poGDS->m_nBlocksPerBand;
499
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
500
0
        nBlocks *= m_poGDS->nBands;
501
0
    int i = 0;  // Used after for.
502
0
    for (; i < nBlocks; ++i)
503
0
    {
504
0
        if (panTIFFOffsets[i] != 0)
505
0
            break;
506
0
    }
507
0
    if (i == nBlocks)
508
0
    {
509
        // All zeroes.
510
0
        if (m_poGDS->eAccess == GA_Update)
511
0
        {
512
            // Initialize the file with empty blocks so that the file has
513
            // the appropriate size.
514
515
0
            toff_t *panByteCounts = nullptr;
516
0
            if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
517
0
                              &panByteCounts) ||
518
0
                panByteCounts == nullptr)
519
0
            {
520
0
                return nullptr;
521
0
            }
522
0
            if (VSIFSeekL(fp, 0, SEEK_END) != 0)
523
0
                return nullptr;
524
0
            vsi_l_offset nBaseOffset = VSIFTellL(fp);
525
526
            // Just write one tile with libtiff to put it in appropriate state.
527
0
            GByte *pabyData =
528
0
                static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
529
0
            if (pabyData == nullptr)
530
0
            {
531
0
                return nullptr;
532
0
            }
533
0
            const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
534
0
                                                   pabyData, nBlockSize);
535
0
            VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
536
0
            VSIFree(pabyData);
537
0
            if (ret != nBlockSize)
538
0
            {
539
0
                return nullptr;
540
0
            }
541
0
            CPLAssert(panTIFFOffsets[0] == nBaseOffset);
542
0
            CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
543
544
            // Now simulate the writing of other blocks.
545
0
            assert(nBlocks > 0);
546
0
            assert(static_cast<vsi_l_offset>(nBlockSize) <
547
0
                   std::numeric_limits<vsi_l_offset>::max() / nBlocks);
548
0
            const vsi_l_offset nDataSize =
549
0
                static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
550
0
            if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
551
0
                return nullptr;
552
553
0
            for (i = 1; i < nBlocks; ++i)
554
0
            {
555
0
                panTIFFOffsets[i] =
556
0
                    nBaseOffset + i * static_cast<toff_t>(nBlockSize);
557
0
                panByteCounts[i] = nBlockSize;
558
0
            }
559
0
        }
560
0
        else
561
0
        {
562
0
            CPLDebug("GTiff", "Sparse files not supported in file mapping");
563
0
            return nullptr;
564
0
        }
565
0
    }
566
567
0
    GIntBig nBlockSpacing = 0;
568
0
    bool bCompatibleSpacing = true;
569
0
    toff_t nPrevOffset = 0;
570
0
    for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
571
0
    {
572
0
        toff_t nCurOffset = 0;
573
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
574
0
            nCurOffset =
575
0
                panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
576
0
        else
577
0
            nCurOffset = panTIFFOffsets[i];
578
0
        if (nCurOffset == 0)
579
0
        {
580
0
            bCompatibleSpacing = false;
581
0
            break;
582
0
        }
583
0
        if (i > 0)
584
0
        {
585
0
            const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
586
0
            if (i == 1)
587
0
            {
588
0
                if (nCurSpacing !=
589
0
                    static_cast<GIntBig>(nBlockYSize) * nLineSize)
590
0
                {
591
0
                    bCompatibleSpacing = false;
592
0
                    break;
593
0
                }
594
0
                nBlockSpacing = nCurSpacing;
595
0
            }
596
0
            else if (nBlockSpacing != nCurSpacing)
597
0
            {
598
0
                bCompatibleSpacing = false;
599
0
                break;
600
0
            }
601
0
        }
602
0
        nPrevOffset = nCurOffset;
603
0
    }
604
605
0
    if (!bCompatibleSpacing)
606
0
    {
607
0
        return nullptr;
608
0
    }
609
610
0
    vsi_l_offset nOffset = 0;
611
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
612
0
    {
613
0
        CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
614
0
        nOffset = panTIFFOffsets[0];
615
0
    }
616
0
    else
617
0
    {
618
0
        nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
619
0
    }
620
0
    CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
621
0
        fp, nOffset, nLength,
622
0
        eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
623
0
        nullptr, nullptr);
624
0
    if (pVMem == nullptr)
625
0
    {
626
0
        return nullptr;
627
0
    }
628
629
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
630
0
    {
631
        // TODO(schwehr): Revisit this block.
632
0
        m_poGDS->m_pBaseMapping = pVMem;
633
0
        pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
634
0
                                          papszOptions);
635
        // Drop ref on base mapping.
636
0
        CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
637
0
        if (pVMem == nullptr)
638
0
            m_poGDS->m_pBaseMapping = nullptr;
639
0
    }
640
0
    else
641
0
    {
642
0
        *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
643
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
644
0
            *pnPixelSpace *= m_poGDS->nBands;
645
0
        *pnLineSpace = nLineSize;
646
0
    }
647
0
    return pVMem;
648
0
}
649
650
/************************************************************************/
651
/*                       IGetDataCoverageStatus()                       */
652
/************************************************************************/
653
654
int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
655
                                            int nYSize, int nMaskFlagStop,
656
                                            double *pdfDataPct)
657
0
{
658
0
    if (eAccess == GA_Update)
659
0
        m_poGDS->FlushCache(false);
660
661
0
    const int iXBlockStart = nXOff / nBlockXSize;
662
0
    const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
663
0
    const int iYBlockStart = nYOff / nBlockYSize;
664
0
    const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
665
0
    int nStatus = 0;
666
0
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
667
0
    GIntBig nPixelsData = 0;
668
0
    for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
669
0
    {
670
0
        for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
671
0
        {
672
0
            const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
673
0
            int nBlockId = nBlockIdBand0;
674
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
675
0
                nBlockId =
676
0
                    nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
677
0
            vsi_l_offset nOffset = 0;
678
0
            vsi_l_offset nLength = 0;
679
0
            bool bHasData = false;
680
0
            bool bError = false;
681
0
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
682
0
                                           &bError))
683
0
            {
684
0
                if (bError)
685
0
                    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
686
0
                nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
687
0
            }
688
0
            else
689
0
            {
690
0
                if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
691
0
                    m_poGDS->eAccess == GA_ReadOnly &&
692
0
                    ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
693
0
                      !m_bNoDataSetAsUInt64) ||
694
0
                     (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
695
0
                     (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
696
0
                     (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
697
0
                {
698
0
                    VSIRangeStatus eStatus =
699
0
                        VSIFGetRangeStatusL(fp, nOffset, nLength);
700
0
                    if (eStatus == VSI_RANGE_STATUS_HOLE)
701
0
                    {
702
0
                        nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
703
0
                    }
704
0
                    else
705
0
                    {
706
0
                        bHasData = true;
707
0
                    }
708
0
                }
709
0
                else
710
0
                {
711
0
                    bHasData = true;
712
0
                }
713
0
            }
714
0
            if (bHasData)
715
0
            {
716
0
                const int nXBlockRight =
717
0
                    (iX * nBlockXSize > INT_MAX - nBlockXSize)
718
0
                        ? INT_MAX
719
0
                        : (iX + 1) * nBlockXSize;
720
0
                const int nYBlockBottom =
721
0
                    (iY * nBlockYSize > INT_MAX - nBlockYSize)
722
0
                        ? INT_MAX
723
0
                        : (iY + 1) * nBlockYSize;
724
725
0
                nPixelsData += (static_cast<GIntBig>(
726
0
                                    std::min(nXBlockRight, nXOff + nXSize)) -
727
0
                                std::max(iX * nBlockXSize, nXOff)) *
728
0
                               (std::min(nYBlockBottom, nYOff + nYSize) -
729
0
                                std::max(iY * nBlockYSize, nYOff));
730
0
                nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
731
0
            }
732
0
            if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
733
0
            {
734
0
                if (pdfDataPct)
735
0
                    *pdfDataPct = -1.0;
736
0
                return nStatus;
737
0
            }
738
0
        }
739
0
    }
740
0
    if (pdfDataPct)
741
0
        *pdfDataPct =
742
0
            100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
743
0
    return nStatus;
744
0
}
745
746
/************************************************************************/
747
/*                             IReadBlock()                             */
748
/************************************************************************/
749
750
CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
751
752
0
{
753
0
    m_poGDS->Crystalize();
754
755
0
    GPtrDiff_t nBlockBufSize = 0;
756
0
    if (TIFFIsTiled(m_poGDS->m_hTIFF))
757
0
    {
758
0
        nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
759
0
    }
760
0
    else
761
0
    {
762
0
        CPLAssert(nBlockXOff == 0);
763
0
        nBlockBufSize =
764
0
            static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
765
0
    }
766
767
0
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
768
769
    /* -------------------------------------------------------------------- */
770
    /*      The bottom most partial tiles and strips are sometimes only     */
771
    /*      partially encoded.  This code reduces the requested data so     */
772
    /*      an error won't be reported in this case. (#1179)                */
773
    /* -------------------------------------------------------------------- */
774
0
    auto nBlockReqSize = nBlockBufSize;
775
776
0
    if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
777
0
    {
778
0
        nBlockReqSize =
779
0
            (nBlockBufSize / nBlockYSize) *
780
0
            (nBlockYSize -
781
0
             static_cast<int>(
782
0
                 (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
783
0
                 nRasterYSize));
784
0
    }
785
786
    /* -------------------------------------------------------------------- */
787
    /*      Handle the case of a strip or tile that doesn't exist yet.      */
788
    /*      Just set to zeros and return.                                   */
789
    /* -------------------------------------------------------------------- */
790
0
    vsi_l_offset nOffset = 0;
791
0
    bool bErrOccurred = false;
792
0
    if (nBlockId != m_poGDS->m_nLoadedBlock &&
793
0
        !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
794
0
    {
795
0
        NullBlock(pImage);
796
0
        if (bErrOccurred)
797
0
            return CE_Failure;
798
0
        return CE_None;
799
0
    }
800
801
0
    if (m_poGDS->m_bStreamingIn &&
802
0
        !(m_poGDS->nBands > 1 &&
803
0
          m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
804
0
          nBlockId == m_poGDS->m_nLoadedBlock))
805
0
    {
806
0
        if (nOffset < VSIFTellL(m_poGDS->m_fpL))
807
0
        {
808
0
            ReportError(CE_Failure, CPLE_NotSupported,
809
0
                        "Trying to load block %d at offset " CPL_FRMT_GUIB
810
0
                        " whereas current pos is " CPL_FRMT_GUIB
811
0
                        " (backward read not supported)",
812
0
                        nBlockId, static_cast<GUIntBig>(nOffset),
813
0
                        static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
814
0
            return CE_Failure;
815
0
        }
816
0
    }
817
818
    /* -------------------------------------------------------------------- */
819
    /*      Handle simple case (separate, onesampleperpixel)                */
820
    /* -------------------------------------------------------------------- */
821
0
    CPLErr eErr = CE_None;
822
0
    if (m_poGDS->nBands == 1 ||
823
0
        m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
824
0
    {
825
0
        if (nBlockReqSize < nBlockBufSize)
826
0
            memset(pImage, 0, nBlockBufSize);
827
828
0
        if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
829
0
        {
830
0
            memset(pImage, 0, nBlockBufSize);
831
0
            return CE_Failure;
832
0
        }
833
0
    }
834
0
    else
835
0
    {
836
        /* --------------------------------------------------------------------
837
         */
838
        /*      Load desired block */
839
        /* --------------------------------------------------------------------
840
         */
841
0
        eErr = m_poGDS->LoadBlockBuf(nBlockId);
842
0
        if (eErr != CE_None)
843
0
        {
844
0
            memset(pImage, 0,
845
0
                   static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
846
0
                       GDALGetDataTypeSizeBytes(eDataType));
847
0
            return eErr;
848
0
        }
849
850
0
        bool bDoCopyWords = true;
851
0
        if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
852
0
            eAccess == GA_ReadOnly &&
853
0
            (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
854
0
            ((eDataType == GDT_UInt8 && m_poGDS->m_nBitsPerSample == 8) ||
855
0
             (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
856
0
             (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
857
0
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
858
0
                    GDALGetDataTypeSizeBytes(eDataType) <
859
0
                GDALGetCacheMax64() / m_poGDS->nBands)
860
0
        {
861
0
            bDoCopyWords = false;
862
0
            void *ppDestBuffers[4];
863
0
            GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
864
0
                                                   nullptr};
865
0
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
866
0
            {
867
0
                if (iBand == nBand)
868
0
                {
869
0
                    ppDestBuffers[iBand - 1] = pImage;
870
0
                }
871
0
                else
872
0
                {
873
0
                    GDALRasterBlock *poBlock =
874
0
                        m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
875
0
                            nBlockXOff, nBlockYOff, true);
876
0
                    if (poBlock == nullptr)
877
0
                    {
878
0
                        bDoCopyWords = true;
879
0
                        break;
880
0
                    }
881
0
                    ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
882
0
                    apoLockedBlocks[iBand - 1] = poBlock;
883
0
                }
884
0
            }
885
0
            if (!bDoCopyWords)
886
0
            {
887
0
                GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
888
0
                                 m_poGDS->nBands, ppDestBuffers, eDataType,
889
0
                                 static_cast<size_t>(nBlockXSize) *
890
0
                                     nBlockYSize);
891
0
            }
892
0
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
893
0
            {
894
0
                if (apoLockedBlocks[iBand - 1])
895
0
                {
896
0
                    apoLockedBlocks[iBand - 1]->DropLock();
897
0
                }
898
0
            }
899
0
        }
900
901
0
        if (bDoCopyWords)
902
0
        {
903
0
            const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
904
0
            GByte *pabyImage =
905
0
                m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
906
907
0
            GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
908
0
                            pImage, eDataType, nWordBytes,
909
0
                            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
910
911
0
            eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
912
0
        }
913
0
    }
914
915
0
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
916
917
0
    return eErr;
918
0
}
919
920
/************************************************************************/
921
/*                         CacheMaskForBlock()                          */
922
/************************************************************************/
923
924
void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
925
926
0
{
927
    // Preload mask data if layout compatible and we have cached ranges
928
0
    if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
929
0
        VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
930
0
    {
931
0
        auto poBand = cpl::down_cast<GTiffRasterBand *>(
932
0
            m_poGDS->m_poMaskDS->GetRasterBand(1));
933
0
        if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
934
0
                poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
935
0
        {
936
0
            GDALRasterBlock *poBlock =
937
0
                poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
938
0
            if (poBlock)
939
0
                poBlock->DropLock();
940
0
        }
941
0
    }
942
0
}
943
944
/************************************************************************/
945
/*                       FillCacheForOtherBands()                       */
946
/************************************************************************/
947
948
CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
949
950
0
{
951
    /* -------------------------------------------------------------------- */
952
    /*      In the fairly common case of pixel interleaved 8bit data        */
953
    /*      that is multi-band, lets push the rest of the data into the     */
954
    /*      block cache too, to avoid (hopefully) having to redecode it.    */
955
    /*                                                                      */
956
    /*      Our following logic actually depends on the fact that the       */
957
    /*      this block is already loaded, so subsequent calls will end      */
958
    /*      up back in this method and pull from the loaded block.          */
959
    /*                                                                      */
960
    /*      Be careful not entering this portion of code from               */
961
    /*      the other bands, otherwise we'll get very deep nested calls     */
962
    /*      and O(nBands^2) performance !                                   */
963
    /*                                                                      */
964
    /*      If there are many bands and the block cache size is not big     */
965
    /*      enough to accommodate the size of all the blocks, don't enter   */
966
    /* -------------------------------------------------------------------- */
967
0
    CPLErr eErr = CE_None;
968
0
    if (m_poGDS->nBands != 1 &&
969
0
        m_poGDS->nBands <
970
0
            128 &&  // avoid caching for datasets with too many bands
971
0
        !m_poGDS->m_bLoadingOtherBands &&
972
0
        static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
973
0
                GDALGetDataTypeSizeBytes(eDataType) <
974
0
            GDALGetCacheMax64() / m_poGDS->nBands)
975
0
    {
976
0
        m_poGDS->m_bLoadingOtherBands = true;
977
978
0
        for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
979
0
        {
980
0
            if (iOtherBand == nBand)
981
0
                continue;
982
983
0
            GDALRasterBlock *poBlock =
984
0
                m_poGDS->GetRasterBand(iOtherBand)
985
0
                    ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
986
0
            if (poBlock == nullptr)
987
0
            {
988
0
                eErr = CE_Failure;
989
0
                break;
990
0
            }
991
0
            poBlock->DropLock();
992
0
        }
993
994
0
        m_poGDS->m_bLoadingOtherBands = false;
995
0
    }
996
997
0
    return eErr;
998
0
}
999
1000
/************************************************************************/
1001
/*                           GetDescription()                           */
1002
/************************************************************************/
1003
1004
const char *GTiffRasterBand::GetDescription() const
1005
0
{
1006
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1007
1008
0
    return m_osDescription;
1009
0
}
1010
1011
/************************************************************************/
1012
/*                             GetOffset()                              */
1013
/************************************************************************/
1014
1015
double GTiffRasterBand::GetOffset(int *pbSuccess)
1016
1017
0
{
1018
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1019
1020
0
    if (pbSuccess)
1021
0
        *pbSuccess = m_bHaveOffsetScale;
1022
0
    return m_dfOffset;
1023
0
}
1024
1025
/************************************************************************/
1026
/*                              GetScale()                              */
1027
/************************************************************************/
1028
1029
double GTiffRasterBand::GetScale(int *pbSuccess)
1030
1031
0
{
1032
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1033
1034
0
    if (pbSuccess)
1035
0
        *pbSuccess = m_bHaveOffsetScale;
1036
0
    return m_dfScale;
1037
0
}
1038
1039
/************************************************************************/
1040
/*                            GetUnitType()                             */
1041
/************************************************************************/
1042
1043
const char *GTiffRasterBand::GetUnitType()
1044
1045
0
{
1046
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1047
0
    if (m_osUnitType.empty())
1048
0
    {
1049
0
        m_poGDS->LookForProjection();
1050
0
        if (m_poGDS->m_pszVertUnit)
1051
0
            return m_poGDS->m_pszVertUnit;
1052
0
    }
1053
1054
0
    return m_osUnitType.c_str();
1055
0
}
1056
1057
/************************************************************************/
1058
/*                       GetMetadataDomainList()                        */
1059
/************************************************************************/
1060
1061
char **GTiffRasterBand::GetMetadataDomainList()
1062
0
{
1063
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1064
1065
0
    m_poGDS->LoadENVIHdrIfNeeded();
1066
1067
0
    return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
1068
0
}
1069
1070
/************************************************************************/
1071
/*                            GetMetadata()                             */
1072
/************************************************************************/
1073
1074
CSLConstList GTiffRasterBand::GetMetadata(const char *pszDomain)
1075
1076
0
{
1077
0
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1078
0
    {
1079
0
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1080
1081
0
        m_poGDS->LoadENVIHdrIfNeeded();
1082
0
    }
1083
0
    else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1084
0
    {
1085
0
        m_poGDS->LoadENVIHdrIfNeeded();
1086
0
    }
1087
1088
0
    return m_oGTiffMDMD.GetMetadata(pszDomain);
1089
0
}
1090
1091
/************************************************************************/
1092
/*                          GetMetadataItem()                           */
1093
/************************************************************************/
1094
1095
const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1096
                                             const char *pszDomain)
1097
1098
0
{
1099
0
    if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1100
0
    {
1101
0
        int nBlockXOff = 0;
1102
0
        int nBlockYOff = 0;
1103
1104
0
        if (EQUAL(pszName, "JPEGTABLES"))
1105
0
        {
1106
0
            uint32_t nJPEGTableSize = 0;
1107
0
            void *pJPEGTable = nullptr;
1108
0
            if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1109
0
                             &nJPEGTableSize, &pJPEGTable) != 1 ||
1110
0
                pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1111
0
            {
1112
0
                return nullptr;
1113
0
            }
1114
0
            char *const pszHex = CPLBinaryToHex(
1115
0
                nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1116
0
            const char *pszReturn = CPLSPrintf("%s", pszHex);
1117
0
            CPLFree(pszHex);
1118
1119
0
            return pszReturn;
1120
0
        }
1121
1122
0
        if (EQUAL(pszName, "IFD_OFFSET"))
1123
0
        {
1124
0
            return CPLSPrintf(CPL_FRMT_GUIB,
1125
0
                              static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1126
0
        }
1127
1128
0
        if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1129
0
            2)
1130
0
        {
1131
0
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1132
0
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1133
0
                return nullptr;
1134
1135
0
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1136
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1137
0
            {
1138
0
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1139
0
            }
1140
1141
0
            vsi_l_offset nOffset = 0;
1142
0
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
1143
0
                                           nullptr))
1144
0
            {
1145
0
                return nullptr;
1146
0
            }
1147
1148
0
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1149
0
        }
1150
1151
0
        if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1152
0
        {
1153
0
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1154
0
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1155
0
                return nullptr;
1156
1157
0
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1158
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1159
0
            {
1160
0
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1161
0
            }
1162
1163
0
            vsi_l_offset nByteCount = 0;
1164
0
            if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
1165
0
                                           nullptr))
1166
0
            {
1167
0
                return nullptr;
1168
0
            }
1169
1170
0
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1171
0
        }
1172
0
    }
1173
0
    else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1174
0
    {
1175
0
        if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1176
0
            return HasBlockCache() ? "1" : "0";
1177
0
    }
1178
0
    else if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1179
0
    {
1180
0
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1181
1182
0
        m_poGDS->LoadENVIHdrIfNeeded();
1183
0
    }
1184
0
    else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1185
0
    {
1186
0
        m_poGDS->LoadENVIHdrIfNeeded();
1187
0
    }
1188
1189
0
    const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1190
1191
0
    if (pszRet == nullptr && eDataType == GDT_UInt8 && pszName && pszDomain &&
1192
0
        EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
1193
0
    {
1194
        // to get a chance of emitting the warning about this legacy usage
1195
0
        pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1196
0
    }
1197
0
    return pszRet;
1198
0
}
1199
1200
/************************************************************************/
1201
/*                       GetColorInterpretation()                       */
1202
/************************************************************************/
1203
1204
GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1205
1206
0
{
1207
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1208
1209
0
    return m_eBandInterp;
1210
0
}
1211
1212
/************************************************************************/
1213
/*                           GetColorTable()                            */
1214
/************************************************************************/
1215
1216
GDALColorTable *GTiffRasterBand::GetColorTable()
1217
1218
0
{
1219
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1220
1221
0
    if (nBand == 1)
1222
0
        return m_poGDS->m_poColorTable.get();
1223
1224
0
    return nullptr;
1225
0
}
1226
1227
/************************************************************************/
1228
/*                           GetNoDataValue()                           */
1229
/************************************************************************/
1230
1231
double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1232
1233
0
{
1234
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1235
1236
0
    int bSuccess = FALSE;
1237
0
    double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1238
0
    if (bSuccess)
1239
0
    {
1240
0
        if (pbSuccess)
1241
0
            *pbSuccess = TRUE;
1242
1243
0
        return dfNoDataValue;
1244
0
    }
1245
1246
0
    if (m_bNoDataSet)
1247
0
    {
1248
0
        if (pbSuccess)
1249
0
            *pbSuccess = TRUE;
1250
1251
0
        return m_dfNoDataValue;
1252
0
    }
1253
1254
0
    if (m_poGDS->m_bNoDataSet)
1255
0
    {
1256
0
        if (pbSuccess)
1257
0
            *pbSuccess = TRUE;
1258
1259
0
        return m_poGDS->m_dfNoDataValue;
1260
0
    }
1261
1262
0
    if (m_bNoDataSetAsInt64)
1263
0
    {
1264
0
        if (pbSuccess)
1265
0
            *pbSuccess = TRUE;
1266
1267
0
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1268
0
    }
1269
1270
0
    if (m_poGDS->m_bNoDataSetAsInt64)
1271
0
    {
1272
0
        if (pbSuccess)
1273
0
            *pbSuccess = TRUE;
1274
1275
0
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
1276
0
    }
1277
1278
0
    if (m_bNoDataSetAsUInt64)
1279
0
    {
1280
0
        if (pbSuccess)
1281
0
            *pbSuccess = TRUE;
1282
1283
0
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1284
0
    }
1285
1286
0
    if (m_poGDS->m_bNoDataSetAsUInt64)
1287
0
    {
1288
0
        if (pbSuccess)
1289
0
            *pbSuccess = TRUE;
1290
1291
0
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
1292
0
    }
1293
1294
0
    if (pbSuccess)
1295
0
        *pbSuccess = FALSE;
1296
0
    return dfNoDataValue;
1297
0
}
1298
1299
/************************************************************************/
1300
/*                       GetNoDataValueAsInt64()                        */
1301
/************************************************************************/
1302
1303
int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1304
1305
0
{
1306
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1307
1308
0
    if (eDataType == GDT_UInt64)
1309
0
    {
1310
0
        CPLError(CE_Failure, CPLE_AppDefined,
1311
0
                 "GetNoDataValueAsUInt64() should be called instead");
1312
0
        if (pbSuccess)
1313
0
            *pbSuccess = FALSE;
1314
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1315
0
    }
1316
0
    if (eDataType != GDT_Int64)
1317
0
    {
1318
0
        CPLError(CE_Failure, CPLE_AppDefined,
1319
0
                 "GetNoDataValue() should be called instead");
1320
0
        if (pbSuccess)
1321
0
            *pbSuccess = FALSE;
1322
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1323
0
    }
1324
1325
0
    int bSuccess = FALSE;
1326
0
    const auto nNoDataValue =
1327
0
        GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1328
0
    if (bSuccess)
1329
0
    {
1330
0
        if (pbSuccess)
1331
0
            *pbSuccess = TRUE;
1332
1333
0
        return nNoDataValue;
1334
0
    }
1335
1336
0
    if (m_bNoDataSetAsInt64)
1337
0
    {
1338
0
        if (pbSuccess)
1339
0
            *pbSuccess = TRUE;
1340
1341
0
        return m_nNoDataValueInt64;
1342
0
    }
1343
1344
0
    if (m_poGDS->m_bNoDataSetAsInt64)
1345
0
    {
1346
0
        if (pbSuccess)
1347
0
            *pbSuccess = TRUE;
1348
1349
0
        return m_poGDS->m_nNoDataValueInt64;
1350
0
    }
1351
1352
0
    if (pbSuccess)
1353
0
        *pbSuccess = FALSE;
1354
0
    return nNoDataValue;
1355
0
}
1356
1357
/************************************************************************/
1358
/*                       GetNoDataValueAsUInt64()                       */
1359
/************************************************************************/
1360
1361
uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1362
1363
0
{
1364
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1365
1366
0
    if (eDataType == GDT_Int64)
1367
0
    {
1368
0
        CPLError(CE_Failure, CPLE_AppDefined,
1369
0
                 "GetNoDataValueAsInt64() should be called instead");
1370
0
        if (pbSuccess)
1371
0
            *pbSuccess = FALSE;
1372
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1373
0
    }
1374
0
    if (eDataType != GDT_UInt64)
1375
0
    {
1376
0
        CPLError(CE_Failure, CPLE_AppDefined,
1377
0
                 "GetNoDataValue() should be called instead");
1378
0
        if (pbSuccess)
1379
0
            *pbSuccess = FALSE;
1380
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1381
0
    }
1382
1383
0
    int bSuccess = FALSE;
1384
0
    const auto nNoDataValue =
1385
0
        GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1386
0
    if (bSuccess)
1387
0
    {
1388
0
        if (pbSuccess)
1389
0
            *pbSuccess = TRUE;
1390
1391
0
        return nNoDataValue;
1392
0
    }
1393
1394
0
    if (m_bNoDataSetAsUInt64)
1395
0
    {
1396
0
        if (pbSuccess)
1397
0
            *pbSuccess = TRUE;
1398
1399
0
        return m_nNoDataValueUInt64;
1400
0
    }
1401
1402
0
    if (m_poGDS->m_bNoDataSetAsUInt64)
1403
0
    {
1404
0
        if (pbSuccess)
1405
0
            *pbSuccess = TRUE;
1406
1407
0
        return m_poGDS->m_nNoDataValueUInt64;
1408
0
    }
1409
1410
0
    if (pbSuccess)
1411
0
        *pbSuccess = FALSE;
1412
0
    return nNoDataValue;
1413
0
}
1414
1415
/************************************************************************/
1416
/*                          GetOverviewCount()                          */
1417
/************************************************************************/
1418
1419
int GTiffRasterBand::GetOverviewCount()
1420
1421
0
{
1422
0
    if (!m_poGDS->AreOverviewsEnabled())
1423
0
        return 0;
1424
1425
0
    m_poGDS->ScanDirectories();
1426
1427
0
    if (!m_poGDS->m_apoOverviewDS.empty())
1428
0
    {
1429
0
        return static_cast<int>(m_poGDS->m_apoOverviewDS.size());
1430
0
    }
1431
1432
0
    const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1433
0
    if (nOverviewCount > 0)
1434
0
        return nOverviewCount;
1435
1436
    // Implicit JPEG overviews are normally hidden, except when doing
1437
    // IRasterIO() operations.
1438
0
    if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1439
0
        return m_poGDS->GetJPEGOverviewCount();
1440
1441
0
    return 0;
1442
0
}
1443
1444
/************************************************************************/
1445
/*                            GetOverview()                             */
1446
/************************************************************************/
1447
1448
GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1449
1450
0
{
1451
0
    m_poGDS->ScanDirectories();
1452
1453
0
    if (!m_poGDS->m_apoOverviewDS.empty())
1454
0
    {
1455
        // Do we have internal overviews?
1456
0
        if (i < 0 || static_cast<size_t>(i) >= m_poGDS->m_apoOverviewDS.size())
1457
0
            return nullptr;
1458
1459
0
        return m_poGDS->m_apoOverviewDS[i]->GetRasterBand(nBand);
1460
0
    }
1461
1462
0
    GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1463
0
    if (poOvrBand != nullptr)
1464
0
        return poOvrBand;
1465
1466
    // For consistency with GetOverviewCount(), we should also test
1467
    // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1468
    // to query them for testing purposes.
1469
0
    if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1470
0
        return m_poGDS->m_apoJPEGOverviewDS[i]->GetRasterBand(nBand);
1471
1472
0
    return nullptr;
1473
0
}
1474
1475
/************************************************************************/
1476
/*                            GetMaskFlags()                            */
1477
/************************************************************************/
1478
1479
int GTiffRasterBand::GetMaskFlags()
1480
0
{
1481
0
    m_poGDS->ScanDirectories();
1482
1483
0
    if (m_poGDS->m_poExternalMaskDS != nullptr)
1484
0
    {
1485
0
        return GMF_PER_DATASET;
1486
0
    }
1487
1488
0
    if (m_poGDS->m_poMaskDS != nullptr)
1489
0
    {
1490
0
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1491
0
        {
1492
0
            return GMF_PER_DATASET;
1493
0
        }
1494
1495
0
        return 0;
1496
0
    }
1497
1498
0
    if (m_poGDS->m_bIsOverview)
1499
0
    {
1500
0
        return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
1501
0
    }
1502
1503
0
    return GDALPamRasterBand::GetMaskFlags();
1504
0
}
1505
1506
/************************************************************************/
1507
/*                            GetMaskBand()                             */
1508
/************************************************************************/
1509
1510
GDALRasterBand *GTiffRasterBand::GetMaskBand()
1511
0
{
1512
0
    m_poGDS->ScanDirectories();
1513
1514
0
    if (m_poGDS->m_poExternalMaskDS != nullptr)
1515
0
    {
1516
0
        return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1517
0
    }
1518
1519
0
    if (m_poGDS->m_poMaskDS != nullptr)
1520
0
    {
1521
0
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1522
0
            return m_poGDS->m_poMaskDS->GetRasterBand(1);
1523
1524
0
        return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1525
0
    }
1526
1527
0
    if (m_poGDS->m_bIsOverview)
1528
0
    {
1529
0
        GDALRasterBand *poBaseMask =
1530
0
            m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1531
0
        if (poBaseMask)
1532
0
        {
1533
0
            const int nOverviews = poBaseMask->GetOverviewCount();
1534
0
            for (int i = 0; i < nOverviews; i++)
1535
0
            {
1536
0
                GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1537
0
                if (poOvr && poOvr->GetXSize() == GetXSize() &&
1538
0
                    poOvr->GetYSize() == GetYSize())
1539
0
                {
1540
0
                    return poOvr;
1541
0
                }
1542
0
            }
1543
0
        }
1544
0
    }
1545
1546
0
    return GDALPamRasterBand::GetMaskBand();
1547
0
}
1548
1549
/************************************************************************/
1550
/*                             IsMaskBand()                             */
1551
/************************************************************************/
1552
1553
bool GTiffRasterBand::IsMaskBand() const
1554
0
{
1555
0
    return (m_poGDS->m_poImageryDS != nullptr &&
1556
0
            m_poGDS->m_poImageryDS->m_poMaskDS.get() == m_poGDS) ||
1557
0
           m_eBandInterp == GCI_AlphaBand ||
1558
0
           m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1559
0
}
1560
1561
/************************************************************************/
1562
/*                         GetMaskValueRange()                          */
1563
/************************************************************************/
1564
1565
GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1566
0
{
1567
0
    if (!IsMaskBand())
1568
0
        return GMVR_UNKNOWN;
1569
0
    if (m_poGDS->m_nBitsPerSample == 1)
1570
0
        return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1571
0
                                          : GMVR_0_AND_1_ONLY;
1572
0
    return GMVR_UNKNOWN;
1573
0
}