Coverage Report

Created: 2025-06-13 06:29

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