LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffrasterband_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 827 933 88.6 %
Date: 2024-11-21 22:18:42 Functions: 32 33 97.0 %

          Line data    Source code
       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        3279 : GDALRasterAttributeTable *GTiffRasterBand::GetDefaultRAT()
      35             : 
      36             : {
      37        3279 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
      38        3279 :     return GDALPamRasterBand::GetDefaultRAT();
      39             : }
      40             : 
      41             : /************************************************************************/
      42             : /*                           GetHistogram()                             */
      43             : /************************************************************************/
      44             : 
      45          20 : CPLErr GTiffRasterBand::GetHistogram(double dfMin, double dfMax, int nBuckets,
      46             :                                      GUIntBig *panHistogram,
      47             :                                      int bIncludeOutOfRange, int bApproxOK,
      48             :                                      GDALProgressFunc pfnProgress,
      49             :                                      void *pProgressData)
      50             : {
      51          20 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
      52          20 :     return GDALPamRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
      53             :                                            bIncludeOutOfRange, bApproxOK,
      54          20 :                                            pfnProgress, pProgressData);
      55             : }
      56             : 
      57             : /************************************************************************/
      58             : /*                       GetDefaultHistogram()                          */
      59             : /************************************************************************/
      60             : 
      61          21 : CPLErr GTiffRasterBand::GetDefaultHistogram(
      62             :     double *pdfMin, double *pdfMax, int *pnBuckets, GUIntBig **ppanHistogram,
      63             :     int bForce, GDALProgressFunc pfnProgress, void *pProgressData)
      64             : {
      65          21 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
      66          21 :     return GDALPamRasterBand::GetDefaultHistogram(pdfMin, pdfMax, pnBuckets,
      67             :                                                   ppanHistogram, bForce,
      68          21 :                                                   pfnProgress, pProgressData);
      69             : }
      70             : 
      71             : /************************************************************************/
      72             : /*                           DirectIO()                                 */
      73             : /************************************************************************/
      74             : 
      75             : // Reads directly bytes from the file using ReadMultiRange(), and by-pass
      76             : // block reading. Restricted to simple TIFF configurations
      77             : // (uncompressed data, standard data types). Particularly useful to extract
      78             : // sub-windows of data on a large /vsicurl dataset).
      79             : // Returns -1 if DirectIO() can't be supported on that file.
      80             : 
      81        2098 : int GTiffRasterBand::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
      82             :                               int nXSize, int nYSize, void *pData,
      83             :                               int nBufXSize, int nBufYSize,
      84             :                               GDALDataType eBufType, GSpacing nPixelSpace,
      85             :                               GSpacing nLineSpace,
      86             :                               GDALRasterIOExtraArg *psExtraArg)
      87             : {
      88        2098 :     const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
      89        4196 :     if (!(eRWFlag == GF_Read && m_poGDS->m_nCompression == COMPRESSION_NONE &&
      90        2098 :           (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
      91         795 :            m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
      92           0 :            m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
      93        2098 :           IsBaseGTiffClass()))
      94             :     {
      95           0 :         return -1;
      96             :     }
      97        2098 :     m_poGDS->Crystalize();
      98             : 
      99             :     // Only know how to deal with nearest neighbour in this optimized routine.
     100        2098 :     if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
     101         447 :         psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
     102             :     {
     103          66 :         return -1;
     104             :     }
     105             : 
     106             : #if DEBUG_VERBOSE
     107             :     CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
     108             :              nYSize, nBufXSize, nBufYSize);
     109             : #endif
     110             : 
     111             :     // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
     112        2032 :     if (m_poGDS->GetAccess() == GA_Update)
     113             :     {
     114           0 :         m_poGDS->FlushCache(false);
     115           0 :         VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
     116             :     }
     117             : 
     118        2032 :     if (TIFFIsTiled(m_poGDS->m_hTIFF))
     119             :     {
     120         504 :         const int nDTSize = nDTSizeBits / 8;
     121         504 :         const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
     122        1008 :             static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize * nDTSize *
     123         504 :             (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands
     124             :                                                              : 1));
     125         504 :         if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
     126             :         {
     127          28 :             m_poGDS->m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
     128          14 :                 VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
     129          14 :             if (m_poGDS->m_pTempBufferForCommonDirectIO == nullptr)
     130           0 :                 return CE_Failure;
     131             :         }
     132             : 
     133         504 :         VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
     134             :         FetchBufferDirectIO oFetcher(fp,
     135         504 :                                      m_poGDS->m_pTempBufferForCommonDirectIO,
     136         504 :                                      nTempBufferForCommonDirectIOSize);
     137             : 
     138        1008 :         return m_poGDS->CommonDirectIOClassic(
     139             :             oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     140         504 :             eBufType, 1, &nBand, nPixelSpace, nLineSpace, 0);
     141             :     }
     142             : 
     143             :     // Get strip offsets.
     144        1528 :     toff_t *panTIFFOffsets = nullptr;
     145        1528 :     if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
     146        3056 :                       &panTIFFOffsets) ||
     147        1528 :         panTIFFOffsets == nullptr)
     148             :     {
     149           0 :         return CE_Failure;
     150             :     }
     151             : 
     152             :     // Sub-sampling or over-sampling can only be done at last stage.
     153        1528 :     int nReqXSize = nXSize;
     154             :     // Can do sub-sampling at the extraction stage.
     155        1528 :     const int nReqYSize = std::min(nBufYSize, nYSize);
     156             :     // TODO(schwehr): Make ppData be GByte**.
     157             :     void **ppData =
     158        1528 :         static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
     159             :     vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
     160        1528 :         VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
     161             :     size_t *panSizes =
     162        1528 :         static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
     163        1528 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
     164        1528 :     void *pTmpBuffer = nullptr;
     165        1528 :     int eErr = CE_None;
     166        1528 :     int nContigBands =
     167        1528 :         m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? m_poGDS->nBands : 1;
     168        1528 :     int nSrcPixelSize = nDTSize * nContigBands;
     169             : 
     170        1528 :     if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
     171           0 :         eErr = CE_Failure;
     172        1295 :     else if (nXSize != nBufXSize || nYSize != nBufYSize ||
     173        1295 :              eBufType != eDataType ||
     174        2823 :              nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
     175             :              nContigBands > 1)
     176             :     {
     177             :         // We need a temporary buffer for over-sampling/sub-sampling
     178             :         // and/or data type conversion.
     179        1388 :         pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
     180        1388 :         if (pTmpBuffer == nullptr)
     181           0 :             eErr = CE_Failure;
     182             :     }
     183             : 
     184             :     // Prepare data extraction.
     185        1528 :     const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
     186             : 
     187       41509 :     for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
     188             :     {
     189       39981 :         if (pTmpBuffer == nullptr)
     190       10980 :             ppData[iLine] = static_cast<GByte *>(pData) + iLine * nLineSpace;
     191             :         else
     192       29001 :             ppData[iLine] =
     193       29001 :                 static_cast<GByte *>(pTmpBuffer) +
     194       29001 :                 static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
     195       39981 :         int nSrcLine = 0;
     196       39981 :         if (nBufYSize < nYSize)  // Sub-sampling in y.
     197        2440 :             nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
     198             :         else
     199       37541 :             nSrcLine = nYOff + iLine;
     200             : 
     201       39981 :         const int nBlockXOff = 0;
     202       39981 :         const int nBlockYOff = nSrcLine / nBlockYSize;
     203       39981 :         const int nYOffsetInBlock = nSrcLine % nBlockYSize;
     204       39981 :         const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
     205             : 
     206       39981 :         panOffsets[iLine] = panTIFFOffsets[nBlockId];
     207       39981 :         if (panOffsets[iLine] == 0)  // We don't support sparse files.
     208        1047 :             eErr = -1;
     209             : 
     210       39981 :         panOffsets[iLine] +=
     211       39981 :             (nXOff + static_cast<vsi_l_offset>(nYOffsetInBlock) * nBlockXSize) *
     212       39981 :             nSrcPixelSize;
     213       39981 :         panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
     214             :     }
     215             : 
     216             :     // Extract data from the file.
     217        1528 :     if (eErr == CE_None)
     218             :     {
     219         481 :         VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
     220             :         const int nRet =
     221         481 :             VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
     222         481 :         if (nRet != 0)
     223          12 :             eErr = CE_Failure;
     224             :     }
     225             : 
     226             :     // Byte-swap if necessary.
     227        1528 :     if (eErr == CE_None && TIFFIsByteSwapped(m_poGDS->m_hTIFF))
     228             :     {
     229        4144 :         for (int iLine = 0; iLine < nReqYSize; ++iLine)
     230             :         {
     231        4094 :             if (GDALDataTypeIsComplex(eDataType))
     232        2396 :                 GDALSwapWords(ppData[iLine], nDTSize / 2,
     233        2396 :                               2 * nReqXSize * nContigBands, nDTSize / 2);
     234             :             else
     235        1698 :                 GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
     236             :                               nDTSize);
     237             :         }
     238             :     }
     239             : 
     240             :     // Over-sampling/sub-sampling and/or data type conversion.
     241        1528 :     const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
     242        1528 :     if (eErr == CE_None && pTmpBuffer != nullptr)
     243             :     {
     244         364 :         const bool bOneByteCopy =
     245         656 :             (eDataType == eBufType &&
     246         292 :              (eDataType == GDT_Byte || eDataType == GDT_Int8));
     247       96459 :         for (int iY = 0; iY < nBufYSize; ++iY)
     248             :         {
     249      192190 :             const int iSrcY = nBufYSize <= nYSize
     250       96095 :                                   ? iY
     251       73872 :                                   : static_cast<int>((iY + 0.5) * dfSrcYInc);
     252             : 
     253      192190 :             GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]) +
     254       96095 :                                  (nContigBands > 1 ? (nBand - 1) : 0) * nDTSize;
     255       96095 :             GByte *pabyDstData = static_cast<GByte *>(pData) + iY * nLineSpace;
     256       96095 :             if (nBufXSize == nXSize)
     257             :             {
     258       19798 :                 GDALCopyWords(pabySrcData, eDataType, nSrcPixelSize,
     259             :                               pabyDstData, eBufType,
     260             :                               static_cast<int>(nPixelSpace), nBufXSize);
     261             :             }
     262             :             else
     263             :             {
     264       76297 :                 if (bOneByteCopy)
     265             :                 {
     266       25435 :                     double dfSrcX = 0.5 * dfSrcXInc;
     267     2147110 :                     for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
     268             :                     {
     269     2121670 :                         const int iSrcX = static_cast<int>(dfSrcX);
     270     2121670 :                         pabyDstData[iX * nPixelSpace] =
     271     2121670 :                             pabySrcData[iSrcX * nSrcPixelSize];
     272             :                     }
     273             :                 }
     274             :                 else
     275             :                 {
     276       50862 :                     double dfSrcX = 0.5 * dfSrcXInc;
     277     4293180 :                     for (int iX = 0; iX < nBufXSize; ++iX, dfSrcX += dfSrcXInc)
     278             :                     {
     279     4242320 :                         const int iSrcX = static_cast<int>(dfSrcX);
     280     4242320 :                         GDALCopyWords(
     281     4242320 :                             pabySrcData + iSrcX * nSrcPixelSize, eDataType, 0,
     282     4242320 :                             pabyDstData + iX * nPixelSpace, eBufType, 0, 1);
     283             :                     }
     284             :                 }
     285             :             }
     286             :         }
     287             :     }
     288             : 
     289             :     // Cleanup.
     290        1528 :     CPLFree(pTmpBuffer);
     291        1528 :     CPLFree(ppData);
     292        1528 :     CPLFree(panOffsets);
     293        1528 :     CPLFree(panSizes);
     294             : 
     295        1528 :     return eErr;
     296             : }
     297             : 
     298             : /************************************************************************/
     299             : /*                           GetVirtualMemAuto()                        */
     300             : /************************************************************************/
     301             : 
     302          17 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAuto(GDALRWFlag eRWFlag,
     303             :                                                   int *pnPixelSpace,
     304             :                                                   GIntBig *pnLineSpace,
     305             :                                                   char **papszOptions)
     306             : {
     307          17 :     const char *pszImpl = CSLFetchNameValueDef(
     308             :         papszOptions, "USE_DEFAULT_IMPLEMENTATION", "AUTO");
     309          17 :     if (EQUAL(pszImpl, "YES") || EQUAL(pszImpl, "ON") || EQUAL(pszImpl, "1") ||
     310          16 :         EQUAL(pszImpl, "TRUE"))
     311             :     {
     312           1 :         return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace,
     313           1 :                                                  pnLineSpace, papszOptions);
     314             :     }
     315             : 
     316          16 :     CPLVirtualMem *psRet = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace,
     317             :                                                      pnLineSpace, papszOptions);
     318          16 :     if (psRet != nullptr)
     319             :     {
     320          14 :         CPLDebug("GTiff", "GetVirtualMemAuto(): Using memory file mapping");
     321          14 :         return psRet;
     322             :     }
     323             : 
     324           2 :     if (EQUAL(pszImpl, "NO") || EQUAL(pszImpl, "OFF") || EQUAL(pszImpl, "0") ||
     325           1 :         EQUAL(pszImpl, "FALSE"))
     326             :     {
     327           1 :         return nullptr;
     328             :     }
     329             : 
     330           1 :     CPLDebug("GTiff", "GetVirtualMemAuto(): Defaulting to base implementation");
     331           1 :     return GDALRasterBand::GetVirtualMemAuto(eRWFlag, pnPixelSpace, pnLineSpace,
     332           1 :                                              papszOptions);
     333             : }
     334             : 
     335             : /************************************************************************/
     336             : /*                     DropReferenceVirtualMem()                        */
     337             : /************************************************************************/
     338             : 
     339           8 : void GTiffRasterBand::DropReferenceVirtualMem(void *pUserData)
     340             : {
     341             :     // This function may also be called when the dataset and rasterband
     342             :     // objects have been destroyed.
     343             :     // If they are still alive, it updates the reference counter of the
     344             :     // base mapping to invalidate the pointer to it if needed.
     345             : 
     346           8 :     GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(pUserData);
     347           8 :     GTiffRasterBand *poSelf = *ppoSelf;
     348             : 
     349           8 :     if (poSelf != nullptr)
     350             :     {
     351           8 :         if (--(poSelf->m_poGDS->m_nRefBaseMapping) == 0)
     352             :         {
     353           4 :             poSelf->m_poGDS->m_pBaseMapping = nullptr;
     354             :         }
     355           8 :         poSelf->m_aSetPSelf.erase(ppoSelf);
     356             :     }
     357           8 :     CPLFree(pUserData);
     358           8 : }
     359             : 
     360             : /************************************************************************/
     361             : /*                     GetVirtualMemAutoInternal()                      */
     362             : /************************************************************************/
     363             : 
     364          20 : CPLVirtualMem *GTiffRasterBand::GetVirtualMemAutoInternal(GDALRWFlag eRWFlag,
     365             :                                                           int *pnPixelSpace,
     366             :                                                           GIntBig *pnLineSpace,
     367             :                                                           char **papszOptions)
     368             : {
     369          20 :     int nLineSize = nBlockXSize * GDALGetDataTypeSizeBytes(eDataType);
     370          20 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     371          14 :         nLineSize *= m_poGDS->nBands;
     372             : 
     373          20 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     374             :     {
     375             :         // In case of a pixel interleaved file, we save virtual memory space
     376             :         // by reusing a base mapping that embraces the whole imagery.
     377          14 :         if (m_poGDS->m_pBaseMapping != nullptr)
     378             :         {
     379             :             // Offset between the base mapping and the requested mapping.
     380           8 :             vsi_l_offset nOffset = static_cast<vsi_l_offset>(nBand - 1) *
     381           8 :                                    GDALGetDataTypeSizeBytes(eDataType);
     382             : 
     383             :             GTiffRasterBand **ppoSelf = static_cast<GTiffRasterBand **>(
     384           8 :                 CPLCalloc(1, sizeof(GTiffRasterBand *)));
     385           8 :             *ppoSelf = this;
     386             : 
     387          24 :             CPLVirtualMem *pVMem = CPLVirtualMemDerivedNew(
     388           8 :                 m_poGDS->m_pBaseMapping, nOffset,
     389           8 :                 CPLVirtualMemGetSize(m_poGDS->m_pBaseMapping) - nOffset,
     390             :                 GTiffRasterBand::DropReferenceVirtualMem, ppoSelf);
     391           8 :             if (pVMem == nullptr)
     392             :             {
     393           0 :                 CPLFree(ppoSelf);
     394           0 :                 return nullptr;
     395             :             }
     396             : 
     397             :             // Mechanism used so that the memory mapping object can be
     398             :             // destroyed after the raster band.
     399           8 :             m_aSetPSelf.insert(ppoSelf);
     400           8 :             ++m_poGDS->m_nRefBaseMapping;
     401           8 :             *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
     402           8 :             if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     403           8 :                 *pnPixelSpace *= m_poGDS->nBands;
     404           8 :             *pnLineSpace = nLineSize;
     405           8 :             return pVMem;
     406             :         }
     407             :     }
     408             : 
     409          12 :     VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
     410             : 
     411          12 :     vsi_l_offset nLength = static_cast<vsi_l_offset>(nRasterYSize) * nLineSize;
     412             : 
     413          24 :     if (!(CPLIsVirtualMemFileMapAvailable() &&
     414          12 :           VSIFGetNativeFileDescriptorL(fp) != nullptr &&
     415             : #if SIZEOF_VOIDP == 4
     416             :           nLength == static_cast<size_t>(nLength) &&
     417             : #endif
     418          10 :           m_poGDS->m_nCompression == COMPRESSION_NONE &&
     419          10 :           (m_poGDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
     420           0 :            m_poGDS->m_nPhotometric == PHOTOMETRIC_RGB ||
     421           0 :            m_poGDS->m_nPhotometric == PHOTOMETRIC_PALETTE) &&
     422          10 :           m_poGDS->m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
     423          10 :           !TIFFIsTiled(m_poGDS->m_hTIFF) &&
     424          10 :           !TIFFIsByteSwapped(m_poGDS->m_hTIFF)))
     425             :     {
     426           2 :         return nullptr;
     427             :     }
     428             : 
     429             :     // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
     430          10 :     if (m_poGDS->GetAccess() == GA_Update)
     431             :     {
     432           7 :         m_poGDS->FlushCache(false);
     433           7 :         VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
     434             :     }
     435             : 
     436             :     // Get strip offsets.
     437          10 :     toff_t *panTIFFOffsets = nullptr;
     438          10 :     if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPOFFSETS,
     439          20 :                       &panTIFFOffsets) ||
     440          10 :         panTIFFOffsets == nullptr)
     441             :     {
     442           0 :         return nullptr;
     443             :     }
     444             : 
     445          10 :     GPtrDiff_t nBlockSize = static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
     446          10 :                             GDALGetDataTypeSizeBytes(eDataType);
     447          10 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     448           4 :         nBlockSize *= m_poGDS->nBands;
     449             : 
     450          10 :     int nBlocks = m_poGDS->m_nBlocksPerBand;
     451          10 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     452           6 :         nBlocks *= m_poGDS->nBands;
     453          10 :     int i = 0;  // Used after for.
     454         103 :     for (; i < nBlocks; ++i)
     455             :     {
     456         100 :         if (panTIFFOffsets[i] != 0)
     457           7 :             break;
     458             :     }
     459          10 :     if (i == nBlocks)
     460             :     {
     461             :         // All zeroes.
     462           3 :         if (m_poGDS->eAccess == GA_Update)
     463             :         {
     464             :             // Initialize the file with empty blocks so that the file has
     465             :             // the appropriate size.
     466             : 
     467           3 :             toff_t *panByteCounts = nullptr;
     468           3 :             if (!TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_STRIPBYTECOUNTS,
     469           6 :                               &panByteCounts) ||
     470           3 :                 panByteCounts == nullptr)
     471             :             {
     472           0 :                 return nullptr;
     473             :             }
     474           3 :             if (VSIFSeekL(fp, 0, SEEK_END) != 0)
     475           0 :                 return nullptr;
     476           3 :             vsi_l_offset nBaseOffset = VSIFTellL(fp);
     477             : 
     478             :             // Just write one tile with libtiff to put it in appropriate state.
     479             :             GByte *pabyData =
     480           3 :                 static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockSize));
     481           3 :             if (pabyData == nullptr)
     482             :             {
     483           0 :                 return nullptr;
     484             :             }
     485           3 :             const auto ret = TIFFWriteEncodedStrip(m_poGDS->m_hTIFF, 0,
     486             :                                                    pabyData, nBlockSize);
     487           3 :             VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_poGDS->m_hTIFF));
     488           3 :             VSIFree(pabyData);
     489           3 :             if (ret != nBlockSize)
     490             :             {
     491           0 :                 return nullptr;
     492             :             }
     493           3 :             CPLAssert(panTIFFOffsets[0] == nBaseOffset);
     494           3 :             CPLAssert(panByteCounts[0] == static_cast<toff_t>(nBlockSize));
     495             : 
     496             :             // Now simulate the writing of other blocks.
     497           3 :             assert(nBlocks > 0);
     498           3 :             assert(static_cast<vsi_l_offset>(nBlockSize) <
     499             :                    std::numeric_limits<vsi_l_offset>::max() / nBlocks);
     500           3 :             const vsi_l_offset nDataSize =
     501           3 :                 static_cast<vsi_l_offset>(nBlockSize) * nBlocks;
     502           3 :             if (VSIFTruncateL(fp, nBaseOffset + nDataSize) != 0)
     503           0 :                 return nullptr;
     504             : 
     505          93 :             for (i = 1; i < nBlocks; ++i)
     506             :             {
     507          90 :                 panTIFFOffsets[i] =
     508          90 :                     nBaseOffset + i * static_cast<toff_t>(nBlockSize);
     509          90 :                 panByteCounts[i] = nBlockSize;
     510             :             }
     511             :         }
     512             :         else
     513             :         {
     514           0 :             CPLDebug("GTiff", "Sparse files not supported in file mapping");
     515           0 :             return nullptr;
     516             :         }
     517             :     }
     518             : 
     519          10 :     GIntBig nBlockSpacing = 0;
     520          10 :     bool bCompatibleSpacing = true;
     521          10 :     toff_t nPrevOffset = 0;
     522         229 :     for (i = 0; i < m_poGDS->m_nBlocksPerBand; ++i)
     523             :     {
     524         219 :         toff_t nCurOffset = 0;
     525         219 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     526          96 :             nCurOffset =
     527          96 :                 panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1) + i];
     528             :         else
     529         123 :             nCurOffset = panTIFFOffsets[i];
     530         219 :         if (nCurOffset == 0)
     531             :         {
     532           0 :             bCompatibleSpacing = false;
     533           0 :             break;
     534             :         }
     535         219 :         if (i > 0)
     536             :         {
     537         209 :             const GIntBig nCurSpacing = nCurOffset - nPrevOffset;
     538         209 :             if (i == 1)
     539             :             {
     540          10 :                 if (nCurSpacing !=
     541          10 :                     static_cast<GIntBig>(nBlockYSize) * nLineSize)
     542             :                 {
     543           0 :                     bCompatibleSpacing = false;
     544           0 :                     break;
     545             :                 }
     546          10 :                 nBlockSpacing = nCurSpacing;
     547             :             }
     548         199 :             else if (nBlockSpacing != nCurSpacing)
     549             :             {
     550           0 :                 bCompatibleSpacing = false;
     551           0 :                 break;
     552             :             }
     553             :         }
     554         219 :         nPrevOffset = nCurOffset;
     555             :     }
     556             : 
     557          10 :     if (!bCompatibleSpacing)
     558             :     {
     559           0 :         return nullptr;
     560             :     }
     561             : 
     562          10 :     vsi_l_offset nOffset = 0;
     563          10 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     564             :     {
     565           4 :         CPLAssert(m_poGDS->m_pBaseMapping == nullptr);
     566           4 :         nOffset = panTIFFOffsets[0];
     567             :     }
     568             :     else
     569             :     {
     570           6 :         nOffset = panTIFFOffsets[m_poGDS->m_nBlocksPerBand * (nBand - 1)];
     571             :     }
     572          10 :     CPLVirtualMem *pVMem = CPLVirtualMemFileMapNew(
     573             :         fp, nOffset, nLength,
     574             :         eRWFlag == GF_Write ? VIRTUALMEM_READWRITE : VIRTUALMEM_READONLY,
     575             :         nullptr, nullptr);
     576          10 :     if (pVMem == nullptr)
     577             :     {
     578           0 :         return nullptr;
     579             :     }
     580             : 
     581          10 :     if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     582             :     {
     583             :         // TODO(schwehr): Revisit this block.
     584           4 :         m_poGDS->m_pBaseMapping = pVMem;
     585           4 :         pVMem = GetVirtualMemAutoInternal(eRWFlag, pnPixelSpace, pnLineSpace,
     586             :                                           papszOptions);
     587             :         // Drop ref on base mapping.
     588           4 :         CPLVirtualMemFree(m_poGDS->m_pBaseMapping);
     589           4 :         if (pVMem == nullptr)
     590           0 :             m_poGDS->m_pBaseMapping = nullptr;
     591             :     }
     592             :     else
     593             :     {
     594           6 :         *pnPixelSpace = GDALGetDataTypeSizeBytes(eDataType);
     595           6 :         if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     596           0 :             *pnPixelSpace *= m_poGDS->nBands;
     597           6 :         *pnLineSpace = nLineSize;
     598             :     }
     599          10 :     return pVMem;
     600             : }
     601             : 
     602             : /************************************************************************/
     603             : /*                         CacheMultiRange()                            */
     604             : /************************************************************************/
     605             : 
     606         234 : static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
     607             : {
     608             :     GByte abyTrailer[4];
     609         234 :     memcpy(abyTrailer, strileData + nStrileSize, 4);
     610         234 :     GByte abyLastBytes[4] = {};
     611         234 :     if (nStrileSize >= 4)
     612         234 :         memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
     613             :     else
     614             :     {
     615             :         // The last bytes will be zero due to the above {} initialization,
     616             :         // and that's what should be in abyTrailer too when the trailer is
     617             :         // correct.
     618           0 :         memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
     619             :     }
     620         234 :     return memcmp(abyTrailer, abyLastBytes, 4) == 0;
     621             : }
     622             : 
     623         262 : void *GTiffRasterBand::CacheMultiRange(int nXOff, int nYOff, int nXSize,
     624             :                                        int nYSize, int nBufXSize, int nBufYSize,
     625             :                                        GDALRasterIOExtraArg *psExtraArg)
     626             : {
     627         262 :     void *pBufferedData = nullptr;
     628             :     // Same logic as in GDALRasterBand::IRasterIO()
     629         262 :     double dfXOff = nXOff;
     630         262 :     double dfYOff = nYOff;
     631         262 :     double dfXSize = nXSize;
     632         262 :     double dfYSize = nYSize;
     633         262 :     if (psExtraArg->bFloatingPointWindowValidity)
     634             :     {
     635          48 :         dfXOff = psExtraArg->dfXOff;
     636          48 :         dfYOff = psExtraArg->dfYOff;
     637          48 :         dfXSize = psExtraArg->dfXSize;
     638          48 :         dfYSize = psExtraArg->dfYSize;
     639             :     }
     640         262 :     const double dfSrcXInc = dfXSize / static_cast<double>(nBufXSize);
     641         262 :     const double dfSrcYInc = dfYSize / static_cast<double>(nBufYSize);
     642         262 :     const double EPS = 1e-10;
     643             :     const int nBlockX1 =
     644         262 :         static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
     645         262 :         nBlockXSize;
     646             :     const int nBlockY1 =
     647         262 :         static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
     648         262 :         nBlockYSize;
     649             :     const int nBlockX2 =
     650         262 :         static_cast<int>(
     651         524 :             std::min(static_cast<double>(nRasterXSize - 1),
     652         262 :                      (nBufXSize - 1 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
     653         262 :         nBlockXSize;
     654             :     const int nBlockY2 =
     655         262 :         static_cast<int>(
     656         524 :             std::min(static_cast<double>(nRasterYSize - 1),
     657         262 :                      (nBufYSize - 1 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
     658         262 :         nBlockYSize;
     659             : 
     660         262 :     const int nBlockCount = nBlocksPerRow * nBlocksPerColumn;
     661             : 
     662             :     struct StrileData
     663             :     {
     664             :         vsi_l_offset nOffset;
     665             :         vsi_l_offset nByteCount;
     666             :         bool bTryMask;
     667             :     };
     668             : 
     669         524 :     std::map<int, StrileData> oMapStrileToOffsetByteCount;
     670             : 
     671             :     // Dedicated method to retrieved the offset and size in an efficient way
     672             :     // when m_bBlockOrderRowMajor and m_bLeaderSizeAsUInt4 conditions are
     673             :     // met.
     674             :     // Except for the last block, we just read the offset from the TIFF offset
     675             :     // array, and retrieve the size in the leader 4 bytes that come before the
     676             :     // payload.
     677             :     auto OptimizedRetrievalOfOffsetSize =
     678         195 :         [&](int nBlockId, vsi_l_offset &nOffset, vsi_l_offset &nSize,
     679             :             size_t nTotalSize, size_t nMaxRawBlockCacheSize)
     680             :     {
     681         438 :         bool bTryMask = m_poGDS->m_bMaskInterleavedWithImagery;
     682         195 :         nOffset = TIFFGetStrileOffset(m_poGDS->m_hTIFF, nBlockId);
     683         195 :         if (nOffset >= 4)
     684             :         {
     685         132 :             if (nBlockId == nBlockCount - 1)
     686             :             {
     687             :                 // Special case for the last block. As there is no next block
     688             :                 // from which to retrieve an offset, use the good old method
     689             :                 // that consists in reading the ByteCount array.
     690          49 :                 if (bTryMask && m_poGDS->GetRasterBand(1)->GetMaskBand() &&
     691          23 :                     m_poGDS->m_poMaskDS)
     692             :                 {
     693          46 :                     auto nMaskOffset = TIFFGetStrileOffset(
     694          23 :                         m_poGDS->m_poMaskDS->m_hTIFF, nBlockId);
     695          23 :                     if (nMaskOffset)
     696             :                     {
     697          23 :                         nSize = nMaskOffset +
     698          46 :                                 TIFFGetStrileByteCount(
     699          23 :                                     m_poGDS->m_poMaskDS->m_hTIFF, nBlockId) -
     700          23 :                                 nOffset;
     701             :                     }
     702             :                     else
     703             :                     {
     704           0 :                         bTryMask = false;
     705             :                     }
     706             :                 }
     707          26 :                 if (nSize == 0)
     708             :                 {
     709           3 :                     nSize = TIFFGetStrileByteCount(m_poGDS->m_hTIFF, nBlockId);
     710             :                 }
     711          26 :                 if (nSize && m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
     712             :                 {
     713          26 :                     nSize += 4;
     714             :                 }
     715             :             }
     716             :             else
     717             :             {
     718             :                 auto nOffsetNext =
     719         106 :                     TIFFGetStrileOffset(m_poGDS->m_hTIFF, nBlockId + 1);
     720         106 :                 if (nOffsetNext > nOffset)
     721             :                 {
     722          98 :                     nSize = nOffsetNext - nOffset;
     723             :                 }
     724             :                 else
     725             :                 {
     726             :                     // Shouldn't happen for a compliant file
     727           8 :                     if (nOffsetNext != 0)
     728             :                     {
     729           0 :                         CPLDebug("GTiff", "Tile %d is not located after %d",
     730             :                                  nBlockId + 1, nBlockId);
     731             :                     }
     732           8 :                     bTryMask = false;
     733           8 :                     nSize = TIFFGetStrileByteCount(m_poGDS->m_hTIFF, nBlockId);
     734           8 :                     if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
     735           8 :                         nSize += 4;
     736             :                 }
     737             :             }
     738         132 :             if (nSize)
     739             :             {
     740         132 :                 nOffset -= 4;
     741         132 :                 nSize += 4;
     742         132 :                 if (nTotalSize + nSize < nMaxRawBlockCacheSize)
     743             :                 {
     744             :                     StrileData data;
     745         132 :                     data.nOffset = nOffset;
     746         132 :                     data.nByteCount = nSize;
     747         132 :                     data.bTryMask = bTryMask;
     748         132 :                     oMapStrileToOffsetByteCount[nBlockId] = data;
     749             :                 }
     750             :             }
     751             :         }
     752             :         else
     753             :         {
     754             :             // Sparse tile
     755             :             StrileData data;
     756          63 :             data.nOffset = 0;
     757          63 :             data.nByteCount = 0;
     758          63 :             data.bTryMask = false;
     759          63 :             oMapStrileToOffsetByteCount[nBlockId] = data;
     760             :         }
     761         195 :     };
     762             : 
     763             :     // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
     764             :     // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
     765             :     // mask) from the temporary oMapStrileToOffsetByteCount.
     766             :     auto FillCacheStrileToOffsetByteCount =
     767          36 :         [&](const std::vector<vsi_l_offset> &anOffsets,
     768             :             const std::vector<size_t> &anSizes,
     769             :             const std::vector<void *> &apData)
     770             :     {
     771          36 :         CPLAssert(m_poGDS->m_bLeaderSizeAsUInt4);
     772          36 :         size_t i = 0;
     773          36 :         vsi_l_offset nLastOffset = 0;
     774         191 :         for (const auto &entry : oMapStrileToOffsetByteCount)
     775             :         {
     776         155 :             const auto nBlockId = entry.first;
     777         155 :             const auto nOffset = entry.second.nOffset;
     778         155 :             const auto nSize = entry.second.nByteCount;
     779         155 :             if (nOffset == 0)
     780             :             {
     781             :                 // Sparse tile
     782          23 :                 m_poGDS->m_oCacheStrileToOffsetByteCount.insert(
     783          23 :                     nBlockId, std::pair(0, 0));
     784          53 :                 continue;
     785             :             }
     786             : 
     787         132 :             if (nOffset < nLastOffset)
     788             :             {
     789             :                 // shouldn't happen normally if tiles are sorted
     790           0 :                 i = 0;
     791             :             }
     792         132 :             nLastOffset = nOffset;
     793         272 :             while (i < anOffsets.size() &&
     794         136 :                    !(nOffset >= anOffsets[i] &&
     795         136 :                      nOffset + nSize <= anOffsets[i] + anSizes[i]))
     796             :             {
     797           4 :                 i++;
     798             :             }
     799         132 :             CPLAssert(i < anOffsets.size());
     800         132 :             CPLAssert(nOffset >= anOffsets[i]);
     801         132 :             CPLAssert(nOffset + nSize <= anOffsets[i] + anSizes[i]);
     802             :             GUInt32 nSizeFromLeader;
     803         132 :             memcpy(&nSizeFromLeader,
     804             :                    // cppcheck-suppress containerOutOfBounds
     805         132 :                    static_cast<GByte *>(apData[i]) + nOffset - anOffsets[i],
     806             :                    sizeof(nSizeFromLeader));
     807         132 :             CPL_LSBPTR32(&nSizeFromLeader);
     808         132 :             bool bOK = true;
     809         132 :             constexpr int nLeaderSize = 4;
     810         132 :             const int nTrailerSize =
     811         132 :                 (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated ? 4 : 0);
     812         132 :             if (nSizeFromLeader > nSize - nLeaderSize - nTrailerSize)
     813             :             {
     814           0 :                 CPLDebug("GTiff",
     815             :                          "Inconsistent block size from in leader of block %d",
     816             :                          nBlockId);
     817           0 :                 bOK = false;
     818             :             }
     819         132 :             else if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
     820             :             {
     821             :                 // Check trailer consistency
     822         132 :                 const GByte *strileData = static_cast<GByte *>(apData[i]) +
     823         132 :                                           nOffset - anOffsets[i] + nLeaderSize;
     824         132 :                 if (!CheckTrailer(strileData, nSizeFromLeader))
     825             :                 {
     826           0 :                     CPLDebug("GTiff", "Inconsistent trailer of block %d",
     827             :                              nBlockId);
     828           0 :                     bOK = false;
     829             :                 }
     830             :             }
     831         132 :             if (!bOK)
     832             :             {
     833           0 :                 return false;
     834             :             }
     835             : 
     836             :             {
     837         132 :                 const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
     838         132 :                 const vsi_l_offset nRealSize = nSizeFromLeader;
     839             : #ifdef DEBUG_VERBOSE
     840             :                 CPLDebug("GTiff",
     841             :                          "Block %d found at offset " CPL_FRMT_GUIB
     842             :                          " with size " CPL_FRMT_GUIB,
     843             :                          nBlockId, nRealOffset, nRealSize);
     844             : #endif
     845         132 :                 m_poGDS->m_oCacheStrileToOffsetByteCount.insert(
     846         132 :                     nBlockId, std::pair(nRealOffset, nRealSize));
     847             :             }
     848             : 
     849             :             // Processing of mask
     850         234 :             if (!(entry.second.bTryMask &&
     851         102 :                   m_poGDS->m_bMaskInterleavedWithImagery &&
     852         102 :                   m_poGDS->GetRasterBand(1)->GetMaskBand() &&
     853         102 :                   m_poGDS->m_poMaskDS))
     854             :             {
     855          30 :                 continue;
     856             :             }
     857             : 
     858         102 :             bOK = false;
     859         102 :             const vsi_l_offset nMaskOffsetWithLeader =
     860         102 :                 nOffset + nLeaderSize + nSizeFromLeader + nTrailerSize;
     861         204 :             if (nMaskOffsetWithLeader + nLeaderSize <=
     862         102 :                 anOffsets[i] + anSizes[i])
     863             :             {
     864             :                 GUInt32 nMaskSizeFromLeader;
     865         102 :                 memcpy(&nMaskSizeFromLeader,
     866         102 :                        static_cast<GByte *>(apData[i]) + nMaskOffsetWithLeader -
     867         102 :                            anOffsets[i],
     868             :                        sizeof(nMaskSizeFromLeader));
     869         102 :                 CPL_LSBPTR32(&nMaskSizeFromLeader);
     870         204 :                 if (nMaskOffsetWithLeader + nLeaderSize + nMaskSizeFromLeader +
     871         204 :                         nTrailerSize <=
     872         102 :                     anOffsets[i] + anSizes[i])
     873             :                 {
     874         102 :                     bOK = true;
     875         102 :                     if (m_poGDS->m_bTrailerRepeatedLast4BytesRepeated)
     876             :                     {
     877             :                         // Check trailer consistency
     878             :                         const GByte *strileMaskData =
     879         102 :                             static_cast<GByte *>(apData[i]) + nOffset -
     880         204 :                             anOffsets[i] + nLeaderSize + nSizeFromLeader +
     881         102 :                             nTrailerSize + nLeaderSize;
     882         102 :                         if (!CheckTrailer(strileMaskData, nMaskSizeFromLeader))
     883             :                         {
     884           0 :                             CPLDebug("GTiff",
     885             :                                      "Inconsistent trailer of mask of block %d",
     886             :                                      nBlockId);
     887           0 :                             bOK = false;
     888             :                         }
     889             :                     }
     890             :                 }
     891         102 :                 if (bOK)
     892             :                 {
     893         102 :                     const vsi_l_offset nRealOffset = nOffset + nLeaderSize +
     894         102 :                                                      nSizeFromLeader +
     895         102 :                                                      nTrailerSize + nLeaderSize;
     896         102 :                     const vsi_l_offset nRealSize = nMaskSizeFromLeader;
     897             : #ifdef DEBUG_VERBOSE
     898             :                     CPLDebug("GTiff",
     899             :                              "Mask of block %d found at offset " CPL_FRMT_GUIB
     900             :                              " with size " CPL_FRMT_GUIB,
     901             :                              nBlockId, nRealOffset, nRealSize);
     902             : #endif
     903             : 
     904         102 :                     m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
     905         102 :                         nBlockId, std::pair(nRealOffset, nRealSize));
     906             :                 }
     907             :             }
     908         102 :             if (!bOK)
     909             :             {
     910           0 :                 CPLDebug("GTiff",
     911             :                          "Mask for block %d is not properly interleaved with "
     912             :                          "imagery block",
     913             :                          nBlockId);
     914             :             }
     915             :         }
     916          36 :         return true;
     917         262 :     };
     918             : 
     919         262 :     thandle_t th = TIFFClientdata(m_poGDS->m_hTIFF);
     920         262 :     if (!VSI_TIFFHasCachedRanges(th))
     921             :     {
     922         234 :         std::vector<std::pair<vsi_l_offset, size_t>> aOffsetSize;
     923         234 :         size_t nTotalSize = 0;
     924         234 :         const unsigned int nMaxRawBlockCacheSize = atoi(
     925         234 :             CPLGetConfigOption("GDAL_MAX_RAW_BLOCK_CACHE_SIZE", "10485760"));
     926         234 :         bool bGoOn = true;
     927         543 :         for (int iY = nBlockY1; bGoOn && iY <= nBlockY2; iY++)
     928             :         {
     929        1010 :             for (int iX = nBlockX1; bGoOn && iX <= nBlockX2; iX++)
     930             :             {
     931         701 :                 GDALRasterBlock *poBlock = TryGetLockedBlockRef(iX, iY);
     932         701 :                 if (poBlock != nullptr)
     933             :                 {
     934         300 :                     poBlock->DropLock();
     935         300 :                     continue;
     936             :                 }
     937         401 :                 int nBlockId = iX + iY * nBlocksPerRow;
     938         401 :                 if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
     939           0 :                     nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
     940         401 :                 vsi_l_offset nOffset = 0;
     941         401 :                 vsi_l_offset nSize = 0;
     942             : 
     943         401 :                 if ((m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ||
     944           0 :                      m_poGDS->nBands == 1) &&
     945         401 :                     !m_poGDS->m_bStreamingIn &&
     946         401 :                     m_poGDS->m_bBlockOrderRowMajor &&
     947         195 :                     m_poGDS->m_bLeaderSizeAsUInt4)
     948             :                 {
     949         195 :                     OptimizedRetrievalOfOffsetSize(nBlockId, nOffset, nSize,
     950             :                                                    nTotalSize,
     951             :                                                    nMaxRawBlockCacheSize);
     952             :                 }
     953             :                 else
     954             :                 {
     955         206 :                     CPL_IGNORE_RET_VAL(
     956         206 :                         m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nSize));
     957             :                 }
     958         401 :                 if (nSize)
     959             :                 {
     960         143 :                     if (nTotalSize + nSize < nMaxRawBlockCacheSize)
     961             :                     {
     962             : #ifdef DEBUG_VERBOSE
     963             :                         CPLDebug("GTiff",
     964             :                                  "Precaching for block (%d, %d), " CPL_FRMT_GUIB
     965             :                                  "-" CPL_FRMT_GUIB,
     966             :                                  iX, iY, nOffset,
     967             :                                  nOffset + static_cast<size_t>(nSize) - 1);
     968             : #endif
     969         143 :                         aOffsetSize.push_back(
     970         143 :                             std::pair(nOffset, static_cast<size_t>(nSize)));
     971         143 :                         nTotalSize += static_cast<size_t>(nSize);
     972             :                     }
     973             :                     else
     974             :                     {
     975           0 :                         bGoOn = false;
     976             :                     }
     977             :                 }
     978             :             }
     979             :         }
     980             : 
     981         234 :         std::sort(aOffsetSize.begin(), aOffsetSize.end());
     982             : 
     983         234 :         if (nTotalSize > 0)
     984             :         {
     985          41 :             pBufferedData = VSI_MALLOC_VERBOSE(nTotalSize);
     986          41 :             if (pBufferedData)
     987             :             {
     988          41 :                 std::vector<vsi_l_offset> anOffsets;
     989          41 :                 std::vector<size_t> anSizes;
     990          41 :                 std::vector<void *> apData;
     991          41 :                 anOffsets.push_back(aOffsetSize[0].first);
     992          41 :                 apData.push_back(static_cast<GByte *>(pBufferedData));
     993          41 :                 size_t nChunkSize = aOffsetSize[0].second;
     994          41 :                 size_t nAccOffset = 0;
     995             :                 // Try to merge contiguous or slightly overlapping ranges
     996         143 :                 for (size_t i = 0; i < aOffsetSize.size() - 1; i++)
     997             :                 {
     998         204 :                     if (aOffsetSize[i].first < aOffsetSize[i + 1].first &&
     999         102 :                         aOffsetSize[i].first + aOffsetSize[i].second >=
    1000         102 :                             aOffsetSize[i + 1].first)
    1001             :                     {
    1002          98 :                         const auto overlap = aOffsetSize[i].first +
    1003          98 :                                              aOffsetSize[i].second -
    1004          98 :                                              aOffsetSize[i + 1].first;
    1005             :                         // That should always be the case for well behaved
    1006             :                         // TIFF files.
    1007          98 :                         if (aOffsetSize[i + 1].second > overlap)
    1008             :                         {
    1009          98 :                             nChunkSize += static_cast<size_t>(
    1010          98 :                                 aOffsetSize[i + 1].second - overlap);
    1011             :                         }
    1012             :                     }
    1013             :                     else
    1014             :                     {
    1015             :                         // terminate current block
    1016           4 :                         anSizes.push_back(nChunkSize);
    1017             : #ifdef DEBUG_VERBOSE
    1018             :                         CPLDebug("GTiff",
    1019             :                                  "Requesting range [" CPL_FRMT_GUIB
    1020             :                                  "-" CPL_FRMT_GUIB "]",
    1021             :                                  anOffsets.back(),
    1022             :                                  anOffsets.back() + anSizes.back() - 1);
    1023             : #endif
    1024           4 :                         nAccOffset += nChunkSize;
    1025             :                         // start a new range
    1026           4 :                         anOffsets.push_back(aOffsetSize[i + 1].first);
    1027           4 :                         apData.push_back(static_cast<GByte *>(pBufferedData) +
    1028             :                                          nAccOffset);
    1029           4 :                         nChunkSize = aOffsetSize[i + 1].second;
    1030             :                     }
    1031             :                 }
    1032             :                 // terminate last block
    1033          41 :                 anSizes.push_back(nChunkSize);
    1034             : #ifdef DEBUG_VERBOSE
    1035             :                 CPLDebug(
    1036             :                     "GTiff",
    1037             :                     "Requesting range [" CPL_FRMT_GUIB "-" CPL_FRMT_GUIB "]",
    1038             :                     anOffsets.back(), anOffsets.back() + anSizes.back() - 1);
    1039             : #endif
    1040             : 
    1041          41 :                 VSILFILE *fp = VSI_TIFFGetVSILFile(th);
    1042             : 
    1043          41 :                 if (VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
    1044          41 :                                         &apData[0], &anOffsets[0], &anSizes[0],
    1045          41 :                                         fp) == 0)
    1046             :                 {
    1047          77 :                     if (!oMapStrileToOffsetByteCount.empty() &&
    1048          36 :                         !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
    1049             :                                                           apData))
    1050             :                     {
    1051             :                         // Retry without optimization
    1052           0 :                         CPLFree(pBufferedData);
    1053           0 :                         m_poGDS->m_bLeaderSizeAsUInt4 = false;
    1054             :                         void *pRet =
    1055           0 :                             CacheMultiRange(nXOff, nYOff, nXSize, nYSize,
    1056             :                                             nBufXSize, nBufYSize, psExtraArg);
    1057           0 :                         m_poGDS->m_bLeaderSizeAsUInt4 = true;
    1058           0 :                         return pRet;
    1059             :                     }
    1060             : 
    1061          41 :                     VSI_TIFFSetCachedRanges(
    1062          41 :                         th, static_cast<int>(anSizes.size()), &apData[0],
    1063          41 :                         &anOffsets[0], &anSizes[0]);
    1064             :                 }
    1065             :             }
    1066             :         }
    1067             :     }
    1068         262 :     return pBufferedData;
    1069             : }
    1070             : 
    1071             : /************************************************************************/
    1072             : /*                       IGetDataCoverageStatus()                       */
    1073             : /************************************************************************/
    1074             : 
    1075         779 : int GTiffRasterBand::IGetDataCoverageStatus(int nXOff, int nYOff, int nXSize,
    1076             :                                             int nYSize, int nMaskFlagStop,
    1077             :                                             double *pdfDataPct)
    1078             : {
    1079         779 :     if (eAccess == GA_Update)
    1080          89 :         m_poGDS->FlushCache(false);
    1081             : 
    1082         779 :     const int iXBlockStart = nXOff / nBlockXSize;
    1083         779 :     const int iXBlockEnd = (nXOff + nXSize - 1) / nBlockXSize;
    1084         779 :     const int iYBlockStart = nYOff / nBlockYSize;
    1085         779 :     const int iYBlockEnd = (nYOff + nYSize - 1) / nBlockYSize;
    1086         779 :     int nStatus = 0;
    1087         779 :     VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_poGDS->m_hTIFF));
    1088         779 :     GIntBig nPixelsData = 0;
    1089        2377 :     for (int iY = iYBlockStart; iY <= iYBlockEnd; ++iY)
    1090             :     {
    1091        4187 :         for (int iX = iXBlockStart; iX <= iXBlockEnd; ++iX)
    1092             :         {
    1093        2589 :             const int nBlockIdBand0 = iX + iY * nBlocksPerRow;
    1094        2589 :             int nBlockId = nBlockIdBand0;
    1095        2589 :             if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1096         112 :                 nBlockId =
    1097         112 :                     nBlockIdBand0 + (nBand - 1) * m_poGDS->m_nBlocksPerBand;
    1098        2589 :             vsi_l_offset nOffset = 0;
    1099        2589 :             vsi_l_offset nLength = 0;
    1100        2589 :             bool bHasData = false;
    1101        2589 :             if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset, &nLength))
    1102             :             {
    1103        1866 :                 nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
    1104             :             }
    1105             :             else
    1106             :             {
    1107         723 :                 if (m_poGDS->m_nCompression == COMPRESSION_NONE &&
    1108         635 :                     m_poGDS->eAccess == GA_ReadOnly &&
    1109         599 :                     ((!m_bNoDataSet && !m_bNoDataSetAsInt64 &&
    1110         599 :                       !m_bNoDataSetAsUInt64) ||
    1111           0 :                      (m_bNoDataSet && m_dfNoDataValue == 0.0) ||
    1112           0 :                      (m_bNoDataSetAsInt64 && m_nNoDataValueInt64 == 0) ||
    1113           0 :                      (m_bNoDataSetAsUInt64 && m_nNoDataValueUInt64 == 0)))
    1114             :                 {
    1115             :                     VSIRangeStatus eStatus =
    1116         599 :                         VSIFGetRangeStatusL(fp, nOffset, nLength);
    1117         599 :                     if (eStatus == VSI_RANGE_STATUS_HOLE)
    1118             :                     {
    1119           0 :                         nStatus |= GDAL_DATA_COVERAGE_STATUS_EMPTY;
    1120             :                     }
    1121             :                     else
    1122             :                     {
    1123         599 :                         bHasData = true;
    1124         599 :                     }
    1125             :                 }
    1126             :                 else
    1127             :                 {
    1128         124 :                     bHasData = true;
    1129             :                 }
    1130             :             }
    1131        2589 :             if (bHasData)
    1132             :             {
    1133         723 :                 const int nXBlockRight =
    1134         723 :                     (iX * nBlockXSize > INT_MAX - nBlockXSize)
    1135         723 :                         ? INT_MAX
    1136         723 :                         : (iX + 1) * nBlockXSize;
    1137         723 :                 const int nYBlockBottom =
    1138         723 :                     (iY * nBlockYSize > INT_MAX - nBlockYSize)
    1139         723 :                         ? INT_MAX
    1140         723 :                         : (iY + 1) * nBlockYSize;
    1141             : 
    1142        1446 :                 nPixelsData += (static_cast<GIntBig>(
    1143         723 :                                     std::min(nXBlockRight, nXOff + nXSize)) -
    1144         723 :                                 std::max(iX * nBlockXSize, nXOff)) *
    1145         723 :                                (std::min(nYBlockBottom, nYOff + nYSize) -
    1146         723 :                                 std::max(iY * nBlockYSize, nYOff));
    1147         723 :                 nStatus |= GDAL_DATA_COVERAGE_STATUS_DATA;
    1148             :             }
    1149        2589 :             if (nMaskFlagStop != 0 && (nMaskFlagStop & nStatus) != 0)
    1150             :             {
    1151         717 :                 if (pdfDataPct)
    1152           0 :                     *pdfDataPct = -1.0;
    1153         717 :                 return nStatus;
    1154             :             }
    1155             :         }
    1156             :     }
    1157          62 :     if (pdfDataPct)
    1158           8 :         *pdfDataPct =
    1159           8 :             100.0 * nPixelsData / (static_cast<GIntBig>(nXSize) * nYSize);
    1160          62 :     return nStatus;
    1161             : }
    1162             : 
    1163             : /************************************************************************/
    1164             : /*                             IReadBlock()                             */
    1165             : /************************************************************************/
    1166             : 
    1167     2197610 : CPLErr GTiffRasterBand::IReadBlock(int nBlockXOff, int nBlockYOff, void *pImage)
    1168             : 
    1169             : {
    1170     2197610 :     m_poGDS->Crystalize();
    1171             : 
    1172     2197580 :     GPtrDiff_t nBlockBufSize = 0;
    1173     2197580 :     if (TIFFIsTiled(m_poGDS->m_hTIFF))
    1174             :     {
    1175       55647 :         nBlockBufSize = static_cast<GPtrDiff_t>(TIFFTileSize(m_poGDS->m_hTIFF));
    1176             :     }
    1177             :     else
    1178             :     {
    1179     2141960 :         CPLAssert(nBlockXOff == 0);
    1180             :         nBlockBufSize =
    1181     2141960 :             static_cast<GPtrDiff_t>(TIFFStripSize(m_poGDS->m_hTIFF));
    1182             :     }
    1183             : 
    1184     2197580 :     const int nBlockId = ComputeBlockId(nBlockXOff, nBlockYOff);
    1185             : 
    1186             :     /* -------------------------------------------------------------------- */
    1187             :     /*      The bottom most partial tiles and strips are sometimes only     */
    1188             :     /*      partially encoded.  This code reduces the requested data so     */
    1189             :     /*      an error won't be reported in this case. (#1179)                */
    1190             :     /* -------------------------------------------------------------------- */
    1191     2197590 :     auto nBlockReqSize = nBlockBufSize;
    1192             : 
    1193     2197590 :     if (nBlockYOff * nBlockYSize > nRasterYSize - nBlockYSize)
    1194             :     {
    1195        5950 :         nBlockReqSize =
    1196        5950 :             (nBlockBufSize / nBlockYSize) *
    1197        5950 :             (nBlockYSize -
    1198             :              static_cast<int>(
    1199        5950 :                  (static_cast<GIntBig>(nBlockYOff + 1) * nBlockYSize) %
    1200        5950 :                  nRasterYSize));
    1201             :     }
    1202             : 
    1203             :     /* -------------------------------------------------------------------- */
    1204             :     /*      Handle the case of a strip or tile that doesn't exist yet.      */
    1205             :     /*      Just set to zeros and return.                                   */
    1206             :     /* -------------------------------------------------------------------- */
    1207     2197590 :     vsi_l_offset nOffset = 0;
    1208     2197590 :     bool bErrOccurred = false;
    1209     4361910 :     if (nBlockId != m_poGDS->m_nLoadedBlock &&
    1210     2164310 :         !m_poGDS->IsBlockAvailable(nBlockId, &nOffset, nullptr, &bErrOccurred))
    1211             :     {
    1212       49284 :         NullBlock(pImage);
    1213       49284 :         if (bErrOccurred)
    1214           1 :             return CE_Failure;
    1215       49283 :         return CE_None;
    1216             :     }
    1217             : 
    1218     2148320 :     if (m_poGDS->m_bStreamingIn &&
    1219       10936 :         !(m_poGDS->nBands > 1 &&
    1220       10423 :           m_poGDS->m_nPlanarConfig == PLANARCONFIG_CONTIG &&
    1221       10048 :           nBlockId == m_poGDS->m_nLoadedBlock))
    1222             :     {
    1223        3436 :         if (nOffset < VSIFTellL(m_poGDS->m_fpL))
    1224             :         {
    1225        2000 :             ReportError(CE_Failure, CPLE_NotSupported,
    1226             :                         "Trying to load block %d at offset " CPL_FRMT_GUIB
    1227             :                         " whereas current pos is " CPL_FRMT_GUIB
    1228             :                         " (backward read not supported)",
    1229             :                         nBlockId, static_cast<GUIntBig>(nOffset),
    1230        1000 :                         static_cast<GUIntBig>(VSIFTellL(m_poGDS->m_fpL)));
    1231        1000 :             return CE_Failure;
    1232             :         }
    1233             :     }
    1234             : 
    1235             :     /* -------------------------------------------------------------------- */
    1236             :     /*      Handle simple case (separate, onesampleperpixel)                */
    1237             :     /* -------------------------------------------------------------------- */
    1238     2147320 :     CPLErr eErr = CE_None;
    1239     2147320 :     if (m_poGDS->nBands == 1 ||
    1240      104378 :         m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1241             :     {
    1242     2054440 :         if (nBlockReqSize < nBlockBufSize)
    1243        2306 :             memset(pImage, 0, nBlockBufSize);
    1244             : 
    1245     2054440 :         if (!m_poGDS->ReadStrile(nBlockId, pImage, nBlockReqSize))
    1246             :         {
    1247          61 :             memset(pImage, 0, nBlockBufSize);
    1248          61 :             return CE_Failure;
    1249             :         }
    1250             :     }
    1251             :     else
    1252             :     {
    1253             :         /* --------------------------------------------------------------------
    1254             :          */
    1255             :         /*      Load desired block */
    1256             :         /* --------------------------------------------------------------------
    1257             :          */
    1258       92877 :         eErr = m_poGDS->LoadBlockBuf(nBlockId);
    1259       92960 :         if (eErr != CE_None)
    1260             :         {
    1261          38 :             memset(pImage, 0,
    1262          76 :                    static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
    1263          38 :                        GDALGetDataTypeSizeBytes(eDataType));
    1264          38 :             return eErr;
    1265             :         }
    1266             : 
    1267       92922 :         bool bDoCopyWords = true;
    1268       61142 :         if (nBand == 1 && !m_poGDS->m_bLoadingOtherBands &&
    1269       55679 :             eAccess == GA_ReadOnly &&
    1270       47124 :             (m_poGDS->nBands == 3 || m_poGDS->nBands == 4) &&
    1271       46774 :             ((eDataType == GDT_Byte && m_poGDS->m_nBitsPerSample == 8) ||
    1272        1289 :              (eDataType == GDT_Int16 && m_poGDS->m_nBitsPerSample == 16) ||
    1273      154337 :              (eDataType == GDT_UInt16 && m_poGDS->m_nBitsPerSample == 16)) &&
    1274       92395 :             static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
    1275       46222 :                     GDALGetDataTypeSizeBytes(eDataType) <
    1276       46173 :                 GDALGetCacheMax64() / m_poGDS->nBands)
    1277             :         {
    1278       46153 :             bDoCopyWords = false;
    1279             :             void *ppDestBuffers[4];
    1280       46153 :             GDALRasterBlock *apoLockedBlocks[4] = {nullptr, nullptr, nullptr,
    1281             :                                                    nullptr};
    1282      195914 :             for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
    1283             :             {
    1284      149683 :                 if (iBand == nBand)
    1285             :                 {
    1286       46142 :                     ppDestBuffers[iBand - 1] = pImage;
    1287             :                 }
    1288             :                 else
    1289             :                 {
    1290             :                     GDALRasterBlock *poBlock =
    1291      103541 :                         m_poGDS->GetRasterBand(iBand)->GetLockedBlockRef(
    1292      103581 :                             nBlockXOff, nBlockYOff, true);
    1293      103624 :                     if (poBlock == nullptr)
    1294             :                     {
    1295           0 :                         bDoCopyWords = true;
    1296           0 :                         break;
    1297             :                     }
    1298      103624 :                     ppDestBuffers[iBand - 1] = poBlock->GetDataRef();
    1299      103619 :                     apoLockedBlocks[iBand - 1] = poBlock;
    1300             :                 }
    1301             :             }
    1302       46231 :             if (!bDoCopyWords)
    1303             :             {
    1304       46197 :                 GDALDeinterleave(m_poGDS->m_pabyBlockBuf, eDataType,
    1305       46197 :                                  m_poGDS->nBands, ppDestBuffers, eDataType,
    1306       46197 :                                  static_cast<size_t>(nBlockXSize) *
    1307       46197 :                                      nBlockYSize);
    1308             :             }
    1309      196055 :             for (int iBand = 1; iBand <= m_poGDS->nBands; ++iBand)
    1310             :             {
    1311      149853 :                 if (apoLockedBlocks[iBand - 1])
    1312             :                 {
    1313      103653 :                     apoLockedBlocks[iBand - 1]->DropLock();
    1314             :                 }
    1315             :             }
    1316             :         }
    1317             : 
    1318       92923 :         if (bDoCopyWords)
    1319             :         {
    1320       46725 :             const int nWordBytes = m_poGDS->m_nBitsPerSample / 8;
    1321       46725 :             GByte *pabyImage =
    1322       46725 :                 m_poGDS->m_pabyBlockBuf + (nBand - 1) * nWordBytes;
    1323             : 
    1324       46725 :             GDALCopyWords64(pabyImage, eDataType, m_poGDS->nBands * nWordBytes,
    1325             :                             pImage, eDataType, nWordBytes,
    1326       46725 :                             static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize);
    1327             : 
    1328       46725 :             eErr = FillCacheForOtherBands(nBlockXOff, nBlockYOff);
    1329             :         }
    1330             :     }
    1331             : 
    1332     2147260 :     CacheMaskForBlock(nBlockXOff, nBlockYOff);
    1333             : 
    1334     2147260 :     return eErr;
    1335             : }
    1336             : 
    1337             : /************************************************************************/
    1338             : /*                           CacheMaskForBlock()                       */
    1339             : /************************************************************************/
    1340             : 
    1341     2148150 : void GTiffRasterBand::CacheMaskForBlock(int nBlockXOff, int nBlockYOff)
    1342             : 
    1343             : {
    1344             :     // Preload mask data if layout compatible and we have cached ranges
    1345     2148260 :     if (m_poGDS->m_bMaskInterleavedWithImagery && m_poGDS->m_poMaskDS &&
    1346         109 :         VSI_TIFFHasCachedRanges(TIFFClientdata(m_poGDS->m_hTIFF)))
    1347             :     {
    1348          98 :         auto poBand = cpl::down_cast<GTiffRasterBand *>(
    1349          98 :             m_poGDS->m_poMaskDS->GetRasterBand(1));
    1350         294 :         if (m_poGDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount.contains(
    1351          98 :                 poBand->ComputeBlockId(nBlockXOff, nBlockYOff)))
    1352             :         {
    1353             :             GDALRasterBlock *poBlock =
    1354          94 :                 poBand->GetLockedBlockRef(nBlockXOff, nBlockYOff);
    1355          94 :             if (poBlock)
    1356          94 :                 poBlock->DropLock();
    1357             :         }
    1358             :     }
    1359     2148150 : }
    1360             : 
    1361             : /************************************************************************/
    1362             : /*                       FillCacheForOtherBands()                       */
    1363             : /************************************************************************/
    1364             : 
    1365       46939 : CPLErr GTiffRasterBand::FillCacheForOtherBands(int nBlockXOff, int nBlockYOff)
    1366             : 
    1367             : {
    1368             :     /* -------------------------------------------------------------------- */
    1369             :     /*      In the fairly common case of pixel interleaved 8bit data        */
    1370             :     /*      that is multi-band, lets push the rest of the data into the     */
    1371             :     /*      block cache too, to avoid (hopefully) having to redecode it.    */
    1372             :     /*                                                                      */
    1373             :     /*      Our following logic actually depends on the fact that the       */
    1374             :     /*      this block is already loaded, so subsequent calls will end      */
    1375             :     /*      up back in this method and pull from the loaded block.          */
    1376             :     /*                                                                      */
    1377             :     /*      Be careful not entering this portion of code from               */
    1378             :     /*      the other bands, otherwise we'll get very deep nested calls     */
    1379             :     /*      and O(nBands^2) performance !                                   */
    1380             :     /*                                                                      */
    1381             :     /*      If there are many bands and the block cache size is not big     */
    1382             :     /*      enough to accommodate the size of all the blocks, don't enter   */
    1383             :     /* -------------------------------------------------------------------- */
    1384       46939 :     CPLErr eErr = CE_None;
    1385      140817 :     if (m_poGDS->nBands != 1 &&
    1386       46939 :         m_poGDS->nBands <
    1387       46937 :             128 &&  // avoid caching for datasets with too many bands
    1388      105850 :         !m_poGDS->m_bLoadingOtherBands &&
    1389       23944 :         static_cast<GPtrDiff_t>(nBlockXSize) * nBlockYSize *
    1390       11972 :                 GDALGetDataTypeSizeBytes(eDataType) <
    1391       11972 :             GDALGetCacheMax64() / m_poGDS->nBands)
    1392             :     {
    1393       11972 :         m_poGDS->m_bLoadingOtherBands = true;
    1394             : 
    1395       49873 :         for (int iOtherBand = 1; iOtherBand <= m_poGDS->nBands; ++iOtherBand)
    1396             :         {
    1397       37901 :             if (iOtherBand == nBand)
    1398       11972 :                 continue;
    1399             : 
    1400             :             GDALRasterBlock *poBlock =
    1401       25929 :                 m_poGDS->GetRasterBand(iOtherBand)
    1402       25929 :                     ->GetLockedBlockRef(nBlockXOff, nBlockYOff);
    1403       25929 :             if (poBlock == nullptr)
    1404             :             {
    1405           0 :                 eErr = CE_Failure;
    1406           0 :                 break;
    1407             :             }
    1408       25929 :             poBlock->DropLock();
    1409             :         }
    1410             : 
    1411       11972 :         m_poGDS->m_bLoadingOtherBands = false;
    1412             :     }
    1413             : 
    1414       46939 :     return eErr;
    1415             : }
    1416             : 
    1417             : /************************************************************************/
    1418             : /*                           GetDescription()                           */
    1419             : /************************************************************************/
    1420             : 
    1421      205594 : const char *GTiffRasterBand::GetDescription() const
    1422             : {
    1423      205594 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1424             : 
    1425      205594 :     return m_osDescription;
    1426             : }
    1427             : 
    1428             : /************************************************************************/
    1429             : /*                             GetOffset()                              */
    1430             : /************************************************************************/
    1431             : 
    1432      212599 : double GTiffRasterBand::GetOffset(int *pbSuccess)
    1433             : 
    1434             : {
    1435      212599 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1436             : 
    1437      212599 :     if (pbSuccess)
    1438        6486 :         *pbSuccess = m_bHaveOffsetScale;
    1439      212599 :     return m_dfOffset;
    1440             : }
    1441             : 
    1442             : /************************************************************************/
    1443             : /*                              GetScale()                              */
    1444             : /************************************************************************/
    1445             : 
    1446      212600 : double GTiffRasterBand::GetScale(int *pbSuccess)
    1447             : 
    1448             : {
    1449      212600 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1450             : 
    1451      212600 :     if (pbSuccess)
    1452        6487 :         *pbSuccess = m_bHaveOffsetScale;
    1453      212600 :     return m_dfScale;
    1454             : }
    1455             : 
    1456             : /************************************************************************/
    1457             : /*                            GetUnitType()                             */
    1458             : /************************************************************************/
    1459             : 
    1460      204836 : const char *GTiffRasterBand::GetUnitType()
    1461             : 
    1462             : {
    1463      204836 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1464      204836 :     if (m_osUnitType.empty())
    1465             :     {
    1466      204757 :         m_poGDS->LookForProjection();
    1467      204757 :         if (m_poGDS->m_pszVertUnit)
    1468           9 :             return m_poGDS->m_pszVertUnit;
    1469             :     }
    1470             : 
    1471      204827 :     return m_osUnitType.c_str();
    1472             : }
    1473             : 
    1474             : /************************************************************************/
    1475             : /*                      GetMetadataDomainList()                         */
    1476             : /************************************************************************/
    1477             : 
    1478          12 : char **GTiffRasterBand::GetMetadataDomainList()
    1479             : {
    1480          12 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1481             : 
    1482          12 :     return CSLDuplicate(m_oGTiffMDMD.GetDomainList());
    1483             : }
    1484             : 
    1485             : /************************************************************************/
    1486             : /*                            GetMetadata()                             */
    1487             : /************************************************************************/
    1488             : 
    1489       15573 : char **GTiffRasterBand::GetMetadata(const char *pszDomain)
    1490             : 
    1491             : {
    1492       15573 :     if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
    1493             :     {
    1494       15416 :         m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1495             :     }
    1496             : 
    1497       15573 :     return m_oGTiffMDMD.GetMetadata(pszDomain);
    1498             : }
    1499             : 
    1500             : /************************************************************************/
    1501             : /*                          GetMetadataItem()                           */
    1502             : /************************************************************************/
    1503             : 
    1504       29850 : const char *GTiffRasterBand::GetMetadataItem(const char *pszName,
    1505             :                                              const char *pszDomain)
    1506             : 
    1507             : {
    1508       29850 :     if (pszDomain == nullptr || !EQUAL(pszDomain, "IMAGE_STRUCTURE"))
    1509             :     {
    1510        7036 :         m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1511             :     }
    1512             : 
    1513       29850 :     if (pszName != nullptr && pszDomain != nullptr && EQUAL(pszDomain, "TIFF"))
    1514             :     {
    1515        4196 :         int nBlockXOff = 0;
    1516        4196 :         int nBlockYOff = 0;
    1517             : 
    1518        4196 :         if (EQUAL(pszName, "JPEGTABLES"))
    1519             :         {
    1520          11 :             uint32_t nJPEGTableSize = 0;
    1521          11 :             void *pJPEGTable = nullptr;
    1522          11 :             if (TIFFGetField(m_poGDS->m_hTIFF, TIFFTAG_JPEGTABLES,
    1523          11 :                              &nJPEGTableSize, &pJPEGTable) != 1 ||
    1524          11 :                 pJPEGTable == nullptr || nJPEGTableSize > INT_MAX)
    1525             :             {
    1526           0 :                 return nullptr;
    1527             :             }
    1528          11 :             char *const pszHex = CPLBinaryToHex(
    1529             :                 nJPEGTableSize, static_cast<const GByte *>(pJPEGTable));
    1530          11 :             const char *pszReturn = CPLSPrintf("%s", pszHex);
    1531          11 :             CPLFree(pszHex);
    1532             : 
    1533          11 :             return pszReturn;
    1534             :         }
    1535             : 
    1536        4185 :         if (EQUAL(pszName, "IFD_OFFSET"))
    1537             :         {
    1538         158 :             return CPLSPrintf(CPL_FRMT_GUIB,
    1539          79 :                               static_cast<GUIntBig>(m_poGDS->m_nDirOffset));
    1540             :         }
    1541             : 
    1542        4106 :         if (sscanf(pszName, "BLOCK_OFFSET_%d_%d", &nBlockXOff, &nBlockYOff) ==
    1543             :             2)
    1544             :         {
    1545        3687 :             if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
    1546        3686 :                 nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
    1547          19 :                 return nullptr;
    1548             : 
    1549        3668 :             int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
    1550        3668 :             if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1551             :             {
    1552        2870 :                 nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
    1553             :             }
    1554             : 
    1555        3668 :             vsi_l_offset nOffset = 0;
    1556        3668 :             if (!m_poGDS->IsBlockAvailable(nBlockId, &nOffset))
    1557             :             {
    1558         190 :                 return nullptr;
    1559             :             }
    1560             : 
    1561        3478 :             return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nOffset));
    1562             :         }
    1563             : 
    1564         419 :         if (sscanf(pszName, "BLOCK_SIZE_%d_%d", &nBlockXOff, &nBlockYOff) == 2)
    1565             :         {
    1566         419 :             if (nBlockXOff < 0 || nBlockXOff >= nBlocksPerRow ||
    1567         418 :                 nBlockYOff < 0 || nBlockYOff >= nBlocksPerColumn)
    1568           2 :                 return nullptr;
    1569             : 
    1570         417 :             int nBlockId = nBlockYOff * nBlocksPerRow + nBlockXOff;
    1571         417 :             if (m_poGDS->m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1572             :             {
    1573           1 :                 nBlockId += (nBand - 1) * m_poGDS->m_nBlocksPerBand;
    1574             :             }
    1575             : 
    1576         417 :             vsi_l_offset nByteCount = 0;
    1577         417 :             if (!m_poGDS->IsBlockAvailable(nBlockId, nullptr, &nByteCount))
    1578             :             {
    1579          89 :                 return nullptr;
    1580             :             }
    1581             : 
    1582         328 :             return CPLSPrintf(CPL_FRMT_GUIB, static_cast<GUIntBig>(nByteCount));
    1583           0 :         }
    1584             :     }
    1585       25654 :     else if (pszName && pszDomain && EQUAL(pszDomain, "_DEBUG_"))
    1586             :     {
    1587         131 :         if (EQUAL(pszName, "HAS_BLOCK_CACHE"))
    1588         131 :             return HasBlockCache() ? "1" : "0";
    1589             :     }
    1590             : 
    1591       25523 :     const char *pszRet = m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
    1592             : 
    1593       25523 :     if (pszRet == nullptr && eDataType == GDT_Byte && pszName && pszDomain &&
    1594       23312 :         EQUAL(pszDomain, "IMAGE_STRUCTURE") && EQUAL(pszName, "PIXELTYPE"))
    1595             :     {
    1596             :         // to get a chance of emitting the warning about this legacy usage
    1597        5158 :         pszRet = GDALRasterBand::GetMetadataItem(pszName, pszDomain);
    1598             :     }
    1599       25523 :     return pszRet;
    1600             : }
    1601             : 
    1602             : /************************************************************************/
    1603             : /*                       GetColorInterpretation()                       */
    1604             : /************************************************************************/
    1605             : 
    1606      225081 : GDALColorInterp GTiffRasterBand::GetColorInterpretation()
    1607             : 
    1608             : {
    1609      225081 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1610             : 
    1611      225081 :     return m_eBandInterp;
    1612             : }
    1613             : 
    1614             : /************************************************************************/
    1615             : /*                           GetColorTable()                            */
    1616             : /************************************************************************/
    1617             : 
    1618       11282 : GDALColorTable *GTiffRasterBand::GetColorTable()
    1619             : 
    1620             : {
    1621       11282 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1622             : 
    1623       11282 :     if (nBand == 1)
    1624        9579 :         return m_poGDS->m_poColorTable.get();
    1625             : 
    1626        1703 :     return nullptr;
    1627             : }
    1628             : 
    1629             : /************************************************************************/
    1630             : /*                           GetNoDataValue()                           */
    1631             : /************************************************************************/
    1632             : 
    1633      815278 : double GTiffRasterBand::GetNoDataValue(int *pbSuccess)
    1634             : 
    1635             : {
    1636      815278 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1637             : 
    1638      815310 :     int bSuccess = FALSE;
    1639      815310 :     double dfNoDataValue = GDALPamRasterBand::GetNoDataValue(&bSuccess);
    1640      813504 :     if (bSuccess)
    1641             :     {
    1642           4 :         if (pbSuccess)
    1643           4 :             *pbSuccess = TRUE;
    1644             : 
    1645           4 :         return dfNoDataValue;
    1646             :     }
    1647             : 
    1648      813500 :     if (m_bNoDataSet)
    1649             :     {
    1650        2243 :         if (pbSuccess)
    1651        2210 :             *pbSuccess = TRUE;
    1652             : 
    1653        2243 :         return m_dfNoDataValue;
    1654             :     }
    1655             : 
    1656      811257 :     if (m_poGDS->m_bNoDataSet)
    1657             :     {
    1658      422828 :         if (pbSuccess)
    1659      422690 :             *pbSuccess = TRUE;
    1660             : 
    1661      422828 :         return m_poGDS->m_dfNoDataValue;
    1662             :     }
    1663             : 
    1664      388429 :     if (m_bNoDataSetAsInt64)
    1665             :     {
    1666           0 :         if (pbSuccess)
    1667           0 :             *pbSuccess = TRUE;
    1668             : 
    1669           0 :         return GDALGetNoDataValueCastToDouble(m_nNoDataValueInt64);
    1670             :     }
    1671             : 
    1672      388429 :     if (m_poGDS->m_bNoDataSetAsInt64)
    1673             :     {
    1674           0 :         if (pbSuccess)
    1675           0 :             *pbSuccess = TRUE;
    1676             : 
    1677           0 :         return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueInt64);
    1678             :     }
    1679             : 
    1680      388429 :     if (m_bNoDataSetAsUInt64)
    1681             :     {
    1682           0 :         if (pbSuccess)
    1683           0 :             *pbSuccess = TRUE;
    1684             : 
    1685           0 :         return GDALGetNoDataValueCastToDouble(m_nNoDataValueUInt64);
    1686             :     }
    1687             : 
    1688      388429 :     if (m_poGDS->m_bNoDataSetAsUInt64)
    1689             :     {
    1690           0 :         if (pbSuccess)
    1691           0 :             *pbSuccess = TRUE;
    1692             : 
    1693           0 :         return GDALGetNoDataValueCastToDouble(m_poGDS->m_nNoDataValueUInt64);
    1694             :     }
    1695             : 
    1696      388429 :     if (pbSuccess)
    1697      389848 :         *pbSuccess = FALSE;
    1698      388429 :     return dfNoDataValue;
    1699             : }
    1700             : 
    1701             : /************************************************************************/
    1702             : /*                       GetNoDataValueAsInt64()                        */
    1703             : /************************************************************************/
    1704             : 
    1705          25 : int64_t GTiffRasterBand::GetNoDataValueAsInt64(int *pbSuccess)
    1706             : 
    1707             : {
    1708          25 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1709             : 
    1710          25 :     if (eDataType == GDT_UInt64)
    1711             :     {
    1712           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1713             :                  "GetNoDataValueAsUInt64() should be called instead");
    1714           0 :         if (pbSuccess)
    1715           0 :             *pbSuccess = FALSE;
    1716           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
    1717             :     }
    1718          25 :     if (eDataType != GDT_Int64)
    1719             :     {
    1720           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1721             :                  "GetNoDataValue() should be called instead");
    1722           0 :         if (pbSuccess)
    1723           0 :             *pbSuccess = FALSE;
    1724           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_INT64;
    1725             :     }
    1726             : 
    1727          25 :     int bSuccess = FALSE;
    1728             :     const auto nNoDataValue =
    1729          25 :         GDALPamRasterBand::GetNoDataValueAsInt64(&bSuccess);
    1730          25 :     if (bSuccess)
    1731             :     {
    1732           0 :         if (pbSuccess)
    1733           0 :             *pbSuccess = TRUE;
    1734             : 
    1735           0 :         return nNoDataValue;
    1736             :     }
    1737             : 
    1738          25 :     if (m_bNoDataSetAsInt64)
    1739             :     {
    1740           2 :         if (pbSuccess)
    1741           2 :             *pbSuccess = TRUE;
    1742             : 
    1743           2 :         return m_nNoDataValueInt64;
    1744             :     }
    1745             : 
    1746          23 :     if (m_poGDS->m_bNoDataSetAsInt64)
    1747             :     {
    1748           7 :         if (pbSuccess)
    1749           6 :             *pbSuccess = TRUE;
    1750             : 
    1751           7 :         return m_poGDS->m_nNoDataValueInt64;
    1752             :     }
    1753             : 
    1754          16 :     if (pbSuccess)
    1755          16 :         *pbSuccess = FALSE;
    1756          16 :     return nNoDataValue;
    1757             : }
    1758             : 
    1759             : /************************************************************************/
    1760             : /*                      GetNoDataValueAsUInt64()                        */
    1761             : /************************************************************************/
    1762             : 
    1763          16 : uint64_t GTiffRasterBand::GetNoDataValueAsUInt64(int *pbSuccess)
    1764             : 
    1765             : {
    1766          16 :     m_poGDS->LoadGeoreferencingAndPamIfNeeded();
    1767             : 
    1768          16 :     if (eDataType == GDT_Int64)
    1769             :     {
    1770           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1771             :                  "GetNoDataValueAsInt64() should be called instead");
    1772           0 :         if (pbSuccess)
    1773           0 :             *pbSuccess = FALSE;
    1774           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
    1775             :     }
    1776          16 :     if (eDataType != GDT_UInt64)
    1777             :     {
    1778           0 :         CPLError(CE_Failure, CPLE_AppDefined,
    1779             :                  "GetNoDataValue() should be called instead");
    1780           0 :         if (pbSuccess)
    1781           0 :             *pbSuccess = FALSE;
    1782           0 :         return GDAL_PAM_DEFAULT_NODATA_VALUE_UINT64;
    1783             :     }
    1784             : 
    1785          16 :     int bSuccess = FALSE;
    1786             :     const auto nNoDataValue =
    1787          16 :         GDALPamRasterBand::GetNoDataValueAsUInt64(&bSuccess);
    1788          16 :     if (bSuccess)
    1789             :     {
    1790           0 :         if (pbSuccess)
    1791           0 :             *pbSuccess = TRUE;
    1792             : 
    1793           0 :         return nNoDataValue;
    1794             :     }
    1795             : 
    1796          16 :     if (m_bNoDataSetAsUInt64)
    1797             :     {
    1798           0 :         if (pbSuccess)
    1799           0 :             *pbSuccess = TRUE;
    1800             : 
    1801           0 :         return m_nNoDataValueUInt64;
    1802             :     }
    1803             : 
    1804          16 :     if (m_poGDS->m_bNoDataSetAsUInt64)
    1805             :     {
    1806           7 :         if (pbSuccess)
    1807           6 :             *pbSuccess = TRUE;
    1808             : 
    1809           7 :         return m_poGDS->m_nNoDataValueUInt64;
    1810             :     }
    1811             : 
    1812           9 :     if (pbSuccess)
    1813           9 :         *pbSuccess = FALSE;
    1814           9 :     return nNoDataValue;
    1815             : }
    1816             : 
    1817             : /************************************************************************/
    1818             : /*                          GetOverviewCount()                          */
    1819             : /************************************************************************/
    1820             : 
    1821      655192 : int GTiffRasterBand::GetOverviewCount()
    1822             : 
    1823             : {
    1824      655192 :     if (!m_poGDS->AreOverviewsEnabled())
    1825          30 :         return 0;
    1826             : 
    1827      655162 :     m_poGDS->ScanDirectories();
    1828             : 
    1829      655162 :     if (m_poGDS->m_nOverviewCount > 0)
    1830             :     {
    1831        4751 :         return m_poGDS->m_nOverviewCount;
    1832             :     }
    1833             : 
    1834      650411 :     const int nOverviewCount = GDALRasterBand::GetOverviewCount();
    1835      650411 :     if (nOverviewCount > 0)
    1836         368 :         return nOverviewCount;
    1837             : 
    1838             :     // Implicit JPEG overviews are normally hidden, except when doing
    1839             :     // IRasterIO() operations.
    1840      650043 :     if (m_poGDS->m_nJPEGOverviewVisibilityCounter)
    1841      643415 :         return m_poGDS->GetJPEGOverviewCount();
    1842             : 
    1843        6628 :     return 0;
    1844             : }
    1845             : 
    1846             : /************************************************************************/
    1847             : /*                            GetOverview()                             */
    1848             : /************************************************************************/
    1849             : 
    1850        8305 : GDALRasterBand *GTiffRasterBand::GetOverview(int i)
    1851             : 
    1852             : {
    1853        8305 :     m_poGDS->ScanDirectories();
    1854             : 
    1855        8305 :     if (m_poGDS->m_nOverviewCount > 0)
    1856             :     {
    1857             :         // Do we have internal overviews?
    1858        7736 :         if (i < 0 || i >= m_poGDS->m_nOverviewCount)
    1859           8 :             return nullptr;
    1860             : 
    1861        7728 :         return m_poGDS->m_papoOverviewDS[i]->GetRasterBand(nBand);
    1862             :     }
    1863             : 
    1864         569 :     GDALRasterBand *const poOvrBand = GDALRasterBand::GetOverview(i);
    1865         569 :     if (poOvrBand != nullptr)
    1866         366 :         return poOvrBand;
    1867             : 
    1868             :     // For consistency with GetOverviewCount(), we should also test
    1869             :     // m_nJPEGOverviewVisibilityCounter, but it is also convenient to be able
    1870             :     // to query them for testing purposes.
    1871         203 :     if (i >= 0 && i < m_poGDS->GetJPEGOverviewCount())
    1872         164 :         return m_poGDS->m_papoJPEGOverviewDS[i]->GetRasterBand(nBand);
    1873             : 
    1874          39 :     return nullptr;
    1875             : }
    1876             : 
    1877             : /************************************************************************/
    1878             : /*                           GetMaskFlags()                             */
    1879             : /************************************************************************/
    1880             : 
    1881       17985 : int GTiffRasterBand::GetMaskFlags()
    1882             : {
    1883       17985 :     m_poGDS->ScanDirectories();
    1884             : 
    1885       17985 :     if (m_poGDS->m_poExternalMaskDS != nullptr)
    1886             :     {
    1887           0 :         return GMF_PER_DATASET;
    1888             :     }
    1889             : 
    1890       17985 :     if (m_poGDS->m_poMaskDS != nullptr)
    1891             :     {
    1892         163 :         if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
    1893             :         {
    1894         156 :             return GMF_PER_DATASET;
    1895             :         }
    1896             : 
    1897           7 :         return 0;
    1898             :     }
    1899             : 
    1900       17822 :     if (m_poGDS->m_bIsOverview)
    1901             :     {
    1902         379 :         return m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskFlags();
    1903             :     }
    1904             : 
    1905       17443 :     return GDALPamRasterBand::GetMaskFlags();
    1906             : }
    1907             : 
    1908             : /************************************************************************/
    1909             : /*                            GetMaskBand()                             */
    1910             : /************************************************************************/
    1911             : 
    1912      119604 : GDALRasterBand *GTiffRasterBand::GetMaskBand()
    1913             : {
    1914      119604 :     m_poGDS->ScanDirectories();
    1915             : 
    1916      119644 :     if (m_poGDS->m_poExternalMaskDS != nullptr)
    1917             :     {
    1918        2842 :         return m_poGDS->m_poExternalMaskDS->GetRasterBand(1);
    1919             :     }
    1920             : 
    1921      116802 :     if (m_poGDS->m_poMaskDS != nullptr)
    1922             :     {
    1923         555 :         if (m_poGDS->m_poMaskDS->GetRasterCount() == 1)
    1924         541 :             return m_poGDS->m_poMaskDS->GetRasterBand(1);
    1925             : 
    1926          14 :         return m_poGDS->m_poMaskDS->GetRasterBand(nBand);
    1927             :     }
    1928             : 
    1929      116247 :     if (m_poGDS->m_bIsOverview)
    1930             :     {
    1931             :         GDALRasterBand *poBaseMask =
    1932         114 :             m_poGDS->m_poBaseDS->GetRasterBand(nBand)->GetMaskBand();
    1933         114 :         if (poBaseMask)
    1934             :         {
    1935         114 :             const int nOverviews = poBaseMask->GetOverviewCount();
    1936         159 :             for (int i = 0; i < nOverviews; i++)
    1937             :             {
    1938          93 :                 GDALRasterBand *poOvr = poBaseMask->GetOverview(i);
    1939         141 :                 if (poOvr && poOvr->GetXSize() == GetXSize() &&
    1940          48 :                     poOvr->GetYSize() == GetYSize())
    1941             :                 {
    1942          48 :                     return poOvr;
    1943             :                 }
    1944             :             }
    1945             :         }
    1946             :     }
    1947             : 
    1948      116199 :     return GDALPamRasterBand::GetMaskBand();
    1949             : }
    1950             : 
    1951             : /************************************************************************/
    1952             : /*                            IsMaskBand()                              */
    1953             : /************************************************************************/
    1954             : 
    1955        9078 : bool GTiffRasterBand::IsMaskBand() const
    1956             : {
    1957        9109 :     return (m_poGDS->m_poImageryDS != nullptr &&
    1958          31 :             m_poGDS->m_poImageryDS->m_poMaskDS == m_poGDS) ||
    1959       16077 :            m_eBandInterp == GCI_AlphaBand ||
    1960       16046 :            m_poGDS->GetMetadataItem("INTERNAL_MASK_FLAGS_1") != nullptr;
    1961             : }
    1962             : 
    1963             : /************************************************************************/
    1964             : /*                         GetMaskValueRange()                          */
    1965             : /************************************************************************/
    1966             : 
    1967           0 : GDALMaskValueRange GTiffRasterBand::GetMaskValueRange() const
    1968             : {
    1969           0 :     if (!IsMaskBand())
    1970           0 :         return GMVR_UNKNOWN;
    1971           0 :     if (m_poGDS->m_nBitsPerSample == 1)
    1972           0 :         return m_poGDS->m_bPromoteTo8Bits ? GMVR_0_AND_255_ONLY
    1973           0 :                                           : GMVR_0_AND_1_ONLY;
    1974           0 :     return GMVR_UNKNOWN;
    1975             : }

Generated by: LCOV version 1.14