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

Generated by: LCOV version 1.14