LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffrasterband_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 640 727 88.0 %
Date: 2025-05-31 00:00:17 Functions: 28 29 96.6 %

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

Generated by: LCOV version 1.14