Coverage Report

Created: 2025-11-16 06:25

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_Byte || 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
                                                  char **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(GDALRWFlag eRWFlag,
414
                                                          int *pnPixelSpace,
415
                                                          GIntBig *pnLineSpace,
416
                                                          char **papszOptions)
417
0
{
418
0
    int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
419
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
420
0
        nLineSize *= m_poGDS->nBands;
421
422
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
423
0
    {
424
        // In case of a pixel interleaved file, we save virtual memory space
425
        // by reusing a base mapping that embraces the whole imagery.
426
0
        if (m_poGDS->m_pBaseMapping != nullptr)
427
0
        {
428
            // Offset between the base mapping and the requested mapping.
429
0
            vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
430
0
                                   GDALGetDataTypeSizeBytes(eDataType);
431
432
0
            GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
433
0
                CPLCalloc(1, sizeof(GTiffRasterBand *)));
434
0
            *ppoSelf = this;
435
436
0
            CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
437
0
                m_poGDS->m_pBaseMapping, nOffset,
438
0
                CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
439
0
                GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
440
0
            if (pVMem == nullptr)
441
0
            {
442
0
                CPLFree(ppoSelf);
443
0
                return nullptr;
444
0
            }
445
446
            // Mechanism used so that the memory mapping object can be
447
            // destroyed after the raster band.
448
0
            m_aSetPSelf.insert(ppoSelf);
449
0
            ++m_poGDS->m_nRefBaseMapping;
450
0
            *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
451
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
452
0
                *pnPixelSpace *= m_poGDS->nBands;
453
0
            *pnLineSpace = nLineSize;
454
0
            return pVMem;
455
0
        }
456
0
    }
457
458
0
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
459
460
0
    vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
461
462
0
    if (!(CPLIsVirtualMemFileMapAvailable() &&
463
0
          VSIFGetNativeFileDescriptorL(fp) != nullptr &&
464
#if SIZEOF_VOIDP == 4
465
          nLength == static_cast<size_t>(nLength) &&
466
#endif
467
0
          m_poGDS->m_nCompression == COMPRESSION_NONE &&
468
0
          (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
469
0
           m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
470
0
           m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
471
0
          m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
472
0
          !TIFFIsTiled(m_poGDS->m_hTIFF) &&
473
0
          !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
474
0
    {
475
0
        return nullptr;
476
0
    }
477
478
    // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
479
0
    if (m_poGDS->GetAccess() == GA_Update)
480
0
    {
481
0
        m_poGDS->FlushCache(false);
482
0
        VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
483
0
    }
484
485
    // Get strip offsets.
486
0
    toff_t *panTIFFOffsets = nullptr;
487
0
    if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
488
0
                      &panTIFFOffsets) ||
489
0
        panTIFFOffsets == nullptr)
490
0
    {
491
0
        return nullptr;
492
0
    }
493
494
0
    GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
495
0
                            GDALGetDataTypeSizeBytes(eDataType);
496
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
497
0
        nBlockSize *= m_poGDS->nBands;
498
499
0
    int nBlocks = m_poGDS->m_nBlocksPerBand;
500
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
501
0
        nBlocks *= m_poGDS->nBands;
502
0
    int i = 0;  // Used after for.
503
0
    for (; i < nBlocks; ++i)
504
0
    {
505
0
        if (panTIFFOffsets[i] != 0)
506
0
            break;
507
0
    }
508
0
    if (i == nBlocks)
509
0
    {
510
        // All zeroes.
511
0
        if (m_poGDS->eAccess == GA_Update)
512
0
        {
513
            // Initialize the file with empty blocks so that the file has
514
            // the appropriate size.
515
516
0
            toff_t *panByteCounts = nullptr;
517
0
            if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
518
0
                              &panByteCounts) ||
519
0
                panByteCounts == nullptr)
520
0
            {
521
0
                return nullptr;
522
0
            }
523
0
            if (VSIFSeekL(fp, 0, SEEK_END) != 0)
524
0
                return nullptr;
525
0
            vsi_l_offset nBaseOffset = VSIFTellL(fp);
526
527
            // Just write one tile with libtiff to put it in appropriate state.
528
0
            GByte *pabyData =
529
0
                static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
530
0
            if (pabyData == nullptr)
531
0
            {
532
0
                return nullptr;
533
0
            }
534
0
            const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
535
0
                                                   pabyData, nBlockSize);
536
0
            VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
537
0
            VSIFree(pabyData);
538
0
            if (ret != nBlockSize)
539
0
            {
540
0
                return nullptr;
541
0
            }
542
0
            CPLAssert(panTIFFOffsets[0] == nBaseOffset);
543
0
            CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
544
545
            // Now simulate the writing of other blocks.
546
0
            assert(nBlocks > 0);
