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

Generated by: LCOV version 1.14