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

Generated by: LCOV version 1.14