547
0
            assert(static_cast<vsi_l_offset>(nBlockSize) <
548
0
                   std::numeric_limits<vsi_l_offset>::max() / nBlocks);
549
0
            const vsi_l_offset nDataSize =
550
0
                static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
551
0
            if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
552
0
                return nullptr;
553
554
0
            for (i = 1; i < nBlocks; ++i)
555
0
            {
556
0
                panTIFFOffsets[i] =
557
0
                    nBaseOffset + i * static_cast<toff_t>(nBlockSize);
558
0
                panByteCounts[i] = nBlockSize;
559
0
            }
560
0
        }
561
0
        else
562
0
        {
563
0
            CPLDebug("GTiff", "Sparse files not supported in file mapping");
564
0
            return nullptr;
565
0
        }
566
0
    }
567
568
0
    GIntBig nBlockSpacing = 0;
569
0
    bool bCompatibleSpacing = true;
570
0
    toff_t nPrevOffset = 0;
571
0
    for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
572
0
    {
573
0
        toff_t nCurOffset = 0;
574
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
575
0
            nCurOffset =
576
0
                panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
577
0
        else
578
0
            nCurOffset = panTIFFOffsets[i];
579
0
        if (nCurOffset == 0)
580
0
        {
581
0
            bCompatibleSpacing = false;
582
0
            break;
583
0
        }
584
0
        if (i > 0)
585
0
        {
586
0
            const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
587
0
            if (i == 1)
588
0
            {
589
0
                if (nCurSpacing !=
590
0
                    static_cast<GIntBig>(nBlockYSize) * nLineSize)
591
0
                {
592
0
                    bCompatibleSpacing = false;
593
0
                    break;
594
0
                }
595
0
                nBlockSpacing = nCurSpacing;
596
0
            }
597
0
            else if (nBlockSpacing != nCurSpacing)
598
0
            {
599
0
                bCompatibleSpacing = false;
600
0
                break;
601
0
            }
602
0
        }
603
0
        nPrevOffset = nCurOffset;
604
0
    }
605
606
0
    if (!bCompatibleSpacing)
607
0
    {
608
0
        return nullptr;
609
0
    }
610
611
0
    vsi_l_offset nOffset = 0;
612
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
613
0
    {
614
0
        CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
615
0
        nOffset = panTIFFOffsets[0];
616
0
    }
617
0
    else
618
0
    {
619
0
        nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
620
0
    }
621
0
    CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
622
0
        fp, nOffset, nLength,
623
0
        eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
624
0
        nullptr, nullptr);
625
0
    if (pVMem == nullptr)
626
0
    {
627
0
        return nullptr;
628
0
    }
629
630
0
    if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
631
0
    {
632
        // TODO(schwehr): Revisit this block.
633
0
        m_poGDS->m_pBaseMapping = pVMem;
634
0
        pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
635
0
                                          papszOptions);
636
        // Drop ref on base mapping.
637
0
        CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
638
0
        if (pVMem == nullptr)
639
0
            m_poGDS->m_pBaseMapping = nullptr;
640
0
    }
641
0
    else
642
0
    {
643
0
        *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
644
0
        if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
645
0
            *pnPixelSpace *= m_poGDS->nBands;
646
0
        *pnLineSpace = nLineSize;
647
0
    }
648
0
    return pVMem;
649
0
}
650
651
/************************************************************************/
652
/*                       IGetDataCoverageStatus()                       */
653
/************************************************************************/
654
655
int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
656
                                            int nYSize, int nMaskFlagStop,
657
                                            double *pdfDataPct)
658
0
{
659
0
    if (eAccess == GA_Update)
660
0
        m_poGDS->FlushCache(false);
661
662
0
    const int iXBlockStart = nXOff / nBlockXSize;
663
0
    const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
664
0
    const int iYBlockStart = nYOff / nBlockYSize;
665
0
    const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
666
0
    int nStatus = 0;
667
0
    VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
668
0
    GIntBig nPixelsData = 0;
669
0
    for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
670
0
    {
671
0
        for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
672
0
        {
673
0
            const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
674
0
            int nBlockId = nBlockIdBand0;
675
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
676
0
                nBlockId =
677
0
                    nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
678
0
            vsi_l_offset nOffset = 0;
679
0
            vsi_l_offset nLength = 0;
680
0
            bool bHasData = false;
681
0
            bool bError = false;
682
0
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength,
683
0
                                           &bError))
684
0
            {
685
0
                if (bError)
686
0
                    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED;
687
0
                nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
688
0
            }
689
0
            else
690
0
            {
691
0
                if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
692
0
                    m_poGDS->eAccess == GA_ReadOnly &&
693
0
                    ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
694
0
                      !m_bNoDataSetAsUInt64) ||
695
0
                     (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
696
0
                     (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
697
0
                     (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
698
0
                {
699
0
                    VSIRangeStatus eStatus =
700
0
                        VSIFGetRangeStatusL(fp, nOffset, nLength);
701
0
                    if (eStatus == VSI_RANGE_STATUS_HOLE)
702
0
                    {
703
0
                        nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
704
0
                    }
705
0
                    else
706
0
                    {
707
0
                        bHasData = true;
708
0
                    }
709
0
                }
710
0
                else
711
0
                {
712
0
                    bHasData = true;
713
0
                }
714
0
            }
715
0
            if (bHasData)
716
0
            {
717
0
                const int nXBlockRight =
718
0
                    (iX * nBlockXSize > INT_MAX - nBlockXSize)
719
0
                        ? INT_MAX
720
0
                        : (iX + 1) * nBlockXSize;
721
0
                const int nYBlockBottom =
722
0
                    (iY * nBlockYSize > INT_MAX - nBlockYSize)
723
0
                        ? INT_MAX
724
0
                        : (iY + 1) * nBlockYSize;
725
726
0
                nPixelsData += (static_cast<GIntBig>(
727
0
                                    std::min(nXBlockRight, nXOff + nXSize)) -
728
0
                                std::max(iX * nBlockXSize, nXOff)) *
729
0
                               (std::min(nYBlockBottom, nYOff + nYSize) -
730
0
                                std::max(iY * nBlockYSize, nYOff));
731
0
                nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
732
0
            }
733
0
            if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
734
0
            {
735
0
                if (pdfDataPct)
736
0
                    *pdfDataPct = -1.0;
737
0
                return nStatus;
738
0
            }
739
0
        }
740
0
    }
741
0
    if (pdfDataPct)
742
0
        *pdfDataPct =
743
0
            100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
744
0
    return nStatus;
745
0
}
746
747
/************************************************************************/
748
/*                             IReadBlock()                             */
749
/************************************************************************/
750
751
CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
752
753
0
{
754
0
    m_poGDS->Crystalize();
755
756
0
    GPtrDiff_t nBlockBufSize = 0;
757
0
    if (TIFFIsTiled(m_poGDS->m_hTIFF))
758
0
    {
759
0
        nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
760
0
    }
761
0
    else
762
0
    {
763
0
        CPLAssert(nBlockXOff == 0);
764
0
        nBlockBufSize =
765
0
            static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
766
0
    }
767
768
0
    const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
769
770
    /* -------------------------------------------------------------------- */
771
    /*      The bottom most partial tiles and strips are sometimes only     */
772
    /*      partially encoded.  This code reduces the requested data so     */
773
    /*      an error won't be reported in this case. (#1179)                */
774
    /* -------------------------------------------------------------------- */
775
0
    auto nBlockReqSize = nBlockBufSize;
776
777
0
    if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
778
0
    {
779
0
        nBlockReqSize =
780
0
            (nBlockBufSize / nBlockYSize) *
781
0
            (nBlockYSize -
782
0
             static_cast<int>(
783
0
                 (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
784
0
                 nRasterYSize));
785
0
    }
786
787
    /* -------------------------------------------------------------------- */
788
    /*      Handle the case of a strip or tile that doesn't exist yet.      */
789
    /*      Just set to zeros and return.                                   */
790
    /* -------------------------------------------------------------------- */
791
0
    vsi_l_offset nOffset = 0;
792
0
    bool bErrOccurred = false;
793
0
    if (nBlockId != m_poGDS->m_nLoadedBlock &&
794
0
        !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
795
0
    {
796
0
        NullBlock(pImage);
797
0
        if (bErrOccurred)
798
0
            return CE_Failure;
799
0
        return CE_None;
800
0
    }
801
802
0
    if (m_poGDS->m_bStreamingIn &&
803
0
        !(m_poGDS->nBands > 1 &&
804
0
          m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
805
0
          nBlockId == m_poGDS->m_nLoadedBlock))
806
0
    {
807
0
        if (nOffset < VSIFTellL(m_poGDS->m_fpL))
808
0
        {
809
0
            ReportError(CE_Failure, CPLE_NotSupported,
810
0
                        "Trying to load block %d at offset " CPL_FRMT_GUIB
811
0
                        " whereas current pos is " CPL_FRMT_GUIB
812
0
                        " (backward read not supported)",
813
0
                        nBlockId, static_cast<GUIntBig>(nOffset),
814
0
                        static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
815
0
            return CE_Failure;
816
0
        }
817
0
    }
818
819
    /* -------------------------------------------------------------------- */
820
    /*      Handle simple case (separate, onesampleperpixel)                */
821
    /* -------------------------------------------------------------------- */
822
0
    CPLErr eErr = CE_None;
823
0
    if (m_poGDS->nBands == 1 ||
824
0
        m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
825
0
    {
826
0
        if (nBlockReqSize < nBlockBufSize)
827
0
            memset(pImage, 0, nBlockBufSize);
828
829
0
        if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
830
0
        {
831
0
            memset(pImage, 0, nBlockBufSize);
832
0
            return CE_Failure;
833
0
        }
834
0
    }
835
0
    else
836
0
    {
837
        /* --------------------------------------------------------------------
838
         */
839
        /*      Load desired block */
840
        /* --------------------------------------------------------------------
841
         */
842
0
        eErr = m_poGDS->LoadBlockBuf(nBlockId);
843
0
        if (eErr != CE_None)
844
0
        {
845
0
            memset(pImage, 0,
846
0
                   static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
847
0
                       GDALGetDataTypeSizeBytes(eDataType));
848
0
            return eErr;
849
0
        }
850
851
0
        bool bDoCopyWords = true;
852
0
        if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
853
0
            eAccess == GA_ReadOnly &&
854
0
            (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
855
0
            ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
856
0
             (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
857
0
             (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
858
0
            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
859
0
                    GDALGetDataTypeSizeBytes(eDataType) <
860
0
                GDALGetCacheMax64() / m_poGDS->nBands)
861
0
        {
862
0
            bDoCopyWords = false;
863
0
            void *ppDestBuffers[4];
864
0
            GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
865
0
                                                   nullptr};
866
0
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
867
0
            {
868
0
                if (iBand == nBand)
869
0
                {
870
0
                    ppDestBuffers[iBand - 1] = pImage;
871
0
                }
872
0
                else
873
0
                {
874
0
                    GDALRasterBlock *poBlock =
875
0
                        m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
876
0
                            nBlockXOff, nBlockYOff, true);
877
0
                    if (poBlock == nullptr)
878
0
                    {
879
0
                        bDoCopyWords = true;
880
0
                        break;
881
0
                    }
882
0
                    ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
883
0
                    apoLockedBlocks[iBand - 1] = poBlock;
884
0
                }
885
0
            }
886
0
            if (!bDoCopyWords)
887
0
            {
888
0
                GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
889
0
                                 m_poGDS->nBands, ppDestBuffers, eDataType,
890
0
                                 static_cast<size_t>(nBlockXSize) *
891
0
                                     nBlockYSize);
892
0
            }
893
0
            for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
894
0
            {
895
0
                if (apoLockedBlocks[iBand - 1])
896
0
                {
897
0
                    apoLockedBlocks[iBand - 1]->DropLock();
898
0
                }
899
0
            }
900
0
        }
901
902
0
        if (bDoCopyWords)
903
0
        {
904
0
            const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
905
0
            GByte *pabyImage =
906
0
                m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
907
908
0
            GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
909
0
                            pImage, eDataType, nWordBytes,
910
0
                            static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
911
912
0
            eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
913
0
        }
914
0
    }
915
916
0
    CacheMaskForBlock(nBlockXOff, nBlockYOff);
917
918
0
    return eErr;
919
0
}
920
921
/************************************************************************/
922
/*                           CacheMaskForBlock()                       */
923
/************************************************************************/
924
925
void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
926
927
0
{
928
    // Preload mask data if layout compatible and we have cached ranges
929
0
    if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
930
0
        VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
931
0
    {
932
0
        auto poBand = cpl::down_cast<GTiffRasterBand *>(
933
0
            m_poGDS->m_poMaskDS->GetRasterBand(1));
934
0
        if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
935
0
                poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
936
0
        {
937
0
            GDALRasterBlock *poBlock =
938
0
                poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
939
0
            if (poBlock)
940
0
                poBlock->DropLock();
941
0
        }
942
0
    }
943
0
}
944
945
/************************************************************************/
946
/*                       FillCacheForOtherBands()                       */
947
/************************************************************************/
948
949
CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
950
951
0
{
952
    /* -------------------------------------------------------------------- */
953
    /*      In the fairly common case of pixel interleaved 8bit data        */
954
    /*      that is multi-band, lets push the rest of the data into the     */
955
    /*      block cache too, to avoid (hopefully) having to redecode it.    */
956
    /*                                                                      */
957
    /*      Our following logic actually depends on the fact that the       */
958
    /*      this block is already loaded, so subsequent calls will end      */
959
    /*      up back in this method and pull from the loaded block.          */
960
    /*                                                                      */
961
    /*      Be careful not entering this portion of code from               */
962
    /*      the other bands, otherwise we'll get very deep nested calls     */
963
    /*      and O(nBands^2) performance !                                   */
964
    /*                                                                      */
965
    /*      If there are many bands and the block cache size is not big     */
966
    /*      enough to accommodate the size of all the blocks, don't enter   */
967
    /* -------------------------------------------------------------------- */
968
0
    CPLErr eErr = CE_None;
969
0
    if (m_poGDS->nBands != 1 &&
970
0
        m_poGDS->nBands <
971
0
            128 &&  // avoid caching for datasets with too many bands
972
0
        !m_poGDS->m_bLoadingOtherBands &&
973
0
        static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
974
0
                GDALGetDataTypeSizeBytes(eDataType) <
975
0
            GDALGetCacheMax64() / m_poGDS->nBands)
976
0
    {
977
0
        m_poGDS->m_bLoadingOtherBands = true;
978
979
0
        for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
980
0
        {
981
0
            if (iOtherBand == nBand)
982
0
                continue;
983
984
0
            GDALRasterBlock *poBlock =
985
0
                m_poGDS->GetRasterBand(iOtherBand)
986
0
                    ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
987
0
            if (poBlock == nullptr)
988
0
            {
989
0
                eErr = CE_Failure;
990
0
                break;
991
0
            }
992
0
            poBlock->DropLock();
993
0
        }
994
995
0
        m_poGDS->m_bLoadingOtherBands = false;
996
0
    }
997
998
0
    return eErr;
999
0
}
1000
1001
/************************************************************************/
1002
/*                           GetDescription()                           */
1003
/************************************************************************/
1004
1005
const char *GTiffRasterBand::GetDescription() const
1006
0
{
1007
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1008
1009
0
    return m_osDescription;
1010
0
}
1011
1012
/************************************************************************/
1013
/*                             GetOffset()                              */
1014
/************************************************************************/
1015
1016
double GTiffRasterBand::GetOffset(int *pbSuccess)
1017
1018
0
{
1019
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1020
1021
0
    if (pbSuccess)
1022
0
        *pbSuccess = m_bHaveOffsetScale;
1023
0
    return m_dfOffset;
1024
0
}
1025
1026
/************************************************************************/
1027
/*                              GetScale()                              */
1028
/************************************************************************/
1029
1030
double GTiffRasterBand::GetScale(int *pbSuccess)
1031
1032
0
{
1033
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1034
1035
0
    if (pbSuccess)
1036
0
        *pbSuccess = m_bHaveOffsetScale;
1037
0
    return m_dfScale;
1038
0
}
1039
1040
/************************************************************************/
1041
/*                            GetUnitType()                             */
1042
/************************************************************************/
1043
1044
const char *GTiffRasterBand::GetUnitType()
1045
1046
0
{
1047
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1048
0
    if (m_osUnitType.empty())
1049
0
    {
1050
0
        m_poGDS->LookForProjection();
1051
0
        if (m_poGDS->m_pszVertUnit)
1052
0
            return m_poGDS->m_pszVertUnit;
1053
0
    }
1054
1055
0
    return m_osUnitType.c_str();
1056
0
}
1057
1058
/************************************************************************/
1059
/*                      GetMetadataDomainList()                         */
1060
/************************************************************************/
1061
1062
char **GTiffRasterBand::GetMetadataDomainList()
1063
0
{
1064
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1065
1066
0
    m_poGDS->LoadENVIHdrIfNeeded();
1067
1068
0
    return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
1069
0
}
1070
1071
/************************************************************************/
1072
/*                            GetMetadata()                             */
1073
/************************************************************************/
1074
1075
char **GTiffRasterBand::GetMetadata(const char *pszDomain)
1076
1077
0
{
1078
0
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1079
0
    {
1080
0
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1081
1082
0
        m_poGDS->LoadENVIHdrIfNeeded();
1083
0
    }
1084
0
    else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1085
0
    {
1086
0
        m_poGDS->LoadENVIHdrIfNeeded();
1087
0
    }
1088
1089
0
    return m_oGTiffMDMD.GetMetadata(pszDomain);
1090
0
}
1091
1092
/************************************************************************/
1093
/*                          GetMetadataItem()                           */
1094
/************************************************************************/
1095
1096
const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
1097
                                             const char *pszDomain)
1098
1099
0
{
1100
0
    if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
1101
0
    {
1102
0
        m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1103
1104
0
        m_poGDS->LoadENVIHdrIfNeeded();
1105
0
    }
1106
0
    else if (EQUAL(pszDomain, MD_DOMAIN_IMAGERY))
1107
0
    {
1108
0
        m_poGDS->LoadENVIHdrIfNeeded();
1109
0
    }
1110
1111
0
    if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
1112
0
    {
1113
0
        int nBlockXOff = 0;
1114
0
        int nBlockYOff = 0;
1115
1116
0
        if (EQUAL(pszName, "JPEGTABLES"))
1117
0
        {
1118
0
            uint32_t nJPEGTableSize = 0;
1119
0
            void *pJPEGTable = nullptr;
1120
0
            if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
1121
0
                             &nJPEGTableSize, &pJPEGTable) != 1 ||
1122
0
                pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
1123
0
            {
1124
0
                return nullptr;
1125
0
            }
1126
0
            char *const pszHex = CPLBinaryToHex(
1127
0
                nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
1128
0
            const char *pszReturn = CPLSPrintf("%s", pszHex);
1129
0
            CPLFree(pszHex);
1130
1131
0
            return pszReturn;
1132
0
        }
1133
1134
0
        if (EQUAL(pszName, "IFD_OFFSET"))
1135
0
        {
1136
0
            return CPLSPrintf(CPL_FRMT_GUIB,
1137
0
                              static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
1138
0
        }
1139
1140
0
        if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
1141
0
            2)
1142
0
        {
1143
0
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1144
0
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1145
0
                return nullptr;
1146
1147
0
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1148
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1149
0
            {
1150
0
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1151
0
            }
1152
1153
0
            vsi_l_offset nOffset = 0;
1154
0
            if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr,
1155
0
                                           nullptr))
1156
0
            {
1157
0
                return nullptr;
1158
0
            }
1159
1160
0
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
1161
0
        }
1162
1163
0
        if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
1164
0
        {
1165
0
            if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
1166
0
                nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
1167
0
                return nullptr;
1168
1169
0
            int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
1170
0
            if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
1171
0
            {
1172
0
                nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
1173
0
            }
1174
1175
0
            vsi_l_offset nByteCount = 0;
1176
0
            if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount,
1177
0
                                           nullptr))
1178
0
            {
1179
0
                return nullptr;
1180
0
            }
1181
1182
0
            return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
1183
0
        }
1184
0
    }
1185
0
    else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
1186
0
    {
1187
0
        if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
1188
0
            return HasBlockCache() ? "1" : "0";
1189
0
    }
1190
1191
0
    const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
1192
1193
0
    if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
1194
0
        EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
1195
0
    {
1196
        // to get a chance of emitting the warning about this legacy usage
1197
0
        pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
1198
0
    }
1199
0
    return pszRet;
1200
0
}
1201
1202
/************************************************************************/
1203
/*                       GetColorInterpretation()                       */
1204
/************************************************************************/
1205
1206
GDALColorInterp GTiffRasterBand::GetColorInterpretation()
1207
1208
0
{
1209
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1210
1211
0
    return m_eBandInterp;
1212
0
}
1213
1214
/************************************************************************/
1215
/*                           GetColorTable()                            */
1216
/************************************************************************/
1217
1218
GDALColorTable *GTiffRasterBand::GetColorTable()
1219
1220
0
{
1221
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1222
1223
0
    if (nBand == 1)
1224
0
        return m_poGDS->m_poColorTable.get();
1225
1226
0
    return nullptr;
1227
0
}
1228
1229
/************************************************************************/
1230
/*                           GetNoDataValue()                           */
1231
/************************************************************************/
1232
1233
double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
1234
1235
0
{
1236
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1237
1238
0
    int bSuccess = FALSE;
1239
0
    double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
1240
0
    if (bSuccess)
1241
0
    {
1242
0
        if (pbSuccess)
1243
0
            *pbSuccess = TRUE;
1244
1245
0
        return dfNoDataValue;
1246
0
    }
1247
1248
0
    if (m_bNoDataSet)
1249
0
    {
1250
0
        if (pbSuccess)
1251
0
            *pbSuccess = TRUE;
1252
1253
0
        return m_dfNoDataValue;
1254
0
    }
1255
1256
0
    if (m_poGDS->m_bNoDataSet)
1257
0
    {
1258
0
        if (pbSuccess)
1259
0
            *pbSuccess = TRUE;
1260
1261
0
        return m_poGDS->m_dfNoDataValue;
1262
0
    }
1263
1264
0
    if (m_bNoDataSetAsInt64)
1265
0
    {
1266
0
        if (pbSuccess)
1267
0
            *pbSuccess = TRUE;
1268
1269
0
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
1270
0
    }
1271
1272
0
    if (m_poGDS->m_bNoDataSetAsInt64)
1273
0
    {
1274
0
        if (pbSuccess)
1275
0
            *pbSuccess = TRUE;
1276
1277
0
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
1278
0
    }
1279
1280
0
    if (m_bNoDataSetAsUInt64)
1281
0
    {
1282
0
        if (pbSuccess)
1283
0
            *pbSuccess = TRUE;
1284
1285
0
        return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
1286
0
    }
1287
1288
0
    if (m_poGDS->m_bNoDataSetAsUInt64)
1289
0
    {
1290
0
        if (pbSuccess)
1291
0
            *pbSuccess = TRUE;
1292
1293
0
        return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
1294
0
    }
1295
1296
0
    if (pbSuccess)
1297
0
        *pbSuccess = FALSE;
1298
0
    return dfNoDataValue;
1299
0
}
1300
1301
/************************************************************************/
1302
/*                       GetNoDataValueAsInt64()                        */
1303
/************************************************************************/
1304
1305
int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
1306
1307
0
{
1308
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1309
1310
0
    if (eDataType == GDT_UInt64)
1311
0
    {
1312
0
        CPLError(CE_Failure, CPLE_AppDefined,
1313
0
                 "GetNoDataValueAsUInt64() should be called instead");
1314
0
        if (pbSuccess)
1315
0
            *pbSuccess = FALSE;
1316
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1317
0
    }
1318
0
    if (eDataType != GDT_Int64)
1319
0
    {
1320
0
        CPLError(CE_Failure, CPLE_AppDefined,
1321
0
                 "GetNoDataValue() should be called instead");
1322
0
        if (pbSuccess)
1323
0
            *pbSuccess = FALSE;
1324
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
1325
0
    }
1326
1327
0
    int bSuccess = FALSE;
1328
0
    const auto nNoDataValue =
1329
0
        GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
1330
0
    if (bSuccess)
1331
0
    {
1332
0
        if (pbSuccess)
1333
0
            *pbSuccess = TRUE;
1334
1335
0
        return nNoDataValue;
1336
0
    }
1337
1338
0
    if (m_bNoDataSetAsInt64)
1339
0
    {
1340
0
        if (pbSuccess)
1341
0
            *pbSuccess = TRUE;
1342
1343
0
        return m_nNoDataValueInt64;
1344
0
    }
1345
1346
0
    if (m_poGDS->m_bNoDataSetAsInt64)
1347
0
    {
1348
0
        if (pbSuccess)
1349
0
            *pbSuccess = TRUE;
1350
1351
0
        return m_poGDS->m_nNoDataValueInt64;
1352
0
    }
1353
1354
0
    if (pbSuccess)
1355
0
        *pbSuccess = FALSE;
1356
0
    return nNoDataValue;
1357
0
}
1358
1359
/************************************************************************/
1360
/*                      GetNoDataValueAsUInt64()                        */
1361
/************************************************************************/
1362
1363
uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
1364
1365
0
{
1366
0
    m_poGDS->LoadGeoreferencingAndPamIfNeeded();
1367
1368
0
    if (eDataType == GDT_Int64)
1369
0
    {
1370
0
        CPLError(CE_Failure, CPLE_AppDefined,
1371
0
                 "GetNoDataValueAsInt64() should be called instead");
1372
0
        if (pbSuccess)
1373
0
            *pbSuccess = FALSE;
1374
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1375
0
    }
1376
0
    if (eDataType != GDT_UInt64)
1377
0
    {
1378
0
        CPLError(CE_Failure, CPLE_AppDefined,
1379
0
                 "GetNoDataValue() should be called instead");
1380
0
        if (pbSuccess)
1381
0
            *pbSuccess = FALSE;
1382
0
        return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
1383
0
    }
1384
1385
0
    int bSuccess = FALSE;
1386
0
    const auto nNoDataValue =
1387
0
        GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
1388
0
    if (bSuccess)
1389
0
    {
1390
0
        if (pbSuccess)
1391
0
            *pbSuccess = TRUE;
1392
1393
0
        return nNoDataValue;
1394
0
    }
1395
1396
0
    if (m_bNoDataSetAsUInt64)
1397
0
    {
1398
0
        if (pbSuccess)
1399
0
            *pbSuccess = TRUE;
1400
1401
0
        return m_nNoDataValueUInt64;
1402
0
    }
1403
1404
0
    if (m_poGDS->m_bNoDataSetAsUInt64)
1405
0
    {
1406
0
        if (pbSuccess)
1407
0
            *pbSuccess = TRUE;
1408
1409
0
        return m_poGDS->m_nNoDataValueUInt64;
1410
0
    }
1411
1412
0
    if (pbSuccess)
1413
0
        *pbSuccess = FALSE;
1414
0
    return nNoDataValue;
1415
0
}
1416
1417
/************************************************************************/
1418
/*                          GetOverviewCount()                          */
1419
/************************************************************************/
1420
1421
int GTiffRasterBand::GetOverviewCount()
1422
1423
0
{
1424
0
    if (!m_poGDS->AreOverviewsEnabled())
1425
0
        return 0;
1426
1427
0
    m_poGDS->ScanDirectories();
1428
1429
0
    if (m_poGDS->m_nOverviewCount > 0)
1430
0
    {
1431
0
        return m_poGDS->m_nOverviewCount;
1432
0
    }
1433
1434
0
    const int nOverviewCount = GDALRasterBand::GetOverviewCount();
1435
0
    if (nOverviewCount > 0)
1436
0
        return nOverviewCount;
1437
1438
    // Implicit JPEG overviews are normally hidden, except when doing
1439
    // IRasterIO() operations.
1440
0
    if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
1441
0
        return m_poGDS->GetJPEGOverviewCount();
1442
1443
0
    return 0;
1444
0
}
1445
1446
/************************************************************************/
1447
/*                            GetOverview()                             */
1448
/************************************************************************/
1449
1450
GDALRasterBand *GTiffRasterBand::GetOverview(int i)
1451
1452
0
{
1453
0
    m_poGDS->ScanDirectories();
1454
1455
0
    if (m_poGDS->m_nOverviewCount > 0)
1456
0
    {
1457
        // Do we have internal overviews?
1458
0
        if (i < 0 || i >= m_poGDS->m_nOverviewCount)
1459
0
            return nullptr;
1460
1461
0
        return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
1462
0
    }
1463
1464
0
    GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
1465
0
    if (poOvrBand != nullptr)
1466
0
        return poOvrBand;
1467
1468
    // For consistency with GetOverviewCount(), we should also test
1469
    // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
1470
    // to query them for testing purposes.
1471
0
    if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
1472
0
        return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
1473
1474
0
    return nullptr;
1475
0
}
1476
1477
/************************************************************************/
1478
/*                           GetMaskFlags()                             */
1479
/************************************************************************/
1480
1481
int GTiffRasterBand::GetMaskFlags()
1482
0
{
1483
0
    m_poGDS->ScanDirectories();
1484
1485
0
    if (m_poGDS->m_poExternalMaskDS != nullptr)
1486
0
    {
1487
0
        return GMF_PER_DATASET;
1488
0
    }
1489
1490
0
    if (m_poGDS->m_poMaskDS != nullptr)
1491
0
    {
1492
0
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1493
0
        {
1494
0
            return GMF_PER_DATASET;
1495
0
        }
1496
1497
0
        return 0;
1498
0
    }
1499
1500
0
    if (m_poGDS->m_bIsOverview)
1501
0
    {
1502
0
        return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
1503
0
    }
1504
1505
0
    return GDALPamRasterBand::GetMaskFlags();
1506
0
}
1507
1508
/************************************************************************/
1509
/*                            GetMaskBand()                             */
1510
/************************************************************************/
1511
1512
GDALRasterBand *GTiffRasterBand::GetMaskBand()
1513
0
{
1514
0
    m_poGDS->ScanDirectories();
1515
1516
0
    if (m_poGDS->m_poExternalMaskDS != nullptr)
1517
0
    {
1518
0
        return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
1519
0
    }
1520
1521
0
    if (m_poGDS->m_poMaskDS != nullptr)
1522
0
    {
1523
0
        if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
1524
0
            return m_poGDS->m_poMaskDS->GetRasterBand(1);
1525
1526
0
        return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
1527
0
    }
1528
1529
0
    if (m_poGDS->m_bIsOverview)
1530
0
    {
1531
0
        GDALRasterBand *poBaseMask =
1532
0
            m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
1533
0
        if (poBaseMask)
1534
0
        {
1535
0
            const int nOverviews = poBaseMask->GetOverviewCount();
1536
0
            for (int i = 0; i < nOverviews; i++)
1537
0
            {
1538
0
                GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
1539
0
                if (poOvr && poOvr->GetXSize() == GetXSize() &&
1540
0
                    poOvr->GetYSize() == GetYSize())
1541
0
                {
1542
0
                    return poOvr;
1543
0
                }
1544
0
            }
1545
0
        }
1546
0
    }
1547
1548
0
    return GDALPamRasterBand::GetMaskBand();
1549
0
}
1550
1551
/************************************************************************/
1552
/*                            IsMaskBand()                              */
1553
/************************************************************************/
1554
1555
bool GTiffRasterBand::IsMaskBand() const
1556
0
{
1557
0
    return (m_poGDS->m_poImageryDS != nullptr &&
1558
0
            m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
1559
0
           m_eBandInterp == GCI_AlphaBand ||
1560
0
           m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
1561
0
}
1562
1563
/************************************************************************/
1564
/*                         GetMaskValueRange()                          */
1565
/************************************************************************/
1566
1567
GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
1568
0
{
1569
0
    if (!IsMaskBand())
1570
0
        return GMVR_UNKNOWN;
1571
0
    if (m_poGDS->m_nBitsPerSample == 1)
1572
0
        return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
1573
0
                                          : GMVR_0_AND_1_ONLY;
1574
0
    return GMVR_UNKNOWN;
1575
0
}