LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3314 3614 91.7 %
Date: 2026-03-19 04:40:40 Functions: 57 57 100.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  Read/get operations on GTiffDataset
       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 "gtiffdataset.h"
      15             : #include "gtiffrasterband.h"
      16             : #include "gtiffjpegoverviewds.h"
      17             : #include "gtiffrgbaband.h"
      18             : #include "gtiffbitmapband.h"
      19             : #include "gtiffsplitband.h"
      20             : #include "gtiffsplitbitmapband.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <cassert>
      24             : #include <limits>
      25             : #include <memory>
      26             : #include <mutex>
      27             : #include <set>
      28             : #include <string>
      29             : #include <queue>
      30             : #include <tuple>
      31             : #include <utility>
      32             : 
      33             : #include "cpl_error.h"
      34             : #include "cpl_error_internal.h"  // CPLErrorHandlerAccumulatorStruct
      35             : #include "cpl_vsi.h"
      36             : #include "cpl_vsi_virtual.h"
      37             : #include "cpl_worker_thread_pool.h"
      38             : #include "fetchbufferdirectio.h"
      39             : #include "gdal_mdreader.h"  // MD_DOMAIN_RPC
      40             : #include "gdal_priv.h"
      41             : #include "geovalues.h"        // RasterPixelIsPoint
      42             : #include "gt_wkt_srs_priv.h"  // GDALGTIFKeyGetSHORT()
      43             : #include "tif_jxl.h"
      44             : #include "tifvsi.h"
      45             : #include "xtiffio.h"
      46             : 
      47             : #include "tiff_common.h"
      48             : 
      49             : /************************************************************************/
      50             : /*                        GetJPEGOverviewCount()                        */
      51             : /************************************************************************/
      52             : 
      53     1044380 : int GTiffDataset::GetJPEGOverviewCount()
      54             : {
      55     1044380 :     if (!m_apoJPEGOverviewDS.empty())
      56         170 :         return static_cast<int>(m_apoJPEGOverviewDS.size());
      57             : 
      58      643494 :     if (m_poBaseDS || eAccess != GA_ReadOnly ||
      59       28830 :         m_nCompression != COMPRESSION_JPEG ||
      60          22 :         (nRasterXSize < 256 && nRasterYSize < 256) ||
      61     1687730 :         !CPLTestBool(CPLGetConfigOption("GTIFF_IMPLICIT_JPEG_OVR", "YES")) ||
      62          22 :         GDALGetDriverByName("JPEG") == nullptr)
      63             :     {
      64     1044190 :         return 0;
      65             :     }
      66             :     const char *pszSourceColorSpace =
      67          22 :         m_oGTiffMDMD.GetMetadataItem("SOURCE_COLOR_SPACE", "IMAGE_STRUCTURE");
      68          22 :     if (pszSourceColorSpace != nullptr && EQUAL(pszSourceColorSpace, "CMYK"))
      69             :     {
      70             :         // We cannot handle implicit overviews on JPEG CMYK datasets converted
      71             :         // to RGBA This would imply doing the conversion in
      72             :         // GTiffJPEGOverviewBand.
      73           1 :         return 0;
      74             :     }
      75             : 
      76             :     // libjpeg-6b only supports 2, 4 and 8 scale denominators.
      77             :     // TODO: Later versions support more.
      78          21 :     int nJPEGOverviewCount = 0;
      79          24 :     for (signed char i = 2; i >= 0; i--)
      80             :     {
      81          24 :         if (nRasterXSize >= (256 << i) || nRasterYSize >= (256 << i))
      82             :         {
      83          21 :             nJPEGOverviewCount = i + 1;
      84          21 :             break;
      85             :         }
      86             :     }
      87          21 :     if (nJPEGOverviewCount == 0)
      88           0 :         return 0;
      89             : 
      90             :     // Get JPEG tables.
      91          21 :     uint32_t nJPEGTableSize = 0;
      92          21 :     void *pJPEGTable = nullptr;
      93          21 :     GByte abyFFD8[] = {0xFF, 0xD8};
      94          21 :     if (TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &nJPEGTableSize, &pJPEGTable))
      95             :     {
      96          20 :         if (pJPEGTable == nullptr || nJPEGTableSize < 2 ||
      97          20 :             nJPEGTableSize > INT_MAX ||
      98          20 :             static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 1] != 0xD9)
      99             :         {
     100           0 :             return 0;
     101             :         }
     102          20 :         nJPEGTableSize--;  // Remove final 0xD9.
     103             :     }
     104             :     else
     105             :     {
     106           1 :         pJPEGTable = abyFFD8;
     107           1 :         nJPEGTableSize = 2;
     108             :     }
     109             : 
     110          81 :     for (int i = 0; i < nJPEGOverviewCount; ++i)
     111             :     {
     112          60 :         m_apoJPEGOverviewDS.emplace_back(std::make_unique<GTiffJPEGOverviewDS>(
     113         120 :             this, i + 1, pJPEGTable, static_cast<int>(nJPEGTableSize)));
     114             :     }
     115             : 
     116          21 :     return nJPEGOverviewCount;
     117             : }
     118             : 
     119             : /************************************************************************/
     120             : /*                       GetCompressionFormats()                        */
     121             : /************************************************************************/
     122             : 
     123           6 : CPLStringList GTiffDataset::GetCompressionFormats(int nXOff, int nYOff,
     124             :                                                   int nXSize, int nYSize,
     125             :                                                   int nBandCount,
     126             :                                                   const int *panBandList)
     127             : {
     128          18 :     if (m_nCompression != COMPRESSION_NONE &&
     129          11 :         IsWholeBlock(nXOff, nYOff, nXSize, nYSize) &&
     130           3 :         ((nBandCount == 1 && (panBandList || nBands == 1) &&
     131           3 :           m_nPlanarConfig == PLANARCONFIG_SEPARATE) ||
     132           5 :          (IsAllBands(nBandCount, panBandList) &&
     133           3 :           m_nPlanarConfig == PLANARCONFIG_CONTIG)))
     134             :     {
     135           6 :         CPLStringList aosList;
     136           3 :         int nBlockId =
     137           3 :             (nXOff / m_nBlockXSize) + (nYOff / m_nBlockYSize) * m_nBlocksPerRow;
     138           3 :         if (m_nPlanarConfig == PLANARCONFIG_SEPARATE && panBandList != nullptr)
     139           0 :             nBlockId += panBandList[0] * m_nBlocksPerBand;
     140             : 
     141           3 :         vsi_l_offset nOffset = 0;
     142           3 :         vsi_l_offset nSize = 0;
     143           6 :         if (IsBlockAvailable(nBlockId, &nOffset, &nSize, nullptr) &&
     144           3 :             nSize <
     145           3 :                 static_cast<vsi_l_offset>(std::numeric_limits<tmsize_t>::max()))
     146             :         {
     147           3 :             switch (m_nCompression)
     148             :             {
     149           3 :                 case COMPRESSION_JPEG:
     150             :                 {
     151           3 :                     if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands == 4 &&
     152           7 :                         m_nPhotometric == PHOTOMETRIC_RGB &&
     153           1 :                         GetRasterBand(4)->GetColorInterpretation() ==
     154             :                             GCI_AlphaBand)
     155             :                     {
     156             :                         // as a hint for the JPEG and JPEGXL drivers to not use it!
     157           1 :                         aosList.AddString("JPEG;colorspace=RGBA");
     158             :                     }
     159             :                     else
     160             :                     {
     161           2 :                         aosList.AddString("JPEG");
     162             :                     }
     163           3 :                     break;
     164             :                 }
     165             : 
     166           0 :                 case COMPRESSION_WEBP:
     167           0 :                     aosList.AddString("WEBP");
     168           0 :                     break;
     169             : 
     170           0 :                 case COMPRESSION_JXL:
     171           0 :                     aosList.AddString("JXL");
     172           0 :                     break;
     173             : 
     174           0 :                 default:
     175           0 :                     break;
     176             :             }
     177             :         }
     178           3 :         return aosList;
     179             :     }
     180           3 :     return CPLStringList();
     181             : }
     182             : 
     183             : /************************************************************************/
     184             : /*                         ReadCompressedData()                         */
     185             : /************************************************************************/
     186             : 
     187          80 : CPLErr GTiffDataset::ReadCompressedData(const char *pszFormat, int nXOff,
     188             :                                         int nYOff, int nXSize, int nYSize,
     189             :                                         int nBandCount, const int *panBandList,
     190             :                                         void **ppBuffer, size_t *pnBufferSize,
     191             :                                         char **ppszDetailedFormat)
     192             : {
     193         185 :     if (m_nCompression != COMPRESSION_NONE &&
     194         104 :         IsWholeBlock(nXOff, nYOff, nXSize, nYSize) &&
     195           8 :         ((nBandCount == 1 && (panBandList != nullptr || nBands == 1) &&
     196           8 :           m_nPlanarConfig == PLANARCONFIG_SEPARATE) ||
     197          24 :          (IsAllBands(nBandCount, panBandList) &&
     198          24 :           m_nPlanarConfig == PLANARCONFIG_CONTIG)))
     199             :     {
     200          12 :         const CPLStringList aosTokens(CSLTokenizeString2(pszFormat, ";", 0));
     201          12 :         if (aosTokens.size() != 1)
     202           0 :             return CE_Failure;
     203             : 
     204             :         // We don't want to handle CMYK JPEG for now
     205          35 :         if ((m_nCompression == COMPRESSION_JPEG &&
     206          11 :              EQUAL(aosTokens[0], "JPEG") &&
     207          10 :              (m_nPlanarConfig == PLANARCONFIG_SEPARATE ||
     208          10 :               m_nPhotometric != PHOTOMETRIC_SEPARATED)) ||
     209           2 :             (m_nCompression == COMPRESSION_WEBP &&
     210          24 :              EQUAL(aosTokens[0], "WEBP")) ||
     211           2 :             ((m_nCompression == COMPRESSION_JXL ||
     212           2 :               m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
     213           1 :              EQUAL(aosTokens[0], "JXL")))
     214             :         {
     215          11 :             std::string osDetailedFormat = aosTokens[0];
     216             : 
     217          11 :             int nBlockId = (nXOff / m_nBlockXSize) +
     218          11 :                            (nYOff / m_nBlockYSize) * m_nBlocksPerRow;
     219          11 :             if (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
     220             :                 panBandList != nullptr)
     221           0 :                 nBlockId += panBandList[0] * m_nBlocksPerBand;
     222             : 
     223          11 :             vsi_l_offset nOffset = 0;
     224          11 :             vsi_l_offset nSize = 0;
     225          22 :             if (IsBlockAvailable(nBlockId, &nOffset, &nSize, nullptr) &&
     226          11 :                 nSize < static_cast<vsi_l_offset>(
     227          11 :                             std::numeric_limits<tmsize_t>::max()))
     228             :             {
     229          11 :                 uint32_t nJPEGTableSize = 0;
     230          11 :                 void *pJPEGTable = nullptr;
     231          11 :                 if (m_nCompression == COMPRESSION_JPEG)
     232             :                 {
     233          10 :                     if (TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES,
     234          10 :                                      &nJPEGTableSize, &pJPEGTable) &&
     235          10 :                         pJPEGTable != nullptr && nJPEGTableSize > 4 &&
     236          10 :                         static_cast<GByte *>(pJPEGTable)[0] == 0xFF &&
     237          10 :                         static_cast<GByte *>(pJPEGTable)[1] == 0xD8 &&
     238          10 :                         static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 2] ==
     239          20 :                             0xFF &&
     240          10 :                         static_cast<GByte *>(pJPEGTable)[nJPEGTableSize - 1] ==
     241             :                             0xD9)
     242             :                     {
     243          10 :                         pJPEGTable = static_cast<GByte *>(pJPEGTable) + 2;
     244          10 :                         nJPEGTableSize -= 4;
     245             :                     }
     246             :                     else
     247             :                     {
     248           0 :                         nJPEGTableSize = 0;
     249             :                     }
     250             :                 }
     251             : 
     252          11 :                 size_t nSizeSize = static_cast<size_t>(nSize + nJPEGTableSize);
     253          11 :                 if (ppBuffer)
     254             :                 {
     255           9 :                     if (!pnBufferSize)
     256           1 :                         return CE_Failure;
     257           8 :                     bool bFreeOnError = false;
     258           8 :                     if (*ppBuffer)
     259             :                     {
     260           3 :                         if (*pnBufferSize < nSizeSize)
     261           1 :                             return CE_Failure;
     262             :                     }
     263             :                     else
     264             :                     {
     265           5 :                         *ppBuffer = VSI_MALLOC_VERBOSE(nSizeSize);
     266           5 :                         if (*ppBuffer == nullptr)
     267           0 :                             return CE_Failure;
     268           5 :                         bFreeOnError = true;
     269             :                     }
     270           7 :                     const auto nTileSize = static_cast<tmsize_t>(nSize);
     271             :                     bool bOK;
     272           7 :                     if (TIFFIsTiled(m_hTIFF))
     273             :                     {
     274           3 :                         bOK = TIFFReadRawTile(m_hTIFF, nBlockId, *ppBuffer,
     275             :                                               nTileSize) == nTileSize;
     276             :                     }
     277             :                     else
     278             :                     {
     279           4 :                         bOK = TIFFReadRawStrip(m_hTIFF, nBlockId, *ppBuffer,
     280             :                                                nTileSize) == nTileSize;
     281             :                     }
     282           7 :                     if (!bOK)
     283             :                     {
     284           0 :                         if (bFreeOnError)
     285             :                         {
     286           0 :                             VSIFree(*ppBuffer);
     287           0 :                             *ppBuffer = nullptr;
     288             :                         }
     289           0 :                         return CE_Failure;
     290             :                     }
     291           7 :                     if (nJPEGTableSize > 0)
     292             :                     {
     293           6 :                         GByte *pabyBuffer = static_cast<GByte *>(*ppBuffer);
     294           6 :                         memmove(pabyBuffer + 2 + nJPEGTableSize, pabyBuffer + 2,
     295           6 :                                 static_cast<size_t>(nSize) - 2);
     296           6 :                         memcpy(pabyBuffer + 2, pJPEGTable, nJPEGTableSize);
     297             :                     }
     298             : 
     299           7 :                     if (m_nCompression == COMPRESSION_JPEG)
     300             :                     {
     301          12 :                         osDetailedFormat = GDALGetCompressionFormatForJPEG(
     302           6 :                             *ppBuffer, nSizeSize);
     303             :                         const CPLStringList aosTokens2(CSLTokenizeString2(
     304          12 :                             osDetailedFormat.c_str(), ";", 0));
     305          18 :                         if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
     306           7 :                             nBands == 4 && m_nPhotometric == PHOTOMETRIC_RGB &&
     307           1 :                             GetRasterBand(4)->GetColorInterpretation() ==
     308             :                                 GCI_AlphaBand)
     309             :                         {
     310           1 :                             osDetailedFormat = aosTokens2[0];
     311           5 :                             for (int i = 1; i < aosTokens2.size(); ++i)
     312             :                             {
     313           4 :                                 if (!STARTS_WITH_CI(aosTokens2[i],
     314             :                                                     "colorspace="))
     315             :                                 {
     316           3 :                                     osDetailedFormat += ';';
     317           3 :                                     osDetailedFormat += aosTokens2[i];
     318             :                                 }
     319             :                             }
     320           1 :                             osDetailedFormat += ";colorspace=RGBA";
     321             :                         }
     322             :                     }
     323             :                 }
     324           9 :                 if (ppszDetailedFormat)
     325           3 :                     *ppszDetailedFormat = VSIStrdup(osDetailedFormat.c_str());
     326           9 :                 if (pnBufferSize)
     327           8 :                     *pnBufferSize = nSizeSize;
     328           9 :                 return CE_None;
     329             :             }
     330             :         }
     331             :     }
     332          69 :     return CE_Failure;
     333             : }
     334             : 
     335             : struct GTiffDecompressContext
     336             : {
     337             :     // The mutex must be recursive because ThreadDecompressionFuncErrorHandler()
     338             :     // which acquires the mutex can be called from a section where the mutex is
     339             :     // already acquired.
     340             :     std::recursive_mutex oMutex{};
     341             :     bool bSuccess = true;
     342             :     CPLErrorAccumulator oErrorAccumulator{};
     343             : 
     344             :     VSIVirtualHandle *poHandle = nullptr;
     345             :     GTiffDataset *poDS = nullptr;
     346             :     GDALDataType eDT = GDT_Unknown;
     347             :     int nXOff = 0;
     348             :     int nYOff = 0;
     349             :     int nXSize = 0;
     350             :     int nYSize = 0;
     351             :     int nBlockXStart = 0;
     352             :     int nBlockYStart = 0;
     353             :     int nBlockXEnd = 0;
     354             :     int nBlockYEnd = 0;
     355             :     GByte *pabyData = nullptr;
     356             :     GDALDataType eBufType = GDT_Unknown;
     357             :     int nBufDTSize = 0;
     358             :     int nBandCount = 0;
     359             :     const int *panBandMap = nullptr;
     360             :     GSpacing nPixelSpace = 0;
     361             :     GSpacing nLineSpace = 0;
     362             :     GSpacing nBandSpace = 0;
     363             :     bool bHasPRead = false;
     364             :     bool bCacheAllBands = false;
     365             :     bool bSkipBlockCache = false;
     366             :     bool bUseBIPOptim = false;
     367             :     bool bUseDeinterleaveOptimNoBlockCache = false;
     368             :     bool bUseDeinterleaveOptimBlockCache = false;
     369             :     bool bIsTiled = false;
     370             :     bool bTIFFIsBigEndian = false;
     371             :     int nBlocksPerRow = 0;
     372             : 
     373             :     uint16_t nPredictor = 0;
     374             : 
     375             :     uint32_t nJPEGTableSize = 0;
     376             :     void *pJPEGTable = nullptr;
     377             :     uint16_t nYCrbCrSubSampling0 = 2;
     378             :     uint16_t nYCrbCrSubSampling1 = 2;
     379             : 
     380             :     uint16_t *pExtraSamples = nullptr;
     381             :     uint16_t nExtraSampleCount = 0;
     382             : };
     383             : 
     384             : struct GTiffDecompressJob
     385             : {
     386             :     GTiffDecompressContext *psContext = nullptr;
     387             :     int iSrcBandIdxSeparate =
     388             :         0;  // in [0, GetRasterCount()-1] in PLANARCONFIG_SEPARATE, or -1 in PLANARCONFIG_CONTIG
     389             :     int iDstBandIdxSeparate =
     390             :         0;  // in [0, nBandCount-1] in PLANARCONFIG_SEPARATE, or -1 in PLANARCONFIG_CONTIG
     391             :     int nXBlock = 0;
     392             :     int nYBlock = 0;
     393             :     vsi_l_offset nOffset = 0;
     394             :     vsi_l_offset nSize = 0;
     395             : };
     396             : 
     397             : /************************************************************************/
     398             : /*                      ThreadDecompressionFunc()                       */
     399             : /************************************************************************/
     400             : 
     401        3836 : /* static */ void GTiffDataset::ThreadDecompressionFunc(void *pData)
     402             : {
     403        3836 :     const auto psJob = static_cast<const GTiffDecompressJob *>(pData);
     404        3836 :     auto psContext = psJob->psContext;
     405        3836 :     auto poDS = psContext->poDS;
     406             : 
     407        3836 :     auto oAccumulator = psContext->oErrorAccumulator.InstallForCurrentScope();
     408             : 
     409        3836 :     const int nBandsPerStrile =
     410        3836 :         poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? poDS->nBands : 1;
     411        7672 :     const int nBandsToWrite = poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     412        3836 :                                   ? psContext->nBandCount
     413             :                                   : 1;
     414             : 
     415        7672 :     const int nXOffsetInBlock = psJob->nXBlock == psContext->nBlockXStart
     416        3836 :                                     ? psContext->nXOff % poDS->m_nBlockXSize
     417             :                                     : 0;
     418        3836 :     const int nXOffsetInData =
     419        3836 :         psJob->nXBlock == psContext->nBlockXStart
     420        3836 :             ? 0
     421        2457 :             : (psJob->nXBlock - psContext->nBlockXStart) * poDS->m_nBlockXSize -
     422        2457 :                   (psContext->nXOff % poDS->m_nBlockXSize);
     423        3836 :     const int nXSize =
     424        3836 :         psJob->nXBlock == psContext->nBlockXStart
     425        7672 :             ? (psJob->nXBlock == psContext->nBlockXEnd
     426        1379 :                    ? psContext->nXSize
     427         477 :                    : poDS->m_nBlockXSize -
     428         477 :                          (psContext->nXOff % poDS->m_nBlockXSize))
     429        2457 :         : psJob->nXBlock == psContext->nBlockXEnd
     430        2934 :             ? (((psContext->nXOff + psContext->nXSize) % poDS->m_nBlockXSize) ==
     431             :                        0
     432         477 :                    ? poDS->m_nBlockXSize
     433         406 :                    : ((psContext->nXOff + psContext->nXSize) %
     434         406 :                       poDS->m_nBlockXSize))
     435        1980 :             : poDS->m_nBlockXSize;
     436             : 
     437        7672 :     const int nYOffsetInBlock = psJob->nYBlock == psContext->nBlockYStart
     438        3836 :                                     ? psContext->nYOff % poDS->m_nBlockYSize
     439             :                                     : 0;
     440        3836 :     const int nYOffsetInData =
     441        3836 :         psJob->nYBlock == psContext->nBlockYStart
     442        3836 :             ? 0
     443        2895 :             : (psJob->nYBlock - psContext->nBlockYStart) * poDS->m_nBlockYSize -
     444        2895 :                   (psContext->nYOff % poDS->m_nBlockYSize);
     445        3836 :     const int nYSize =
     446        3836 :         psJob->nYBlock == psContext->nBlockYStart
     447        7672 :             ? (psJob->nYBlock == psContext->nBlockYEnd
     448         941 :                    ? psContext->nYSize
     449         917 :                    : poDS->m_nBlockYSize -
     450         917 :                          (psContext->nYOff % poDS->m_nBlockYSize))
     451        2895 :         : psJob->nYBlock == psContext->nBlockYEnd
     452        3812 :             ? (((psContext->nYOff + psContext->nYSize) % poDS->m_nBlockYSize) ==
     453             :                        0
     454         917 :                    ? poDS->m_nBlockYSize
     455         801 :                    : ((psContext->nYOff + psContext->nYSize) %
     456         801 :                       poDS->m_nBlockYSize))
     457        1978 :             : poDS->m_nBlockYSize;
     458             : #if 0
     459             :     CPLDebug("GTiff",
     460             :              "nXBlock = %d, nYBlock = %d, "
     461             :              "nXOffsetInBlock = %d, nXOffsetInData = %d, nXSize = %d, "
     462             :              "nYOffsetInBlock = %d, nYOffsetInData = %d, nYSize = %d\n",
     463             :              psJob->nXBlock, psJob->nYBlock,
     464             :              nXOffsetInBlock, nXOffsetInData, nXSize,
     465             :              nYOffsetInBlock, nYOffsetInData, nYSize);
     466             : #endif
     467             : 
     468        3836 :     if (psJob->nSize == 0)
     469             :     {
     470             :         {
     471           2 :             std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
     472           2 :             if (!psContext->bSuccess)
     473           0 :                 return;
     474             :         }
     475           2 :         const double dfNoDataValue =
     476           2 :             poDS->m_bNoDataSet ? poDS->m_dfNoDataValue : 0;
     477         102 :         for (int y = 0; y < nYSize; ++y)
     478             :         {
     479         200 :             for (int i = 0; i < nBandsToWrite; ++i)
     480             :             {
     481         100 :                 const int iDstBandIdx =
     482         100 :                     poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     483         100 :                         ? i
     484           0 :                         : psJob->iDstBandIdxSeparate;
     485         100 :                 GDALCopyWords64(
     486             :                     &dfNoDataValue, GDT_Float64, 0,
     487         100 :                     psContext->pabyData + iDstBandIdx * psContext->nBandSpace +
     488         100 :                         (y + nYOffsetInData) * psContext->nLineSpace +
     489         100 :                         nXOffsetInData * psContext->nPixelSpace,
     490             :                     psContext->eBufType,
     491         100 :                     static_cast<int>(psContext->nPixelSpace), nXSize);
     492             :             }
     493             :         }
     494           2 :         return;
     495             :     }
     496             : 
     497        3834 :     const int nBandsToCache =
     498        3834 :         psContext->bCacheAllBands ? poDS->nBands : nBandsToWrite;
     499        3834 :     std::vector<GDALRasterBlock *> apoBlocks(nBandsToCache);
     500        3834 :     std::vector<bool> abAlreadyLoadedBlocks(nBandsToCache);
     501        3834 :     int nAlreadyLoadedBlocks = 0;
     502        3834 :     std::vector<GByte> abyInput;
     503             : 
     504             :     struct FreeBlocks
     505             :     {
     506             :         std::vector<GDALRasterBlock *> &m_apoBlocks;
     507             : 
     508        3834 :         explicit FreeBlocks(std::vector<GDALRasterBlock *> &apoBlocksIn)
     509        3834 :             : m_apoBlocks(apoBlocksIn)
     510             :         {
     511        3834 :         }
     512             : 
     513        3834 :         ~FreeBlocks()
     514        3834 :         {
     515       10510 :             for (auto *poBlock : m_apoBlocks)
     516             :             {
     517        6676 :                 if (poBlock)
     518        3993 :                     poBlock->DropLock();
     519             :             }
     520        3834 :         }
     521             :     };
     522             : 
     523        3834 :     FreeBlocks oFreeBlocks(apoBlocks);
     524             : 
     525        1781 :     const auto LoadBlocks = [&]()
     526             :     {
     527        5774 :         for (int i = 0; i < nBandsToCache; ++i)
     528             :         {
     529        6302 :             const int iBand = psContext->bCacheAllBands ? i + 1
     530        7343 :                               : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     531        2309 :                                   ? psContext->panBandMap[i]
     532         660 :                                   : psJob->iSrcBandIdxSeparate + 1;
     533        7986 :             apoBlocks[i] = poDS->GetRasterBand(iBand)->TryGetLockedBlockRef(
     534        3993 :                 psJob->nXBlock, psJob->nYBlock);
     535        3993 :             if (apoBlocks[i] == nullptr)
     536             :             {
     537             :                 // Temporary disabling of dirty block flushing, otherwise
     538             :                 // we can be in a deadlock situation, where the
     539             :                 // GTiffDataset::SubmitCompressionJob() method waits for jobs
     540             :                 // to be finished, that can't finish (actually be started)
     541             :                 // because this task and its siblings are taking all the
     542             :                 // available workers allowed by the global thread pool.
     543        1041 :                 GDALRasterBlock::EnterDisableDirtyBlockFlush();
     544        2082 :                 apoBlocks[i] = poDS->GetRasterBand(iBand)->GetLockedBlockRef(
     545        1041 :                     psJob->nXBlock, psJob->nYBlock, TRUE);
     546        1041 :                 GDALRasterBlock::LeaveDisableDirtyBlockFlush();
     547        1041 :                 if (apoBlocks[i] == nullptr)
     548           0 :                     return false;
     549             :             }
     550             :             else
     551             :             {
     552        2952 :                 abAlreadyLoadedBlocks[i] = true;
     553        2952 :                 nAlreadyLoadedBlocks++;
     554             :             }
     555             :         }
     556        1781 :         return true;
     557        3834 :     };
     558             : 
     559        2609 :     const auto AllocInputBuffer = [&]()
     560             :     {
     561        2609 :         bool bError = false;
     562             : #if SIZEOF_VOIDP == 4
     563             :         if (psJob->nSize != static_cast<size_t>(psJob->nSize))
     564             :         {
     565             :             bError = true;
     566             :         }
     567             :         else
     568             : #endif
     569             :         {
     570             :             try
     571             :             {
     572        2609 :                 abyInput.resize(static_cast<size_t>(psJob->nSize));
     573             :             }
     574           0 :             catch (const std::exception &)
     575             :             {
     576           0 :                 bError = true;
     577             :             }
     578             :         }
     579        2609 :         if (bError)
     580             :         {
     581           0 :             CPLError(CE_Failure, CPLE_OutOfMemory,
     582             :                      "Cannot allocate working buffer of size " CPL_FRMT_GUIB,
     583           0 :                      static_cast<GUIntBig>(psJob->nSize));
     584           0 :             return false;
     585             :         }
     586        2609 :         return true;
     587        3834 :     };
     588             : 
     589        3834 :     if (psContext->bHasPRead)
     590             :     {
     591             :         {
     592        3834 :             std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
     593        3834 :             if (!psContext->bSuccess)
     594           5 :                 return;
     595             : 
     596             :             // Coverity Scan notices that GDALRasterBlock::Internalize() calls
     597             :             // CPLSleep() in a debug code path, and warns about that while
     598             :             // holding the above mutex.
     599             :             // coverity[sleep]
     600        3829 :             if (!psContext->bSkipBlockCache && !LoadBlocks())
     601             :             {
     602           0 :                 psContext->bSuccess = false;
     603           0 :                 return;
     604             :             }
     605             :         }
     606        3829 :         if (nAlreadyLoadedBlocks != nBandsToCache)
     607             :         {
     608        2609 :             if (!AllocInputBuffer())
     609             :             {
     610           0 :                 std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
     611           0 :                 psContext->bSuccess = false;
     612           0 :                 return;
     613             :             }
     614        2609 :             if (psContext->poHandle->PRead(abyInput.data(), abyInput.size(),
     615        5218 :                                            psJob->nOffset) != abyInput.size())
     616             :             {
     617           3 :                 CPLError(CE_Failure, CPLE_AppDefined,
     618             :                          "Cannot read " CPL_FRMT_GUIB
     619             :                          " bytes at offset " CPL_FRMT_GUIB,
     620           3 :                          static_cast<GUIntBig>(psJob->nSize),
     621           3 :                          static_cast<GUIntBig>(psJob->nOffset));
     622             : 
     623           3 :                 std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
     624           3 :                 psContext->bSuccess = false;
     625           3 :                 return;
     626             :             }
     627             :         }
     628             :     }
     629             :     else
     630             :     {
     631           0 :         std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
     632           0 :         if (!psContext->bSuccess)
     633           0 :             return;
     634             : 
     635             :         // Coverity Scan notices that GDALRasterBlock::Internalize() calls
     636             :         // CPLSleep() in a debug code path, and warns about that while
     637             :         // holding the above mutex.
     638             :         // coverity[sleep]
     639           0 :         if (!psContext->bSkipBlockCache && !LoadBlocks())
     640             :         {
     641           0 :             psContext->bSuccess = false;
     642           0 :             return;
     643             :         }
     644             : 
     645           0 :         if (nAlreadyLoadedBlocks != nBandsToCache)
     646             :         {
     647           0 :             if (!AllocInputBuffer())
     648             :             {
     649           0 :                 psContext->bSuccess = false;
     650           0 :                 return;
     651             :             }
     652           0 :             if (psContext->poHandle->Seek(psJob->nOffset, SEEK_SET) != 0 ||
     653           0 :                 psContext->poHandle->Read(abyInput.data(), abyInput.size(),
     654             :                                           1) != 1)
     655             :             {
     656           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     657             :                          "Cannot read " CPL_FRMT_GUIB
     658             :                          " bytes at offset " CPL_FRMT_GUIB,
     659           0 :                          static_cast<GUIntBig>(psJob->nSize),
     660           0 :                          static_cast<GUIntBig>(psJob->nOffset));
     661           0 :                 psContext->bSuccess = false;
     662           0 :                 return;
     663             :             }
     664             :         }
     665             :     }
     666             : 
     667        3826 :     const int nDTSize = GDALGetDataTypeSizeBytes(psContext->eDT);
     668        3826 :     GByte *pDstPtr = psContext->pabyData +
     669        3826 :                      nYOffsetInData * psContext->nLineSpace +
     670        3826 :                      nXOffsetInData * psContext->nPixelSpace;
     671             : 
     672        3826 :     if (nAlreadyLoadedBlocks != nBandsToCache)
     673             :     {
     674             :         // Generate a dummy in-memory TIFF file that has all the needed tags
     675             :         // from the original file
     676             :         const CPLString osTmpFilename(
     677        2606 :             VSIMemGenerateHiddenFilename("decompress.tif"));
     678        2606 :         VSILFILE *fpTmp = VSIFOpenL(osTmpFilename.c_str(), "wb+");
     679             :         TIFF *hTIFFTmp =
     680        2606 :             VSI_TIFFOpen(osTmpFilename.c_str(),
     681        2606 :                          psContext->bTIFFIsBigEndian ? "wb+" : "wl+", fpTmp);
     682        2606 :         CPLAssert(hTIFFTmp != nullptr);
     683        2606 :         const int nBlockYSize =
     684        3072 :             (psContext->bIsTiled ||
     685         466 :              psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
     686        3072 :                 ? poDS->m_nBlockYSize
     687          53 :             : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
     688          53 :                 ? poDS->m_nBlockYSize
     689          42 :                 : poDS->nRasterYSize % poDS->m_nBlockYSize;
     690        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_IMAGEWIDTH, poDS->m_nBlockXSize);
     691        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_IMAGELENGTH, nBlockYSize);
     692        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_BITSPERSAMPLE, poDS->m_nBitsPerSample);
     693        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_COMPRESSION, poDS->m_nCompression);
     694        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_PHOTOMETRIC, poDS->m_nPhotometric);
     695        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLEFORMAT, poDS->m_nSampleFormat);
     696        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_SAMPLESPERPIXEL,
     697        2606 :                      poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     698         786 :                          ? poDS->m_nSamplesPerPixel
     699             :                          : 1);
     700        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_ROWSPERSTRIP, nBlockYSize);
     701        2606 :         TIFFSetField(hTIFFTmp, TIFFTAG_PLANARCONFIG, poDS->m_nPlanarConfig);
     702        2606 :         if (psContext->nPredictor != PREDICTOR_NONE)
     703          60 :             TIFFSetField(hTIFFTmp, TIFFTAG_PREDICTOR, psContext->nPredictor);
     704        2606 :         if (poDS->m_nCompression == COMPRESSION_LERC)
     705             :         {
     706          30 :             TIFFSetField(hTIFFTmp, TIFFTAG_LERC_PARAMETERS, 2,
     707          30 :                          poDS->m_anLercAddCompressionAndVersion);
     708             :         }
     709        2576 :         else if (poDS->m_nCompression == COMPRESSION_JPEG)
     710             :         {
     711          14 :             if (psContext->pJPEGTable)
     712             :             {
     713          14 :                 TIFFSetField(hTIFFTmp, TIFFTAG_JPEGTABLES,
     714             :                              psContext->nJPEGTableSize, psContext->pJPEGTable);
     715             :             }
     716          14 :             if (poDS->m_nPhotometric == PHOTOMETRIC_YCBCR)
     717             :             {
     718           7 :                 TIFFSetField(hTIFFTmp, TIFFTAG_YCBCRSUBSAMPLING,
     719           7 :                              psContext->nYCrbCrSubSampling0,
     720           7 :                              psContext->nYCrbCrSubSampling1);
     721             :             }
     722             :         }
     723        2606 :         if (poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG)
     724             :         {
     725         786 :             if (psContext->pExtraSamples)
     726             :             {
     727          66 :                 TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
     728          66 :                              psContext->nExtraSampleCount,
     729             :                              psContext->pExtraSamples);
     730             :             }
     731             :             else
     732             :             {
     733         720 :                 const int nSamplesAccountedFor =
     734         968 :                     poDS->m_nPhotometric == PHOTOMETRIC_RGB          ? 3
     735         248 :                     : poDS->m_nPhotometric == PHOTOMETRIC_MINISBLACK ? 1
     736             :                                                                      : 0;
     737         720 :                 if (nSamplesAccountedFor > 0 &&
     738         713 :                     poDS->m_nSamplesPerPixel > nSamplesAccountedFor)
     739             :                 {
     740             :                     // If the input image is not compliant regarndig ExtraSamples,
     741             :                     // generate a synthetic one to avoid gazillons of warnings
     742           0 :                     const auto nExtraSampleCount = static_cast<uint16_t>(
     743           0 :                         poDS->m_nSamplesPerPixel - nSamplesAccountedFor);
     744             :                     std::vector<uint16_t> anExtraSamples(
     745           0 :                         nExtraSampleCount, EXTRASAMPLE_UNSPECIFIED);
     746           0 :                     TIFFSetField(hTIFFTmp, TIFFTAG_EXTRASAMPLES,
     747             :                                  nExtraSampleCount, anExtraSamples.data());
     748             :                 }
     749             :             }
     750             :         }
     751        2606 :         TIFFWriteCheck(hTIFFTmp, FALSE, "ThreadDecompressionFunc");
     752        2606 :         TIFFWriteDirectory(hTIFFTmp);
     753        2606 :         XTIFFClose(hTIFFTmp);
     754             : 
     755             :         // Re-open file
     756        2606 :         hTIFFTmp = VSI_TIFFOpen(osTmpFilename.c_str(), "r", fpTmp);
     757        2606 :         CPLAssert(hTIFFTmp != nullptr);
     758        2606 :         poDS->RestoreVolatileParameters(hTIFFTmp);
     759             : 
     760        2606 :         bool bRet = true;
     761             :         // Request m_nBlockYSize line in the block, except on the bottom-most
     762             :         // tile/strip.
     763        2606 :         const int nBlockReqYSize =
     764        2606 :             (psJob->nYBlock < poDS->m_nBlocksPerColumn - 1)
     765        3203 :                 ? poDS->m_nBlockYSize
     766         597 :             : (poDS->nRasterYSize % poDS->m_nBlockYSize) == 0
     767         597 :                 ? poDS->m_nBlockYSize
     768         554 :                 : poDS->nRasterYSize % poDS->m_nBlockYSize;
     769             : 
     770        2606 :         const size_t nReqSize = static_cast<size_t>(poDS->m_nBlockXSize) *
     771        2606 :                                 nBlockReqYSize * nBandsPerStrile * nDTSize;
     772             : 
     773             :         GByte *pabyOutput;
     774        2606 :         std::vector<GByte> abyOutput;
     775        5436 :         if (poDS->m_nCompression == COMPRESSION_NONE &&
     776        2830 :             !TIFFIsByteSwapped(poDS->m_hTIFF) && abyInput.size() >= nReqSize &&
     777         224 :             (psContext->bSkipBlockCache || nBandsPerStrile > 1))
     778             :         {
     779         224 :             pabyOutput = abyInput.data();
     780             :         }
     781             :         else
     782             :         {
     783        2382 :             if (psContext->bSkipBlockCache || nBandsPerStrile > 1)
     784             :             {
     785        2060 :                 abyOutput.resize(nReqSize);
     786        2060 :                 pabyOutput = abyOutput.data();
     787             :             }
     788             :             else
     789             :             {
     790         322 :                 pabyOutput = static_cast<GByte *>(apoBlocks[0]->GetDataRef());
     791             :             }
     792        2382 :             if (!TIFFReadFromUserBuffer(hTIFFTmp, 0, abyInput.data(),
     793        2382 :                                         abyInput.size(), pabyOutput,
     794        2382 :                                         nReqSize) &&
     795           0 :                 !poDS->m_bIgnoreReadErrors)
     796             :             {
     797           0 :                 bRet = false;
     798             :             }
     799             :         }
     800        2606 :         XTIFFClose(hTIFFTmp);
     801        2606 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTmp));
     802        2606 :         VSIUnlink(osTmpFilename.c_str());
     803             : 
     804        2606 :         if (!bRet)
     805             :         {
     806           0 :             std::lock_guard<std::recursive_mutex> oLock(psContext->oMutex);
     807           0 :             psContext->bSuccess = false;
     808           0 :             return;
     809             :         }
     810             : 
     811        2606 :         if (!psContext->bSkipBlockCache && nBandsPerStrile > 1)
     812             :         {
     813             :             // Copy pixel-interleaved all-band buffer to cached blocks
     814             : 
     815         236 :             if (psContext->bUseDeinterleaveOptimBlockCache)
     816             :             {
     817             :                 // Optimization
     818         232 :                 std::vector<void *> ppDestBuffers(poDS->nBands);
     819         464 :                 for (int i = 0; i < poDS->nBands; ++i)
     820             :                 {
     821         348 :                     ppDestBuffers[i] = apoBlocks[i]->GetDataRef();
     822             :                 }
     823         116 :                 GDALDeinterleave(pabyOutput, psContext->eDT, poDS->nBands,
     824             :                                  ppDestBuffers.data(), psContext->eDT,
     825         116 :                                  static_cast<size_t>(nBlockReqYSize) *
     826         116 :                                      poDS->m_nBlockXSize);
     827             :             }
     828             :             else
     829             :             {
     830             :                 // General case
     831         488 :                 for (int i = 0; i < nBandsToCache; ++i)
     832             :                 {
     833         368 :                     if (!abAlreadyLoadedBlocks[i])
     834             :                     {
     835         736 :                         const int iBand = psContext->bCacheAllBands
     836         368 :                                               ? i
     837         368 :                                               : psContext->panBandMap[i] - 1;
     838         368 :                         GDALCopyWords64(pabyOutput + iBand * nDTSize,
     839         368 :                                         psContext->eDT, nDTSize * poDS->nBands,
     840         368 :                                         apoBlocks[i]->GetDataRef(),
     841             :                                         psContext->eDT, nDTSize,
     842         368 :                                         static_cast<size_t>(nBlockReqYSize) *
     843         368 :                                             poDS->m_nBlockXSize);
     844             :                     }
     845             :                 }
     846             :             }
     847             :         }
     848             : 
     849        2606 :         const GByte *pSrcPtr =
     850             :             pabyOutput +
     851        2606 :             (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
     852        2606 :              nXOffsetInBlock) *
     853        2606 :                 nDTSize * nBandsPerStrile;
     854        2606 :         const size_t nSrcLineInc = static_cast<size_t>(poDS->m_nBlockXSize) *
     855        2606 :                                    nDTSize * nBandsPerStrile;
     856             : 
     857             :         // Optimization when writing to BIP buffer.
     858        2606 :         if (psContext->bUseBIPOptim)
     859             :         {
     860       13593 :             for (int y = 0; y < nYSize; ++y)
     861             :             {
     862       13262 :                 GDALCopyWords64(pSrcPtr, psContext->eDT, nDTSize, pDstPtr,
     863             :                                 psContext->eBufType, psContext->nBufDTSize,
     864       13262 :                                 static_cast<size_t>(nXSize) * poDS->nBands);
     865       13262 :                 pSrcPtr += nSrcLineInc;
     866       13262 :                 pDstPtr += psContext->nLineSpace;
     867             :             }
     868         331 :             return;
     869             :         }
     870             : 
     871        2275 :         if (psContext->bSkipBlockCache)
     872             :         {
     873             :             // Copy from pixel-interleaved all-band buffer (or temporary buffer
     874             :             // for single-band/separate case) into final buffer
     875        1759 :             if (psContext->bUseDeinterleaveOptimNoBlockCache)
     876             :             {
     877             :                 // Optimization
     878         215 :                 std::vector<void *> ppDestBuffers(psContext->nBandCount);
     879         860 :                 for (int i = 0; i < psContext->nBandCount; ++i)
     880             :                 {
     881         645 :                     ppDestBuffers[i] =
     882         645 :                         pDstPtr +
     883         645 :                         (psContext->panBandMap[i] - 1) * psContext->nBandSpace;
     884             :                 }
     885       12275 :                 for (int y = 0; y < nYSize; ++y)
     886             :                 {
     887       12060 :                     GDALDeinterleave(
     888             :                         pSrcPtr, psContext->eDT, psContext->nBandCount,
     889             :                         ppDestBuffers.data(), psContext->eDT, nXSize);
     890       12060 :                     pSrcPtr += nSrcLineInc;
     891       48240 :                     for (int i = 0; i < psContext->nBandCount; ++i)
     892             :                     {
     893       36180 :                         ppDestBuffers[i] =
     894       36180 :                             static_cast<GByte *>(ppDestBuffers[i]) +
     895       36180 :                             psContext->nLineSpace;
     896             :                     }
     897             :                 }
     898         215 :                 return;
     899             :             }
     900             : 
     901             :             // General case
     902       40244 :             for (int y = 0; y < nYSize; ++y)
     903             :             {
     904       78200 :                 for (int i = 0; i < nBandsToWrite; ++i)
     905             :                 {
     906       39500 :                     const int iSrcBandIdx =
     907       39500 :                         poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     908       39500 :                             ? psContext->panBandMap[i] - 1
     909             :                             : 0;
     910       39500 :                     const int iDstBandIdx =
     911       39500 :                         poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     912       39500 :                             ? i
     913       38500 :                             : psJob->iDstBandIdxSeparate;
     914       39500 :                     GDALCopyWords64(
     915       39500 :                         pSrcPtr + iSrcBandIdx * nDTSize + y * nSrcLineInc,
     916             :                         psContext->eDT, nDTSize * nBandsPerStrile,
     917       39500 :                         pDstPtr + iDstBandIdx * psContext->nBandSpace +
     918       39500 :                             y * psContext->nLineSpace,
     919             :                         psContext->eBufType,
     920       39500 :                         static_cast<int>(psContext->nPixelSpace), nXSize);
     921             :                 }
     922             :             }
     923        1544 :             return;
     924             :         }
     925             :     }
     926             : 
     927        1736 :     CPLAssert(!psContext->bSkipBlockCache);
     928             : 
     929             :     // Compose cached blocks into final buffer
     930        4548 :     for (int i = 0; i < nBandsToWrite; ++i)
     931             :     {
     932        2812 :         const int iSrcBandIdx =
     933        5076 :             psContext->bCacheAllBands ? psContext->panBandMap[i] - 1
     934        2264 :             : poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG ? i
     935             :                                                            : 0;
     936        2812 :         assert(iSrcBandIdx >= 0);
     937        5624 :         const int iDstBandIdx = poDS->m_nPlanarConfig == PLANARCONFIG_CONTIG
     938        2812 :                                     ? i
     939         660 :                                     : psJob->iDstBandIdxSeparate;
     940             :         const GByte *pSrcPtr =
     941        2812 :             static_cast<GByte *>(apoBlocks[iSrcBandIdx]->GetDataRef()) +
     942        2812 :             (static_cast<size_t>(nYOffsetInBlock) * poDS->m_nBlockXSize +
     943        2812 :              nXOffsetInBlock) *
     944        2812 :                 nDTSize;
     945       68244 :         for (int y = 0; y < nYSize; ++y)
     946             :         {
     947       65432 :             GDALCopyWords64(pSrcPtr + static_cast<size_t>(y) *
     948       65432 :                                           poDS->m_nBlockXSize * nDTSize,
     949             :                             psContext->eDT, nDTSize,
     950       65432 :                             pDstPtr + iDstBandIdx * psContext->nBandSpace +
     951       65432 :                                 y * psContext->nLineSpace,
     952             :                             psContext->eBufType,
     953       65432 :                             static_cast<int>(psContext->nPixelSpace), nXSize);
     954             :         }
     955             :     }
     956             : }
     957             : 
     958             : /************************************************************************/
     959             : /*                   IsMultiThreadedReadCompatible()                    */
     960             : /************************************************************************/
     961             : 
     962         283 : bool GTiffDataset::IsMultiThreadedReadCompatible() const
     963             : {
     964         283 :     return cpl::down_cast<GTiffRasterBand *>(papoBands[0])
     965         283 :                ->IsBaseGTiffClass() &&
     966         564 :            !m_bStreamingIn && !m_bStreamingOut &&
     967         281 :            (m_nCompression == COMPRESSION_NONE ||
     968         258 :             m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
     969         235 :             m_nCompression == COMPRESSION_LZW ||
     970          86 :             m_nCompression == COMPRESSION_PACKBITS ||
     971          72 :             m_nCompression == COMPRESSION_LZMA ||
     972          58 :             m_nCompression == COMPRESSION_ZSTD ||
     973          44 :             m_nCompression == COMPRESSION_LERC ||
     974          30 :             m_nCompression == COMPRESSION_JXL ||
     975          30 :             m_nCompression == COMPRESSION_JXL_DNG_1_7 ||
     976          16 :             m_nCompression == COMPRESSION_WEBP ||
     977         285 :             m_nCompression == COMPRESSION_JPEG);
     978             : }
     979             : 
     980             : /************************************************************************/
     981             : /*                         MultiThreadedRead()                          */
     982             : /************************************************************************/
     983             : 
     984         254 : CPLErr GTiffDataset::MultiThreadedRead(int nXOff, int nYOff, int nXSize,
     985             :                                        int nYSize, void *pData,
     986             :                                        GDALDataType eBufType, int nBandCount,
     987             :                                        const int *panBandMap,
     988             :                                        GSpacing nPixelSpace,
     989             :                                        GSpacing nLineSpace, GSpacing nBandSpace)
     990             : {
     991         508 :     auto poQueue = m_poThreadPool->CreateJobQueue();
     992         254 :     if (poQueue == nullptr)
     993             :     {
     994           0 :         return CE_Failure;
     995             :     }
     996             : 
     997         254 :     const int nBlockXStart = nXOff / m_nBlockXSize;
     998         254 :     const int nBlockYStart = nYOff / m_nBlockYSize;
     999         254 :     const int nBlockXEnd = (nXOff + nXSize - 1) / m_nBlockXSize;
    1000         254 :     const int nBlockYEnd = (nYOff + nYSize - 1) / m_nBlockYSize;
    1001         254 :     const int nXBlocks = nBlockXEnd - nBlockXStart + 1;
    1002         254 :     const int nYBlocks = nBlockYEnd - nBlockYStart + 1;
    1003         254 :     const int nStrilePerBlock =
    1004         254 :         m_nPlanarConfig == PLANARCONFIG_CONTIG ? 1 : nBandCount;
    1005         254 :     const int nBlocks = nXBlocks * nYBlocks * nStrilePerBlock;
    1006             : 
    1007         508 :     GTiffDecompressContext sContext;
    1008         254 :     sContext.poHandle = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
    1009         254 :     sContext.bHasPRead =
    1010         254 :         sContext.poHandle->HasPRead()
    1011             : #ifdef DEBUG
    1012         254 :         && CPLTestBool(CPLGetConfigOption("GTIFF_ALLOW_PREAD", "YES"))
    1013             : #endif
    1014             :         ;
    1015         254 :     sContext.poDS = this;
    1016         254 :     sContext.eDT = GetRasterBand(1)->GetRasterDataType();
    1017         254 :     sContext.nXOff = nXOff;
    1018         254 :     sContext.nYOff = nYOff;
    1019         254 :     sContext.nXSize = nXSize;
    1020         254 :     sContext.nYSize = nYSize;
    1021         254 :     sContext.nBlockXStart = nBlockXStart;
    1022         254 :     sContext.nBlockXEnd = nBlockXEnd;
    1023         254 :     sContext.nBlockYStart = nBlockYStart;
    1024         254 :     sContext.nBlockYEnd = nBlockYEnd;
    1025         254 :     sContext.pabyData = static_cast<GByte *>(pData);
    1026         254 :     sContext.eBufType = eBufType;
    1027         254 :     sContext.nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
    1028         254 :     sContext.nBandCount = nBandCount;
    1029         254 :     sContext.panBandMap = panBandMap;
    1030         254 :     sContext.nPixelSpace = nPixelSpace;
    1031         254 :     sContext.nLineSpace = nLineSpace;
    1032             :     // Setting nBandSpace to a dummy value when nBandCount == 1 helps detecting
    1033             :     // bad computations of target buffer address
    1034             :     // (https://github.com/rasterio/rasterio/issues/2847)
    1035         254 :     sContext.nBandSpace = nBandCount == 1 ? 0xDEADBEEF : nBandSpace;
    1036         254 :     sContext.bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
    1037         254 :     sContext.bTIFFIsBigEndian = CPL_TO_BOOL(TIFFIsBigEndian(m_hTIFF));
    1038         254 :     sContext.nPredictor = PREDICTOR_NONE;
    1039         254 :     sContext.nBlocksPerRow = m_nBlocksPerRow;
    1040             : 
    1041         254 :     if (m_bDirectIO)
    1042             :     {
    1043           0 :         sContext.bSkipBlockCache = true;
    1044             :     }
    1045         254 :     else if (nXOff == 0 && nYOff == 0 && nXSize == nRasterXSize &&
    1046         195 :              nYSize == nRasterYSize)
    1047             :     {
    1048         190 :         if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1049             :         {
    1050          40 :             sContext.bSkipBlockCache = true;
    1051             :         }
    1052         150 :         else if (nBandCount == nBands)
    1053             :         {
    1054          74 :             sContext.bSkipBlockCache = true;
    1055         208 :             for (int i = 0; i < nBands; ++i)
    1056             :             {
    1057         158 :                 if (panBandMap[i] != i + 1)
    1058             :                 {
    1059          24 :                     sContext.bSkipBlockCache = false;
    1060          24 :                     break;
    1061             :                 }
    1062             :             }
    1063             :         }
    1064             :     }
    1065             : 
    1066         254 :     if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount == nBands &&
    1067         122 :         nPixelSpace == nBands * static_cast<GSpacing>(sContext.nBufDTSize))
    1068             :     {
    1069          44 :         sContext.bUseBIPOptim = true;
    1070         140 :         for (int i = 0; i < nBands; ++i)
    1071             :         {
    1072          96 :             if (panBandMap[i] != i + 1)
    1073             :             {
    1074           0 :                 sContext.bUseBIPOptim = false;
    1075           0 :                 break;
    1076             :             }
    1077             :         }
    1078             :     }
    1079             : 
    1080         254 :     if (m_nPlanarConfig == PLANARCONFIG_CONTIG &&
    1081         198 :         (nBands == 3 || nBands == 4) && nBands == nBandCount &&
    1082          94 :         (sContext.eDT == GDT_UInt8 || sContext.eDT == GDT_Int16 ||
    1083           9 :          sContext.eDT == GDT_UInt16))
    1084             :     {
    1085          94 :         if (sContext.bSkipBlockCache)
    1086             :         {
    1087          36 :             if (sContext.eBufType == sContext.eDT &&
    1088          35 :                 nPixelSpace == sContext.nBufDTSize)
    1089             :             {
    1090          24 :                 sContext.bUseDeinterleaveOptimNoBlockCache = true;
    1091             :             }
    1092             :         }
    1093             :         else
    1094             :         {
    1095          58 :             sContext.bUseDeinterleaveOptimBlockCache = true;
    1096         166 :             for (int i = 0; i < nBands; ++i)
    1097             :             {
    1098         130 :                 if (panBandMap[i] != i + 1)
    1099             :                 {
    1100          22 :                     sContext.bUseDeinterleaveOptimBlockCache = false;
    1101          22 :                     break;
    1102             :                 }
    1103             :             }
    1104             :         }
    1105             :     }
    1106             : 
    1107             :     // In contig mode, if only one band is requested, check if we have
    1108             :     // enough cache to cache all bands.
    1109         254 :     if (!sContext.bSkipBlockCache && nBands != 1 &&
    1110         151 :         m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount == 1)
    1111             :     {
    1112          76 :         const GIntBig nRequiredMem = static_cast<GIntBig>(nBands) * nXBlocks *
    1113          76 :                                      nYBlocks * m_nBlockXSize * m_nBlockYSize *
    1114          76 :                                      GDALGetDataTypeSizeBytes(sContext.eDT);
    1115          76 :         if (nRequiredMem > GDALGetCacheMax64())
    1116             :         {
    1117           0 :             if (!m_bHasWarnedDisableAggressiveBandCaching)
    1118             :             {
    1119           0 :                 CPLDebug("GTiff",
    1120             :                          "Disable aggressive band caching. "
    1121             :                          "Cache not big enough. "
    1122             :                          "At least " CPL_FRMT_GIB " bytes necessary",
    1123             :                          nRequiredMem);
    1124           0 :                 m_bHasWarnedDisableAggressiveBandCaching = true;
    1125             :             }
    1126             :         }
    1127             :         else
    1128             :         {
    1129          76 :             sContext.bCacheAllBands = true;
    1130          76 :             if ((nBands == 3 || nBands == 4) &&
    1131          66 :                 (sContext.eDT == GDT_UInt8 || sContext.eDT == GDT_Int16 ||
    1132           6 :                  sContext.eDT == GDT_UInt16))
    1133             :             {
    1134          66 :                 sContext.bUseDeinterleaveOptimBlockCache = true;
    1135             :             }
    1136             :         }
    1137             :     }
    1138             : 
    1139         254 :     if (eAccess == GA_Update)
    1140             :     {
    1141         234 :         std::vector<int> anBandsToCheck;
    1142         234 :         if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1)
    1143             :         {
    1144         740 :             for (int i = 0; i < nBands; ++i)
    1145             :             {
    1146         564 :                 anBandsToCheck.push_back(i);
    1147         176 :             }
    1148             :         }
    1149             :         else
    1150             :         {
    1151         170 :             for (int i = 0; i < nBandCount; ++i)
    1152             :             {
    1153         112 :                 anBandsToCheck.push_back(panBandMap[i] - 1);
    1154             :             }
    1155             :         }
    1156         234 :         if (!anBandsToCheck.empty())
    1157             :         {
    1158             :             // If at least one block in the region of intersest is dirty,
    1159             :             // fallback to normal reading code path to be able to retrieve
    1160             :             // content partly from the block cache.
    1161             :             // An alternative that was implemented in GDAL 3.6 to 3.8.0 was
    1162             :             // to flush dirty blocks, but this could cause many write&read&write
    1163             :             // cycles in some gdalwarp scenarios.
    1164             :             // Cf https://github.com/OSGeo/gdal/issues/8729
    1165         234 :             bool bUseBaseImplementation = false;
    1166        1225 :             for (int y = 0; y < nYBlocks; ++y)
    1167             :             {
    1168        3521 :                 for (int x = 0; x < nXBlocks; ++x)
    1169             :                 {
    1170        8912 :                     for (const int iBand : anBandsToCheck)
    1171             :                     {
    1172        6400 :                         if (m_nLoadedBlock >= 0 && m_bLoadedBlockDirty &&
    1173           0 :                             cpl::down_cast<GTiffRasterBand *>(papoBands[iBand])
    1174           0 :                                     ->ComputeBlockId(nBlockXStart + x,
    1175             :                                                      nBlockYStart + y) ==
    1176           0 :                                 m_nLoadedBlock)
    1177             :                         {
    1178           0 :                             bUseBaseImplementation = true;
    1179          18 :                             goto after_loop;
    1180             :                         }
    1181       12800 :                         auto poBlock = papoBands[iBand]->TryGetLockedBlockRef(
    1182        6400 :                             nBlockXStart + x, nBlockYStart + y);
    1183        6400 :                         if (poBlock)
    1184             :                         {
    1185        3868 :                             if (poBlock->GetDirty())
    1186             :                             {
    1187          18 :                                 poBlock->DropLock();
    1188          18 :                                 bUseBaseImplementation = true;
    1189          18 :                                 goto after_loop;
    1190             :                             }
    1191        3850 :                             poBlock->DropLock();
    1192             :                         }
    1193             :                     }
    1194             :                 }
    1195             :             }
    1196         216 :         after_loop:
    1197         234 :             if (bUseBaseImplementation)
    1198             :             {
    1199          18 :                 ++m_nDisableMultiThreadedRead;
    1200             :                 GDALRasterIOExtraArg sExtraArg;
    1201          18 :                 INIT_RASTERIO_EXTRA_ARG(sExtraArg);
    1202          18 :                 const CPLErr eErr = GDALDataset::IRasterIO(
    1203             :                     GF_Read, nXOff, nYOff, nXSize, nYSize, pData, nXSize,
    1204             :                     nYSize, eBufType, nBandCount, const_cast<int *>(panBandMap),
    1205             :                     nPixelSpace, nLineSpace, nBandSpace, &sExtraArg);
    1206          18 :                 --m_nDisableMultiThreadedRead;
    1207          18 :                 return eErr;
    1208             :             }
    1209             :         }
    1210             : 
    1211             :         // Make sure that all blocks that we are going to read and that are
    1212             :         // being written by a worker thread are completed.
    1213             :         // cppcheck-suppress constVariableReference
    1214         216 :         auto &oQueue =
    1215         216 :             m_poBaseDS ? m_poBaseDS->m_asQueueJobIdx : m_asQueueJobIdx;
    1216         216 :         if (!oQueue.empty())
    1217             :         {
    1218          85 :             for (int y = 0; y < nYBlocks; ++y)
    1219             :             {
    1220         192 :                 for (int x = 0; x < nXBlocks; ++x)
    1221             :                 {
    1222         296 :                     for (int i = 0; i < nStrilePerBlock; ++i)
    1223             :                     {
    1224         176 :                         int nBlockId =
    1225         176 :                             nBlockXStart + x +
    1226         176 :                             (nBlockYStart + y) * sContext.nBlocksPerRow;
    1227         176 :                         if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1228          84 :                             nBlockId += (panBandMap[i] - 1) * m_nBlocksPerBand;
    1229             : 
    1230         176 :                         WaitCompletionForBlock(nBlockId);
    1231             :                     }
    1232             :                 }
    1233             :             }
    1234             :         }
    1235             : 
    1236             :         // Flush to file, and then to disk if using pread() interface
    1237         216 :         VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
    1238         216 :         if (sContext.bHasPRead)
    1239         216 :             sContext.poHandle->Flush();
    1240             :     }
    1241             : 
    1242         236 :     if (GTIFFSupportsPredictor(m_nCompression))
    1243             :     {
    1244         155 :         TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &sContext.nPredictor);
    1245             :     }
    1246          81 :     else if (m_nCompression == COMPRESSION_JPEG)
    1247             :     {
    1248           2 :         TIFFGetField(m_hTIFF, TIFFTAG_JPEGTABLES, &sContext.nJPEGTableSize,
    1249             :                      &sContext.pJPEGTable);
    1250           2 :         if (m_nPhotometric == PHOTOMETRIC_YCBCR)
    1251             :         {
    1252           1 :             TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_YCBCRSUBSAMPLING,
    1253             :                                   &sContext.nYCrbCrSubSampling0,
    1254             :                                   &sContext.nYCrbCrSubSampling1);
    1255             :         }
    1256             :     }
    1257         236 :     if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    1258             :     {
    1259         189 :         TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &sContext.nExtraSampleCount,
    1260             :                      &sContext.pExtraSamples);
    1261             :     }
    1262             : 
    1263             :     // Create one job per tile/strip
    1264         236 :     vsi_l_offset nFileSize = 0;
    1265         472 :     std::vector<GTiffDecompressJob> asJobs(nBlocks);
    1266         472 :     std::vector<vsi_l_offset> anOffsets(nBlocks);
    1267         472 :     std::vector<size_t> anSizes(nBlocks);
    1268         236 :     int iJob = 0;
    1269         236 :     int nAdviseReadRanges = 0;
    1270             :     const size_t nAdviseReadTotalBytesLimit =
    1271         236 :         sContext.poHandle->GetAdviseReadTotalBytesLimit();
    1272         236 :     size_t nAdviseReadAccBytes = 0;
    1273        8697 :     for (int y = 0; y < nYBlocks; ++y)
    1274             :     {
    1275       18491 :         for (int x = 0; x < nXBlocks; ++x)
    1276             :         {
    1277       21125 :             for (int i = 0; i < nStrilePerBlock; ++i)
    1278             :             {
    1279       11098 :                 asJobs[iJob].psContext = &sContext;
    1280       11098 :                 asJobs[iJob].iSrcBandIdxSeparate =
    1281       11098 :                     m_nPlanarConfig == PLANARCONFIG_CONTIG ? -1
    1282        2200 :                                                            : panBandMap[i] - 1;
    1283       11098 :                 asJobs[iJob].iDstBandIdxSeparate =
    1284       11098 :                     m_nPlanarConfig == PLANARCONFIG_CONTIG ? -1 : i;
    1285       11098 :                 asJobs[iJob].nXBlock = nBlockXStart + x;
    1286       11098 :                 asJobs[iJob].nYBlock = nBlockYStart + y;
    1287             : 
    1288       11098 :                 int nBlockId = asJobs[iJob].nXBlock +
    1289       11098 :                                asJobs[iJob].nYBlock * sContext.nBlocksPerRow;
    1290       11098 :                 if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1291        2200 :                     nBlockId +=
    1292        2200 :                         asJobs[iJob].iSrcBandIdxSeparate * m_nBlocksPerBand;
    1293             : 
    1294       11098 :                 bool bErrorInIsBlockAvailable = false;
    1295       11098 :                 if (!sContext.bHasPRead)
    1296             :                 {
    1297             :                     // Taking the mutex here is only needed when bHasPRead ==
    1298             :                     // false since we could have concurrent uses of the handle,
    1299             :                     // when when reading the TIFF TileOffsets / TileByteCounts
    1300             :                     // array
    1301             :                     std::lock_guard<std::recursive_mutex> oLock(
    1302           0 :                         sContext.oMutex);
    1303             : 
    1304           0 :                     CPL_IGNORE_RET_VAL(IsBlockAvailable(
    1305           0 :                         nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
    1306             :                         &bErrorInIsBlockAvailable));
    1307             :                 }
    1308             :                 else
    1309             :                 {
    1310       11098 :                     CPL_IGNORE_RET_VAL(IsBlockAvailable(
    1311       11098 :                         nBlockId, &asJobs[iJob].nOffset, &asJobs[iJob].nSize,
    1312             :                         &bErrorInIsBlockAvailable));
    1313             :                 }
    1314       11098 :                 if (bErrorInIsBlockAvailable)
    1315             :                 {
    1316           2 :                     ReportError(CE_Failure, CPLE_AppDefined,
    1317             :                                 "Error while getting location of block %d",
    1318             :                                 nBlockId);
    1319             :                     std::lock_guard<std::recursive_mutex> oLock(
    1320           2 :                         sContext.oMutex);
    1321           2 :                     sContext.bSuccess = false;
    1322           2 :                     return CE_Failure;
    1323             :                 }
    1324             : 
    1325             :                 // Sanity check on block size
    1326       11096 :                 if (asJobs[iJob].nSize > 100U * 1024 * 1024)
    1327             :                 {
    1328           0 :                     if (nFileSize == 0)
    1329             :                     {
    1330             :                         std::lock_guard<std::recursive_mutex> oLock(
    1331           0 :                             sContext.oMutex);
    1332           0 :                         sContext.poHandle->Seek(0, SEEK_END);
    1333           0 :                         nFileSize = sContext.poHandle->Tell();
    1334             :                     }
    1335           0 :                     if (asJobs[iJob].nSize > nFileSize)
    1336             :                     {
    1337           0 :                         CPLError(CE_Failure, CPLE_AppDefined,
    1338             :                                  "Cannot read " CPL_FRMT_GUIB
    1339             :                                  " bytes at offset " CPL_FRMT_GUIB,
    1340           0 :                                  static_cast<GUIntBig>(asJobs[iJob].nSize),
    1341           0 :                                  static_cast<GUIntBig>(asJobs[iJob].nOffset));
    1342             : 
    1343             :                         std::lock_guard<std::recursive_mutex> oLock(
    1344           0 :                             sContext.oMutex);
    1345           0 :                         sContext.bSuccess = false;
    1346           0 :                         return CE_Failure;
    1347             :                     }
    1348             :                 }
    1349             : 
    1350             :                 // Only request in AdviseRead() ranges for blocks we don't
    1351             :                 // have in cache.
    1352       11096 :                 bool bAddToAdviseRead = true;
    1353       11096 :                 if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    1354             :                 {
    1355             :                     auto poBlock =
    1356        2200 :                         GetRasterBand(panBandMap[i])
    1357        2200 :                             ->TryGetLockedBlockRef(asJobs[iJob].nXBlock,
    1358        2200 :                                                    asJobs[iJob].nYBlock);
    1359        2200 :                     if (poBlock)
    1360             :                     {
    1361         968 :                         poBlock->DropLock();
    1362         968 :                         bAddToAdviseRead = false;
    1363             :                     }
    1364             :                 }
    1365             :                 else
    1366             :                 {
    1367        8896 :                     bool bAllCached = true;
    1368       10606 :                     for (int iBand = 0; iBand < nBandCount; ++iBand)
    1369             :                     {
    1370             :                         auto poBlock =
    1371        9676 :                             GetRasterBand(panBandMap[iBand])
    1372        9676 :                                 ->TryGetLockedBlockRef(asJobs[iJob].nXBlock,
    1373        9676 :                                                        asJobs[iJob].nYBlock);
    1374        9676 :                         if (poBlock)
    1375             :                         {
    1376        1710 :                             poBlock->DropLock();
    1377             :                         }
    1378             :                         else
    1379             :                         {
    1380        7966 :                             bAllCached = false;
    1381        7966 :                             break;
    1382             :                         }
    1383             :                     }
    1384        8896 :                     if (bAllCached)
    1385         930 :                         bAddToAdviseRead = false;
    1386             :                 }
    1387             : 
    1388       11096 :                 if (bAddToAdviseRead)
    1389             :                 {
    1390        9198 :                     anOffsets[nAdviseReadRanges] = asJobs[iJob].nOffset;
    1391       18396 :                     anSizes[nAdviseReadRanges] =
    1392        9198 :                         static_cast<size_t>(std::min<vsi_l_offset>(
    1393       27594 :                             std::numeric_limits<size_t>::max(),
    1394        9198 :                             asJobs[iJob].nSize));
    1395             : 
    1396             :                     // If the total number of bytes we must read excess the
    1397             :                     // capacity of AdviseRead(), then split the RasterIO()
    1398             :                     // request in 2 halves.
    1399       16666 :                     if (nAdviseReadTotalBytesLimit > 0 &&
    1400        7468 :                         anSizes[nAdviseReadRanges] <
    1401        7468 :                             nAdviseReadTotalBytesLimit &&
    1402        7468 :                         anSizes[nAdviseReadRanges] >
    1403       16666 :                             nAdviseReadTotalBytesLimit - nAdviseReadAccBytes &&
    1404             :                         nYBlocks >= 2)
    1405             :                     {
    1406           1 :                         const int nYOff2 =
    1407           1 :                             (nBlockYStart + nYBlocks / 2) * m_nBlockYSize;
    1408           1 :                         CPLDebugOnly("GTiff",
    1409             :                                      "Splitting request (%d,%d,%dx%d) into "
    1410             :                                      "(%d,%d,%dx%d) and (%d,%d,%dx%d)",
    1411             :                                      nXOff, nYOff, nXSize, nYSize, nXOff, nYOff,
    1412             :                                      nXSize, nYOff2 - nYOff, nXOff, nYOff2,
    1413             :                                      nXSize, nYOff + nYSize - nYOff2);
    1414             : 
    1415           1 :                         asJobs.clear();
    1416           1 :                         anOffsets.clear();
    1417           1 :                         anSizes.clear();
    1418           1 :                         poQueue.reset();
    1419             : 
    1420           1 :                         CPLErr eErr = MultiThreadedRead(
    1421             :                             nXOff, nYOff, nXSize, nYOff2 - nYOff, pData,
    1422             :                             eBufType, nBandCount, panBandMap, nPixelSpace,
    1423             :                             nLineSpace, nBandSpace);
    1424           1 :                         if (eErr == CE_None)
    1425             :                         {
    1426           1 :                             eErr = MultiThreadedRead(
    1427           1 :                                 nXOff, nYOff2, nXSize, nYOff + nYSize - nYOff2,
    1428             :                                 static_cast<GByte *>(pData) +
    1429           1 :                                     (nYOff2 - nYOff) * nLineSpace,
    1430             :                                 eBufType, nBandCount, panBandMap, nPixelSpace,
    1431             :                                 nLineSpace, nBandSpace);
    1432             :                         }
    1433           1 :                         return eErr;
    1434             :                     }
    1435        9197 :                     nAdviseReadAccBytes += anSizes[nAdviseReadRanges];
    1436             : 
    1437        9197 :                     ++nAdviseReadRanges;
    1438             :                 }
    1439             : 
    1440       11095 :                 ++iJob;
    1441             :             }
    1442             :         }
    1443             :     }
    1444             : 
    1445         233 :     if (sContext.bSuccess)
    1446             :     {
    1447             :         // Potentially start asynchronous fetching of ranges depending on file
    1448             :         // implementation
    1449         233 :         if (nAdviseReadRanges > 0)
    1450             :         {
    1451         106 :             sContext.poHandle->AdviseRead(nAdviseReadRanges, anOffsets.data(),
    1452         106 :                                           anSizes.data());
    1453             :         }
    1454             : 
    1455             :         // We need to do that as threads will access the block cache
    1456         233 :         TemporarilyDropReadWriteLock();
    1457             : 
    1458        4069 :         for (auto &sJob : asJobs)
    1459             :         {
    1460        3836 :             poQueue->SubmitJob(ThreadDecompressionFunc, &sJob);
    1461             :         }
    1462             : 
    1463             :         // Wait for all jobs to have been completed
    1464         233 :         poQueue->WaitCompletion();
    1465             : 
    1466             :         // Undo effect of above TemporarilyDropReadWriteLock()
    1467         233 :         ReacquireReadWriteLock();
    1468             : 
    1469         233 :         sContext.oErrorAccumulator.ReplayErrors();
    1470             :     }
    1471             : 
    1472         233 :     return sContext.bSuccess ? CE_None : CE_Failure;
    1473             : }
    1474             : 
    1475             : /************************************************************************/
    1476             : /*                       FetchBufferVirtualMemIO                        */
    1477             : /************************************************************************/
    1478             : 
    1479             : class FetchBufferVirtualMemIO final
    1480             : {
    1481             :     const GByte *pabySrcData;
    1482             :     size_t nMappingSize;
    1483             :     GByte *pTempBuffer;
    1484             : 
    1485             :   public:
    1486         971 :     FetchBufferVirtualMemIO(const GByte *pabySrcDataIn, size_t nMappingSizeIn,
    1487             :                             GByte *pTempBufferIn)
    1488         971 :         : pabySrcData(pabySrcDataIn), nMappingSize(nMappingSizeIn),
    1489         971 :           pTempBuffer(pTempBufferIn)
    1490             :     {
    1491         971 :     }
    1492             : 
    1493      897395 :     const GByte *FetchBytes(vsi_l_offset nOffset, int nPixels, int nDTSize,
    1494             :                             bool bIsByteSwapped, bool bIsComplex, int nBlockId)
    1495             :     {
    1496      897395 :         if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
    1497             :         {
    1498          24 :             CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
    1499             :                      nBlockId);
    1500          24 :             return nullptr;
    1501             :         }
    1502      897371 :         if (!bIsByteSwapped)
    1503      572847 :             return pabySrcData + nOffset;
    1504      324524 :         memcpy(pTempBuffer, pabySrcData + nOffset,
    1505      324524 :                static_cast<size_t>(nPixels) * nDTSize);
    1506      324524 :         if (bIsComplex)
    1507      159940 :             GDALSwapWords(pTempBuffer, nDTSize / 2, 2 * nPixels, nDTSize / 2);
    1508             :         else
    1509      164584 :             GDALSwapWords(pTempBuffer, nDTSize, nPixels, nDTSize);
    1510      324524 :         return pTempBuffer;
    1511             :     }
    1512             : 
    1513      115046 :     bool FetchBytes(GByte *pabyDstBuffer, vsi_l_offset nOffset, int nPixels,
    1514             :                     int nDTSize, bool bIsByteSwapped, bool bIsComplex,
    1515             :                     int nBlockId)
    1516             :     {
    1517      115046 :         if (nOffset + static_cast<size_t>(nPixels) * nDTSize > nMappingSize)
    1518             :         {
    1519          11 :             CPLError(CE_Failure, CPLE_FileIO, "Missing data for block %d",
    1520             :                      nBlockId);
    1521          11 :             return false;
    1522             :         }
    1523      115035 :         memcpy(pabyDstBuffer, pabySrcData + nOffset,
    1524      115035 :                static_cast<size_t>(nPixels) * nDTSize);
    1525      115035 :         if (bIsByteSwapped)
    1526             :         {
    1527       48082 :             if (bIsComplex)
    1528       26390 :                 GDALSwapWords(pabyDstBuffer, nDTSize / 2, 2 * nPixels,
    1529             :                               nDTSize / 2);
    1530             :             else
    1531       21692 :                 GDALSwapWords(pabyDstBuffer, nDTSize, nPixels, nDTSize);
    1532             :         }
    1533      115035 :         return true;
    1534             :     }
    1535             : 
    1536             :     // cppcheck-suppress unusedStructMember
    1537             :     static const bool bMinimizeIO = false;
    1538             : };
    1539             : 
    1540             : /************************************************************************/
    1541             : /*                            VirtualMemIO()                            */
    1542             : /************************************************************************/
    1543             : 
    1544        1101 : int GTiffDataset::VirtualMemIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    1545             :                                int nXSize, int nYSize, void *pData,
    1546             :                                int nBufXSize, int nBufYSize,
    1547             :                                GDALDataType eBufType, int nBandCount,
    1548             :                                const int *panBandMap, GSpacing nPixelSpace,
    1549             :                                GSpacing nLineSpace, GSpacing nBandSpace,
    1550             :                                GDALRasterIOExtraArg *psExtraArg)
    1551             : {
    1552        1101 :     if (eAccess == GA_Update || eRWFlag == GF_Write || m_bStreamingIn)
    1553           0 :         return -1;
    1554             : 
    1555             :     // Only know how to deal with nearest neighbour in this optimized routine.
    1556        1101 :     if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
    1557         417 :         psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
    1558             :     {
    1559         130 :         return -1;
    1560             :     }
    1561             : 
    1562         971 :     const GDALDataType eDataType = GetRasterBand(1)->GetRasterDataType();
    1563         971 :     const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
    1564         971 :     if (!(m_nCompression == COMPRESSION_NONE &&
    1565         971 :           (m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
    1566         392 :            m_nPhotometric == PHOTOMETRIC_RGB ||
    1567           0 :            m_nPhotometric == PHOTOMETRIC_PALETTE) &&
    1568         971 :           m_nBitsPerSample == nDTSizeBits))
    1569             :     {
    1570           0 :         m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
    1571           0 :         return -1;
    1572             :     }
    1573             : 
    1574         971 :     size_t nMappingSize = 0;
    1575         971 :     GByte *pabySrcData = nullptr;
    1576         971 :     if (STARTS_WITH(m_osFilename.c_str(), "/vsimem/"))
    1577             :     {
    1578         708 :         vsi_l_offset nDataLength = 0;
    1579             :         pabySrcData =
    1580         708 :             VSIGetMemFileBuffer(m_osFilename.c_str(), &nDataLength, FALSE);
    1581         708 :         nMappingSize = static_cast<size_t>(nDataLength);
    1582         708 :         if (pabySrcData == nullptr)
    1583           0 :             return -1;
    1584             :     }
    1585         263 :     else if (m_psVirtualMemIOMapping == nullptr)
    1586             :     {
    1587          11 :         VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
    1588          22 :         if (!CPLIsVirtualMemFileMapAvailable() ||
    1589          11 :             VSIFGetNativeFileDescriptorL(fp) == nullptr)
    1590             :         {
    1591           0 :             m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
    1592           0 :             return -1;
    1593             :         }
    1594          11 :         if (VSIFSeekL(fp, 0, SEEK_END) != 0)
    1595             :         {
    1596           0 :             m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
    1597           0 :             return -1;
    1598             :         }
    1599          11 :         const vsi_l_offset nLength = VSIFTellL(fp);
    1600             :         if (static_cast<size_t>(nLength) != nLength)
    1601             :         {
    1602             :             m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
    1603             :             return -1;
    1604             :         }
    1605          11 :         if (m_eVirtualMemIOUsage == VirtualMemIOEnum::IF_ENOUGH_RAM)
    1606             :         {
    1607           0 :             GIntBig nRAM = CPLGetUsablePhysicalRAM();
    1608           0 :             if (static_cast<GIntBig>(nLength) > nRAM)
    1609             :             {
    1610           0 :                 CPLDebug("GTiff",
    1611             :                          "Not enough RAM to map whole file into memory.");
    1612           0 :                 m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
    1613           0 :                 return -1;
    1614             :             }
    1615             :         }
    1616          11 :         m_psVirtualMemIOMapping = CPLVirtualMemFileMapNew(
    1617             :             fp, 0, nLength, VIRTUALMEM_READONLY, nullptr, nullptr);
    1618          11 :         if (m_psVirtualMemIOMapping == nullptr)
    1619             :         {
    1620           0 :             m_eVirtualMemIOUsage = VirtualMemIOEnum::NO;
    1621           0 :             return -1;
    1622             :         }
    1623          11 :         m_eVirtualMemIOUsage = VirtualMemIOEnum::YES;
    1624             :     }
    1625             : 
    1626         971 :     if (m_psVirtualMemIOMapping)
    1627             :     {
    1628             : #ifdef DEBUG
    1629         263 :         CPLDebug("GTiff", "Using VirtualMemIO");
    1630             : #endif
    1631         263 :         nMappingSize = CPLVirtualMemGetSize(m_psVirtualMemIOMapping);
    1632             :         pabySrcData =
    1633         263 :             static_cast<GByte *>(CPLVirtualMemGetAddr(m_psVirtualMemIOMapping));
    1634             :     }
    1635             : 
    1636         971 :     if (TIFFIsByteSwapped(m_hTIFF) && m_pTempBufferForCommonDirectIO == nullptr)
    1637             :     {
    1638          12 :         const int nDTSize = nDTSizeBits / 8;
    1639          12 :         size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
    1640          24 :             m_nBlockXSize * nDTSize *
    1641          12 :             (m_nPlanarConfig == PLANARCONFIG_CONTIG ? nBands : 1));
    1642          12 :         if (TIFFIsTiled(m_hTIFF))
    1643           6 :             nTempBufferForCommonDirectIOSize *= m_nBlockYSize;
    1644             : 
    1645          12 :         m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
    1646          12 :             VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
    1647          12 :         if (m_pTempBufferForCommonDirectIO == nullptr)
    1648           0 :             return CE_Failure;
    1649             :     }
    1650             :     FetchBufferVirtualMemIO oFetcher(pabySrcData, nMappingSize,
    1651         971 :                                      m_pTempBufferForCommonDirectIO);
    1652             : 
    1653         971 :     return CommonDirectIO(oFetcher, nXOff, nYOff, nXSize, nYSize, pData,
    1654             :                           nBufXSize, nBufYSize, eBufType, nBandCount,
    1655         971 :                           panBandMap, nPixelSpace, nLineSpace, nBandSpace);
    1656             : }
    1657             : 
    1658             : /************************************************************************/
    1659             : /*                      CopyContigByteMultiBand()                       */
    1660             : /************************************************************************/
    1661             : 
    1662        2754 : static inline void CopyContigByteMultiBand(const GByte *CPL_RESTRICT pabySrc,
    1663             :                                            int nSrcStride,
    1664             :                                            GByte *CPL_RESTRICT pabyDest,
    1665             :                                            int nDestStride, int nIters,
    1666             :                                            int nBandCount)
    1667             : {
    1668        2754 :     if (nBandCount == 3)
    1669             :     {
    1670        1620 :         if (nSrcStride == 3 && nDestStride == 4)
    1671             :         {
    1672        2106 :             while (nIters >= 8)
    1673             :             {
    1674        1620 :                 pabyDest[4 * 0 + 0] = pabySrc[3 * 0 + 0];
    1675        1620 :                 pabyDest[4 * 0 + 1] = pabySrc[3 * 0 + 1];
    1676        1620 :                 pabyDest[4 * 0 + 2] = pabySrc[3 * 0 + 2];
    1677        1620 :                 pabyDest[4 * 1 + 0] = pabySrc[3 * 1 + 0];
    1678        1620 :                 pabyDest[4 * 1 + 1] = pabySrc[3 * 1 + 1];
    1679        1620 :                 pabyDest[4 * 1 + 2] = pabySrc[3 * 1 + 2];
    1680        1620 :                 pabyDest[4 * 2 + 0] = pabySrc[3 * 2 + 0];
    1681        1620 :                 pabyDest[4 * 2 + 1] = pabySrc[3 * 2 + 1];
    1682        1620 :                 pabyDest[4 * 2 + 2] = pabySrc[3 * 2 + 2];
    1683        1620 :                 pabyDest[4 * 3 + 0] = pabySrc[3 * 3 + 0];
    1684        1620 :                 pabyDest[4 * 3 + 1] = pabySrc[3 * 3 + 1];
    1685        1620 :                 pabyDest[4 * 3 + 2] = pabySrc[3 * 3 + 2];
    1686        1620 :                 pabyDest[4 * 4 + 0] = pabySrc[3 * 4 + 0];
    1687        1620 :                 pabyDest[4 * 4 + 1] = pabySrc[3 * 4 + 1];
    1688        1620 :                 pabyDest[4 * 4 + 2] = pabySrc[3 * 4 + 2];
    1689        1620 :                 pabyDest[4 * 5 + 0] = pabySrc[3 * 5 + 0];
    1690        1620 :                 pabyDest[4 * 5 + 1] = pabySrc[3 * 5 + 1];
    1691        1620 :                 pabyDest[4 * 5 + 2] = pabySrc[3 * 5 + 2];
    1692        1620 :                 pabyDest[4 * 6 + 0] = pabySrc[3 * 6 + 0];
    1693        1620 :                 pabyDest[4 * 6 + 1] = pabySrc[3 * 6 + 1];
    1694        1620 :                 pabyDest[4 * 6 + 2] = pabySrc[3 * 6 + 2];
    1695        1620 :                 pabyDest[4 * 7 + 0] = pabySrc[3 * 7 + 0];
    1696        1620 :                 pabyDest[4 * 7 + 1] = pabySrc[3 * 7 + 1];
    1697        1620 :                 pabyDest[4 * 7 + 2] = pabySrc[3 * 7 + 2];
    1698        1620 :                 pabySrc += 3 * 8;
    1699        1620 :                 pabyDest += 4 * 8;
    1700        1620 :                 nIters -= 8;
    1701             :             }
    1702         648 :             while (nIters-- > 0)
    1703             :             {
    1704         162 :                 pabyDest[0] = pabySrc[0];
    1705         162 :                 pabyDest[1] = pabySrc[1];
    1706         162 :                 pabyDest[2] = pabySrc[2];
    1707         162 :                 pabySrc += 3;
    1708         162 :                 pabyDest += 4;
    1709             :             }
    1710             :         }
    1711             :         else
    1712             :         {
    1713       53622 :             while (nIters-- > 0)
    1714             :             {
    1715       52488 :                 pabyDest[0] = pabySrc[0];
    1716       52488 :                 pabyDest[1] = pabySrc[1];
    1717       52488 :                 pabyDest[2] = pabySrc[2];
    1718       52488 :                 pabySrc += nSrcStride;
    1719       52488 :                 pabyDest += nDestStride;
    1720             :             }
    1721             :         }
    1722             :     }
    1723             :     else
    1724             :     {
    1725       53622 :         while (nIters-- > 0)
    1726             :         {
    1727      236196 :             for (int iBand = 0; iBand < nBandCount; ++iBand)
    1728      183708 :                 pabyDest[iBand] = pabySrc[iBand];
    1729       52488 :             pabySrc += nSrcStride;
    1730       52488 :             pabyDest += nDestStride;
    1731             :         }
    1732             :     }
    1733        2754 : }
    1734             : 
    1735             : /************************************************************************/
    1736             : /*                           CommonDirectIO()                           */
    1737             : /************************************************************************/
    1738             : 
    1739             : // #define DEBUG_REACHED_VIRTUAL_MEM_IO
    1740             : #ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
    1741             : static int anReachedVirtualMemIO[52] = {0};
    1742             : #define REACHED(x) anReachedVirtualMemIO[x] = 1
    1743             : #else
    1744             : #define REACHED(x)
    1745             : #endif
    1746             : 
    1747             : template <class FetchBuffer>
    1748        1742 : CPLErr GTiffDataset::CommonDirectIO(FetchBuffer &oFetcher, int nXOff, int nYOff,
    1749             :                                     int nXSize, int nYSize, void *pData,
    1750             :                                     int nBufXSize, int nBufYSize,
    1751             :                                     GDALDataType eBufType, int nBandCount,
    1752             :                                     const int *panBandMap, GSpacing nPixelSpace,
    1753             :                                     GSpacing nLineSpace, GSpacing nBandSpace)
    1754             : {
    1755             :     const auto poFirstBand =
    1756        1742 :         cpl::down_cast<GTiffRasterBand *>(GetRasterBand(1));
    1757        1742 :     const GDALDataType eDataType = poFirstBand->GetRasterDataType();
    1758        1742 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
    1759        1742 :     const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eDataType));
    1760        1742 :     const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
    1761             : 
    1762             :     // Get strip offsets.
    1763        1742 :     toff_t *panOffsets = nullptr;
    1764        1742 :     if (!TIFFGetField(m_hTIFF,
    1765        1742 :                       (TIFFIsTiled(m_hTIFF)) ? TIFFTAG_TILEOFFSETS
    1766             :                                              : TIFFTAG_STRIPOFFSETS,
    1767        3484 :                       &panOffsets) ||
    1768        1742 :         panOffsets == nullptr)
    1769             :     {
    1770           0 :         return CE_Failure;
    1771             :     }
    1772             : 
    1773         346 :     bool bUseContigImplementation = m_nPlanarConfig == PLANARCONFIG_CONTIG &&
    1774        2088 :                                     nBandCount > 1 && nBandSpace == nBufDTSize;
    1775        1742 :     if (bUseContigImplementation)
    1776             :     {
    1777         470 :         for (int iBand = 0; iBand < nBandCount; ++iBand)
    1778             :         {
    1779         370 :             const int nBand = panBandMap[iBand];
    1780         370 :             if (nBand != iBand + 1)
    1781             :             {
    1782           0 :                 bUseContigImplementation = false;
    1783           0 :                 break;
    1784             :             }
    1785             :         }
    1786             :     }
    1787             : 
    1788        1742 :     const int nBandsPerBlock =
    1789        1742 :         m_nPlanarConfig == PLANARCONFIG_SEPARATE ? 1 : nBands;
    1790        1742 :     const int nBandsPerBlockDTSize = nBandsPerBlock * nDTSize;
    1791        1742 :     const bool bNoTypeChange = (eDataType == eBufType);
    1792        1742 :     const bool bNoXResampling = (nXSize == nBufXSize);
    1793        1742 :     const bool bNoXResamplingNoTypeChange = (bNoTypeChange && bNoXResampling);
    1794        1742 :     const bool bByteOnly = (bNoTypeChange && nDTSize == 1);
    1795        1742 :     const bool bByteNoXResampling = (bByteOnly && bNoXResamplingNoTypeChange);
    1796        1742 :     const bool bIsByteSwapped = CPL_TO_BOOL(TIFFIsByteSwapped(m_hTIFF));
    1797        1742 :     const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
    1798        1742 :     const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
    1799             : 
    1800        1742 :     int bNoDataSetIn = FALSE;
    1801        1742 :     double dfNoData = poFirstBand->GetNoDataValue(&bNoDataSetIn);
    1802        1742 :     GByte abyNoData = 0;
    1803        1742 :     if (!bNoDataSetIn)
    1804        1742 :         dfNoData = 0;
    1805           0 :     else if (dfNoData >= 0 && dfNoData <= 255)
    1806           0 :         abyNoData = static_cast<GByte>(dfNoData + 0.5);
    1807             : 
    1808             :     // cppcheck-suppress knownConditionTrueFalse
    1809        1542 :     if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) && bNoXResampling &&
    1810        1542 :         (nYSize == nBufYSize) && m_nPlanarConfig == PLANARCONFIG_CONTIG &&
    1811             :         nBandCount > 1)
    1812             :     {
    1813          35 :         GByte *pabyData = static_cast<GByte *>(pData);
    1814         275 :         for (int y = 0; y < nBufYSize;)
    1815             :         {
    1816         242 :             const int nSrcLine = nYOff + y;
    1817         242 :             const int nBlockYOff = nSrcLine / m_nBlockYSize;
    1818         242 :             const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
    1819         242 :             const int nUsedBlockHeight =
    1820         242 :                 std::min(nBufYSize - y, m_nBlockYSize - nYOffsetInBlock);
    1821             : 
    1822         242 :             int nBlockXOff = nXOff / m_nBlockXSize;
    1823         242 :             int nXOffsetInBlock = nXOff % m_nBlockXSize;
    1824         242 :             int nBlockId = poFirstBand->ComputeBlockId(nBlockXOff, nBlockYOff);
    1825             : 
    1826         242 :             int x = 0;
    1827        1200 :             while (x < nBufXSize)
    1828             :             {
    1829         960 :                 const toff_t nCurOffset = panOffsets[nBlockId];
    1830         960 :                 const int nUsedBlockWidth =
    1831         960 :                     std::min(m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
    1832             : 
    1833         960 :                 if (nCurOffset == 0)
    1834             :                 {
    1835             :                     REACHED(30);
    1836        7287 :                     for (int k = 0; k < nUsedBlockHeight; ++k)
    1837             :                     {
    1838        6813 :                         GByte *pabyLocalData =
    1839        6813 :                             pabyData + (y + k) * nLineSpace + x * nPixelSpace;
    1840       33573 :                         for (int iBand = 0; iBand < nBandCount; ++iBand)
    1841             :                         {
    1842       26760 :                             GByte *pabyLocalDataBand =
    1843       26760 :                                 pabyLocalData + iBand * nBandSpace;
    1844             : 
    1845       26760 :                             GDALCopyWords(&dfNoData, GDT_Float64, 0,
    1846             :                                           pabyLocalDataBand, eBufType,
    1847             :                                           static_cast<int>(nPixelSpace),
    1848             :                                           nUsedBlockWidth);
    1849             :                         }
    1850             :                     }
    1851             :                 }
    1852             :                 else
    1853             :                 {
    1854         486 :                     const int nByteOffsetInBlock =
    1855         486 :                         nYOffsetInBlock * m_nBlockXSize * nBandsPerBlockDTSize;
    1856         972 :                     const GByte *pabyLocalSrcDataK0 = oFetcher.FetchBytes(
    1857         486 :                         nCurOffset + nByteOffsetInBlock,
    1858         486 :                         m_nBlockXSize * nUsedBlockHeight * nBandsPerBlock,
    1859             :                         nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
    1860         486 :                     if (pabyLocalSrcDataK0 == nullptr)
    1861           2 :                         return CE_Failure;
    1862             : 
    1863        7468 :                     for (int k = 0; k < nUsedBlockHeight; ++k)
    1864             :                     {
    1865        6984 :                         GByte *pabyLocalData =
    1866        6984 :                             pabyData + (y + k) * nLineSpace + x * nPixelSpace;
    1867        6984 :                         const GByte *pabyLocalSrcData =
    1868             :                             pabyLocalSrcDataK0 +
    1869        6984 :                             (k * m_nBlockXSize + nXOffsetInBlock) *
    1870             :                                 nBandsPerBlockDTSize;
    1871             : 
    1872        6984 :                         if (bUseContigImplementation && nBands == nBandCount &&
    1873        3234 :                             nPixelSpace == nBandsPerBlockDTSize)
    1874             :                         {
    1875             :                             REACHED(31);
    1876        2262 :                             GDALCopyWords(pabyLocalSrcData, eDataType, nDTSize,
    1877             :                                           pabyLocalData, eBufType, nBufDTSize,
    1878        2262 :                                           nUsedBlockWidth * nBands);
    1879             :                         }
    1880             :                         else
    1881             :                         {
    1882             :                             REACHED(32);
    1883       22608 :                             for (int iBand = 0; iBand < nBandCount; ++iBand)
    1884             :                             {
    1885       17886 :                                 GByte *pabyLocalDataBand =
    1886       17886 :                                     pabyLocalData + iBand * nBandSpace;
    1887       17886 :                                 const GByte *pabyLocalSrcDataBand =
    1888             :                                     pabyLocalSrcData +
    1889       17886 :                                     (panBandMap[iBand] - 1) * nDTSize;
    1890             : 
    1891       17886 :                                 GDALCopyWords(pabyLocalSrcDataBand, eDataType,
    1892             :                                               nBandsPerBlockDTSize,
    1893             :                                               pabyLocalDataBand, eBufType,
    1894             :                                               static_cast<int>(nPixelSpace),
    1895             :                                               nUsedBlockWidth);
    1896             :                             }
    1897             :                         }
    1898             :                     }
    1899             :                 }
    1900             : 
    1901         958 :                 nXOffsetInBlock = 0;
    1902         958 :                 ++nBlockXOff;
    1903         958 :                 ++nBlockId;
    1904         958 :                 x += nUsedBlockWidth;
    1905             :             }
    1906             : 
    1907         240 :             y += nUsedBlockHeight;
    1908             :         }
    1909             :     }
    1910             :     // cppcheck-suppress knownConditionTrueFalse
    1911        1472 :     else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
    1912        1472 :              bNoXResampling && (nYSize == nBufYSize))
    1913             :     // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
    1914             :     {
    1915         967 :         for (int iBand = 0; iBand < nBandCount; ++iBand)
    1916             :         {
    1917         488 :             GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
    1918         488 :             const int nBand = panBandMap[iBand];
    1919             :             auto poCurBand =
    1920         488 :                 cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
    1921        3783 :             for (int y = 0; y < nBufYSize;)
    1922             :             {
    1923        3304 :                 const int nSrcLine = nYOff + y;
    1924        3304 :                 const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    1925        3304 :                 const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    1926        3304 :                 const int nUsedBlockHeight =
    1927        3304 :                     std::min(nBufYSize - y, m_nBlockYSize - nYOffsetIm_nBlock);
    1928             : 
    1929        3304 :                 int nBlockXOff = nXOff / m_nBlockXSize;
    1930        3304 :                 int nXOffsetInBlock = nXOff % m_nBlockXSize;
    1931             :                 int nBlockId =
    1932        3304 :                     poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
    1933             : 
    1934        3304 :                 int x = 0;
    1935       16000 :                 while (x < nBufXSize)
    1936             :                 {
    1937       12705 :                     const toff_t nCurOffset = panOffsets[nBlockId];
    1938       12705 :                     const int nUsedBlockWidth = std::min(
    1939       12705 :                         m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
    1940             : 
    1941       12705 :                     if (nCurOffset == 0)
    1942             :                     {
    1943             :                         REACHED(35);
    1944       42642 :                         for (int k = 0; k < nUsedBlockHeight; ++k)
    1945             :                         {
    1946       39858 :                             GByte *pabyLocalData = pabyData +
    1947       39858 :                                                    (y + k) * nLineSpace +
    1948       39858 :                                                    x * nPixelSpace;
    1949             : 
    1950       39858 :                             GDALCopyWords(&dfNoData, GDT_Float64, 0,
    1951             :                                           pabyLocalData, eBufType,
    1952             :                                           static_cast<int>(nPixelSpace),
    1953             :                                           nUsedBlockWidth);
    1954             :                         }
    1955             :                     }
    1956             :                     else
    1957             :                     {
    1958        9921 :                         const int nByteOffsetIm_nBlock = nYOffsetIm_nBlock *
    1959        9921 :                                                          m_nBlockXSize *
    1960             :                                                          nBandsPerBlockDTSize;
    1961       19842 :                         const GByte *pabyLocalSrcDataK0 = oFetcher.FetchBytes(
    1962        9921 :                             nCurOffset + nByteOffsetIm_nBlock,
    1963        9921 :                             m_nBlockXSize * nUsedBlockHeight * nBandsPerBlock,
    1964             :                             nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
    1965        9921 :                         if (pabyLocalSrcDataK0 == nullptr)
    1966           9 :                             return CE_Failure;
    1967             : 
    1968        9912 :                         if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    1969             :                         {
    1970             :                             REACHED(36);
    1971         512 :                             pabyLocalSrcDataK0 += (nBand - 1) * nDTSize;
    1972             :                         }
    1973             :                         else
    1974             :                         {
    1975             :                             REACHED(37);
    1976             :                         }
    1977             : 
    1978      151464 :                         for (int k = 0; k < nUsedBlockHeight; ++k)
    1979             :                         {
    1980      141552 :                             GByte *pabyLocalData = pabyData +
    1981      141552 :                                                    (y + k) * nLineSpace +
    1982      141552 :                                                    x * nPixelSpace;
    1983      141552 :                             const GByte *pabyLocalSrcData =
    1984             :                                 pabyLocalSrcDataK0 +
    1985      141552 :                                 (k * m_nBlockXSize + nXOffsetInBlock) *
    1986             :                                     nBandsPerBlockDTSize;
    1987             : 
    1988      141552 :                             GDALCopyWords(
    1989             :                                 pabyLocalSrcData, eDataType,
    1990             :                                 nBandsPerBlockDTSize, pabyLocalData, eBufType,
    1991             :                                 static_cast<int>(nPixelSpace), nUsedBlockWidth);
    1992             :                         }
    1993             :                     }
    1994             : 
    1995       12696 :                     nXOffsetInBlock = 0;
    1996       12696 :                     ++nBlockXOff;
    1997       12696 :                     ++nBlockId;
    1998       12696 :                     x += nUsedBlockWidth;
    1999             :                 }
    2000             : 
    2001        3295 :                 y += nUsedBlockHeight;
    2002             :             }
    2003             :         }
    2004             :     }
    2005             :     // cppcheck-suppress knownConditionTrueFalse
    2006         248 :     else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF) &&
    2007         248 :              m_nPlanarConfig == PLANARCONFIG_CONTIG && nBandCount > 1)
    2008             :     {
    2009          20 :         GByte *pabyData = static_cast<GByte *>(pData);
    2010          20 :         int anSrcYOffset[256] = {0};
    2011         119 :         for (int y = 0; y < nBufYSize;)
    2012             :         {
    2013         100 :             const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
    2014         100 :             const int nSrcLine = static_cast<int>(dfYOffStart);
    2015         100 :             const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    2016         100 :             const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    2017         100 :             const int nBaseByteOffsetIm_nBlock =
    2018         100 :                 nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
    2019         100 :             int ychunk = 1;
    2020         100 :             int nLastSrcLineK = nSrcLine;
    2021         100 :             anSrcYOffset[0] = 0;
    2022       12064 :             for (int k = 1; k < nBufYSize - y; ++k)
    2023             :             {
    2024       12044 :                 int nSrcLineK =
    2025       12044 :                     nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
    2026       12044 :                 const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
    2027       12044 :                 if (k < 256)
    2028        7544 :                     anSrcYOffset[k] =
    2029        7544 :                         ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
    2030        7544 :                         m_nBlockXSize * nBandsPerBlockDTSize;
    2031       12044 :                 if (nBlockYOffK != m_nBlockYOff)
    2032             :                 {
    2033          80 :                     break;
    2034             :                 }
    2035       11964 :                 ++ychunk;
    2036       11964 :                 nLastSrcLineK = nSrcLineK;
    2037             :             }
    2038         100 :             const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
    2039             :             // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
    2040             : 
    2041         100 :             double dfSrcX = nXOff + 0.5 * dfSrcXInc;
    2042         100 :             int nCurBlockXOff = 0;
    2043         100 :             int nNextBlockXOff = 0;
    2044         100 :             toff_t nCurOffset = 0;
    2045         100 :             const GByte *pabyLocalSrcDataStartLine = nullptr;
    2046       10843 :             for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
    2047             :             {
    2048       10744 :                 const int nSrcPixel = static_cast<int>(dfSrcX);
    2049       10744 :                 if (nSrcPixel >= nNextBlockXOff)
    2050             :                 {
    2051         292 :                     const int nBlockXOff = nSrcPixel / m_nBlockXSize;
    2052         292 :                     nCurBlockXOff = nBlockXOff * m_nBlockXSize;
    2053         292 :                     nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
    2054             :                     const int nBlockId =
    2055         292 :                         poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
    2056         292 :                     nCurOffset = panOffsets[nBlockId];
    2057         292 :                     if (nCurOffset != 0)
    2058             :                     {
    2059         292 :                         pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
    2060         146 :                             nCurOffset + nBaseByteOffsetIm_nBlock,
    2061         146 :                             m_nBlockXSize * nBandsPerBlock * nUsedBlockHeight,
    2062             :                             nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
    2063         146 :                         if (pabyLocalSrcDataStartLine == nullptr)
    2064           1 :                             return CE_Failure;
    2065             :                     }
    2066             :                 }
    2067             : 
    2068       10743 :                 if (nCurOffset == 0)
    2069             :                 {
    2070             :                     REACHED(38);
    2071             : 
    2072      442476 :                     for (int k = 0; k < ychunk; ++k)
    2073             :                     {
    2074      437062 :                         GByte *const pabyLocalData =
    2075      437062 :                             pabyData + (y + k) * nLineSpace + x * nPixelSpace;
    2076     2185310 :                         for (int iBand = 0; iBand < nBandCount; ++iBand)
    2077             :                         {
    2078     1748250 :                             GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2079     1748250 :                                           pabyLocalData + nBandSpace * iBand,
    2080             :                                           eBufType, 0, 1);
    2081             :                         }
    2082             :                     }
    2083             :                 }
    2084             :                 else
    2085             :                 {
    2086        5329 :                     const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
    2087        5329 :                     double dfYOff = dfYOffStart;
    2088        5329 :                     const GByte *const pabyLocalSrcDataK0 =
    2089             :                         pabyLocalSrcDataStartLine +
    2090        5329 :                         nXOffsetInBlock * nBandsPerBlockDTSize;
    2091        5329 :                     GByte *pabyLocalData =
    2092        5329 :                         pabyData + y * nLineSpace + x * nPixelSpace;
    2093      429042 :                     for (int k = 0; k < ychunk;
    2094      423713 :                          ++k, pabyLocalData += nLineSpace)
    2095             :                     {
    2096      423713 :                         const GByte *pabyLocalSrcData = nullptr;
    2097      423713 :                         if (ychunk <= 256)
    2098             :                         {
    2099             :                             REACHED(39);
    2100      231713 :                             pabyLocalSrcData =
    2101      231713 :                                 pabyLocalSrcDataK0 + anSrcYOffset[k];
    2102             :                         }
    2103             :                         else
    2104             :                         {
    2105             :                             REACHED(40);
    2106      192000 :                             const int nYOffsetIm_nBlockK =
    2107      192000 :                                 static_cast<int>(dfYOff) % m_nBlockYSize;
    2108             :                             // CPLAssert(
    2109             :                             //     nYOffsetIm_nBlockK - nYOffsetIm_nBlock <=
    2110             :                             //     nUsedBlockHeight);
    2111      192000 :                             pabyLocalSrcData =
    2112             :                                 pabyLocalSrcDataK0 +
    2113      192000 :                                 (nYOffsetIm_nBlockK - nYOffsetIm_nBlock) *
    2114      192000 :                                     m_nBlockXSize * nBandsPerBlockDTSize;
    2115      192000 :                             dfYOff += dfSrcYInc;
    2116             :                         }
    2117             : 
    2118      423713 :                         if (bByteOnly)
    2119             :                         {
    2120             :                             REACHED(41);
    2121     2118560 :                             for (int iBand = 0; iBand < nBandCount; ++iBand)
    2122             :                             {
    2123     1694850 :                                 GByte *pabyLocalDataBand =
    2124     1694850 :                                     pabyLocalData + iBand * nBandSpace;
    2125     1694850 :                                 const GByte *pabyLocalSrcDataBand =
    2126     1694850 :                                     pabyLocalSrcData + (panBandMap[iBand] - 1);
    2127     1694850 :                                 *pabyLocalDataBand = *pabyLocalSrcDataBand;
    2128             :                             }
    2129             :                         }
    2130             :                         else
    2131             :                         {
    2132             :                             REACHED(42);
    2133           0 :                             for (int iBand = 0; iBand < nBandCount; ++iBand)
    2134             :                             {
    2135           0 :                                 GByte *pabyLocalDataBand =
    2136           0 :                                     pabyLocalData + iBand * nBandSpace;
    2137           0 :                                 const GByte *pabyLocalSrcDataBand =
    2138             :                                     pabyLocalSrcData +
    2139           0 :                                     (panBandMap[iBand] - 1) * nDTSize;
    2140             : 
    2141           0 :                                 GDALCopyWords(pabyLocalSrcDataBand, eDataType,
    2142             :                                               0, pabyLocalDataBand, eBufType, 0,
    2143             :                                               1);
    2144             :                             }
    2145             :                         }
    2146             :                     }
    2147             :                 }
    2148             :             }
    2149             : 
    2150          99 :             y += ychunk;
    2151             :         }
    2152             :     }
    2153             :     // cppcheck-suppress knownConditionTrueFalse
    2154         228 :     else if (FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
    2155             :     // && (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1) )
    2156             :     {
    2157         452 :         for (int iBand = 0; iBand < nBandCount; ++iBand)
    2158             :         {
    2159         228 :             GByte *pabyData = static_cast<GByte *>(pData) + iBand * nBandSpace;
    2160         228 :             const int nBand = panBandMap[iBand];
    2161             :             auto poCurBand =
    2162         228 :                 cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
    2163         228 :             int anSrcYOffset[256] = {0};
    2164        1392 :             for (int y = 0; y < nBufYSize;)
    2165             :             {
    2166        1168 :                 const double dfYOffStart = nYOff + (y + 0.5) * dfSrcYInc;
    2167        1168 :                 const int nSrcLine = static_cast<int>(dfYOffStart);
    2168        1168 :                 const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    2169        1168 :                 const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    2170        1168 :                 const int nBaseByteOffsetIm_nBlock =
    2171        1168 :                     nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
    2172        1168 :                 int ychunk = 1;
    2173        1168 :                 int nLastSrcLineK = nSrcLine;
    2174        1168 :                 anSrcYOffset[0] = 0;
    2175      125300 :                 for (int k = 1; k < nBufYSize - y; ++k)
    2176             :                 {
    2177      125072 :                     const int nSrcLineK =
    2178      125072 :                         nYOff + static_cast<int>((y + k + 0.5) * dfSrcYInc);
    2179      125072 :                     const int nBlockYOffK = nSrcLineK / m_nBlockYSize;
    2180      125072 :                     if (k < 256)
    2181       80072 :                         anSrcYOffset[k] =
    2182       80072 :                             ((nSrcLineK % m_nBlockYSize) - nYOffsetIm_nBlock) *
    2183       80072 :                             m_nBlockXSize * nBandsPerBlockDTSize;
    2184      125072 :                     if (nBlockYOffK != m_nBlockYOff)
    2185             :                     {
    2186         940 :                         break;
    2187             :                     }
    2188      124132 :                     ++ychunk;
    2189      124132 :                     nLastSrcLineK = nSrcLineK;
    2190             :                 }
    2191        1168 :                 const int nUsedBlockHeight = nLastSrcLineK - nSrcLine + 1;
    2192             :                 // CPLAssert(nUsedBlockHeight <= m_nBlockYSize);
    2193             : 
    2194        1168 :                 double dfSrcX = nXOff + 0.5 * dfSrcXInc;
    2195        1168 :                 int nCurBlockXOff = 0;
    2196        1168 :                 int nNextBlockXOff = 0;
    2197        1168 :                 toff_t nCurOffset = 0;
    2198        1168 :                 const GByte *pabyLocalSrcDataStartLine = nullptr;
    2199      138796 :                 for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
    2200             :                 {
    2201      137632 :                     int nSrcPixel = static_cast<int>(dfSrcX);
    2202      137632 :                     if (nSrcPixel >= nNextBlockXOff)
    2203             :                     {
    2204        3424 :                         const int nBlockXOff = nSrcPixel / m_nBlockXSize;
    2205        3424 :                         nCurBlockXOff = nBlockXOff * m_nBlockXSize;
    2206        3424 :                         nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
    2207             :                         const int nBlockId =
    2208        3424 :                             poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
    2209        3424 :                         nCurOffset = panOffsets[nBlockId];
    2210        3424 :                         if (nCurOffset != 0)
    2211             :                         {
    2212        5392 :                             pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
    2213        2696 :                                 nCurOffset + nBaseByteOffsetIm_nBlock,
    2214        2696 :                                 m_nBlockXSize * nBandsPerBlock *
    2215             :                                     nUsedBlockHeight,
    2216             :                                 nDTSize, bIsByteSwapped, bIsComplex, nBlockId);
    2217        2696 :                             if (pabyLocalSrcDataStartLine == nullptr)
    2218           4 :                                 return CE_Failure;
    2219             : 
    2220        2692 :                             if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    2221             :                             {
    2222             :                                 REACHED(45);
    2223          72 :                                 pabyLocalSrcDataStartLine +=
    2224          72 :                                     (nBand - 1) * nDTSize;
    2225             :                             }
    2226             :                             else
    2227             :                             {
    2228             :                                 REACHED(46);
    2229             :                             }
    2230             :                         }
    2231             :                     }
    2232             : 
    2233      137628 :                     if (nCurOffset == 0)
    2234             :                     {
    2235             :                         REACHED(47);
    2236             : 
    2237     2215820 :                         for (int k = 0; k < ychunk; ++k)
    2238             :                         {
    2239     2185310 :                             GByte *const pabyLocalData = pabyData +
    2240     2185310 :                                                          (y + k) * nLineSpace +
    2241     2185310 :                                                          x * nPixelSpace;
    2242             : 
    2243     2185310 :                             GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2244             :                                           pabyLocalData, eBufType, 0, 1);
    2245             :                         }
    2246             :                     }
    2247             :                     else
    2248             :                     {
    2249      107116 :                         const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
    2250      107116 :                         double dfYOff = dfYOffStart;
    2251      107116 :                         const GByte *const pabyLocalSrcDataK0 =
    2252             :                             pabyLocalSrcDataStartLine +
    2253      107116 :                             nXOffsetInBlock * nBandsPerBlockDTSize;
    2254      107116 :                         GByte *pabyLocalData =
    2255      107116 :                             pabyData + y * nLineSpace + x * nPixelSpace;
    2256     7952300 :                         for (int k = 0; k < ychunk;
    2257     7845180 :                              ++k, pabyLocalData += nLineSpace)
    2258             :                         {
    2259     7845180 :                             const GByte *pabyLocalSrcData = nullptr;
    2260     7845180 :                             if (ychunk <= 256)
    2261             :                             {
    2262             :                                 REACHED(48);
    2263     4773180 :                                 pabyLocalSrcData =
    2264     4773180 :                                     pabyLocalSrcDataK0 + anSrcYOffset[k];
    2265             :                             }
    2266             :                             else
    2267             :                             {
    2268             :                                 REACHED(49);
    2269     3072000 :                                 const int nYOffsetIm_nBlockK =
    2270     3072000 :                                     static_cast<int>(dfYOff) % m_nBlockYSize;
    2271             :                                 // CPLAssert(
    2272             :                                 //     nYOffsetIm_nBlockK - nYOffsetIm_nBlock <=
    2273             :                                 //     nUsedBlockHeight);
    2274     3072000 :                                 pabyLocalSrcData =
    2275             :                                     pabyLocalSrcDataK0 +
    2276     3072000 :                                     (nYOffsetIm_nBlockK - nYOffsetIm_nBlock) *
    2277     3072000 :                                         m_nBlockXSize * nBandsPerBlockDTSize;
    2278     3072000 :                                 dfYOff += dfSrcYInc;
    2279             :                             }
    2280             : 
    2281     7845180 :                             if (bByteOnly)
    2282             :                             {
    2283             :                                 REACHED(50);
    2284             : 
    2285     2121160 :                                 *pabyLocalData = *pabyLocalSrcData;
    2286             :                             }
    2287             :                             else
    2288             :                             {
    2289             :                                 REACHED(51);
    2290             : 
    2291     5724020 :                                 GDALCopyWords(pabyLocalSrcData, eDataType, 0,
    2292             :                                               pabyLocalData, eBufType, 0, 1);
    2293             :                             }
    2294             :                         }
    2295             :                     }
    2296             :                 }
    2297             : 
    2298        1164 :                 y += ychunk;
    2299             :             }
    2300             :         }
    2301             :     }
    2302         971 :     else if (bUseContigImplementation)
    2303             :     {
    2304             :         // cppcheck-suppress knownConditionTrueFalse
    2305          72 :         if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
    2306             :         {
    2307          37 :             GByte *pabyData = static_cast<GByte *>(pData);
    2308        2777 :             for (int y = 0; y < nBufYSize; ++y)
    2309             :             {
    2310        2742 :                 const int nSrcLine =
    2311        2742 :                     nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
    2312        2742 :                 const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    2313        2742 :                 const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    2314        2742 :                 const int nBaseByteOffsetIm_nBlock =
    2315        2742 :                     nYOffsetIm_nBlock * m_nBlockXSize * nBandsPerBlockDTSize;
    2316             : 
    2317        2742 :                 if (bNoXResampling)
    2318             :                 {
    2319        2535 :                     GByte *pabyLocalData = pabyData + y * nLineSpace;
    2320        2535 :                     int nBlockXOff = nXOff / m_nBlockXSize;
    2321        2535 :                     int nXOffsetInBlock = nXOff % m_nBlockXSize;
    2322             :                     int nBlockId =
    2323        2535 :                         poFirstBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
    2324             : 
    2325        2535 :                     int x = 0;
    2326       12372 :                     while (x < nBufXSize)
    2327             :                     {
    2328        9838 :                         const int nByteOffsetIm_nBlock =
    2329             :                             nBaseByteOffsetIm_nBlock +
    2330        9838 :                             nXOffsetInBlock * nBandsPerBlockDTSize;
    2331        9838 :                         const toff_t nCurOffset = panOffsets[nBlockId];
    2332        9838 :                         const int nUsedBlockWidth = std::min(
    2333        9838 :                             m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
    2334             : 
    2335        9838 :                         int nIters = nUsedBlockWidth;
    2336        9838 :                         if (nCurOffset == 0)
    2337             :                         {
    2338        3768 :                             if (bByteNoXResampling)
    2339             :                             {
    2340             :                                 REACHED(0);
    2341       46560 :                                 while (nIters-- > 0)
    2342             :                                 {
    2343      217886 :                                     for (int iBand = 0; iBand < nBandCount;
    2344             :                                          ++iBand)
    2345             :                                     {
    2346      172964 :                                         pabyLocalData[iBand] = abyNoData;
    2347             :                                     }
    2348       44922 :                                     pabyLocalData += nPixelSpace;
    2349             :                                 }
    2350             :                             }
    2351             :                             else
    2352             :                             {
    2353             :                                 REACHED(1);
    2354       60500 :                                 while (nIters-- > 0)
    2355             :                                 {
    2356       58370 :                                     GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2357             :                                                   pabyLocalData, eBufType,
    2358             :                                                   static_cast<int>(nBandSpace),
    2359             :                                                   nBandCount);
    2360       58370 :                                     pabyLocalData += nPixelSpace;
    2361             :                                 }
    2362             :                             }
    2363             :                         }
    2364             :                         else
    2365             :                         {
    2366        6070 :                             if (bNoTypeChange && nBands == nBandCount &&
    2367        4612 :                                 nPixelSpace == nBandsPerBlockDTSize)
    2368             :                             {
    2369             :                                 REACHED(2);
    2370        3397 :                                 if (!oFetcher.FetchBytes(
    2371             :                                         pabyLocalData,
    2372        3397 :                                         nCurOffset + nByteOffsetIm_nBlock,
    2373             :                                         nIters * nBandsPerBlock, nDTSize,
    2374             :                                         bIsByteSwapped, bIsComplex, nBlockId))
    2375             :                                 {
    2376           1 :                                     return CE_Failure;
    2377             :                                 }
    2378        3396 :                                 pabyLocalData +=
    2379        3396 :                                     nIters * nBandsPerBlock * nDTSize;
    2380             :                             }
    2381             :                             else
    2382             :                             {
    2383        5346 :                                 const GByte *pabyLocalSrcData =
    2384             :                                     oFetcher.FetchBytes(
    2385        2673 :                                         nCurOffset + nByteOffsetIm_nBlock,
    2386             :                                         nIters * nBandsPerBlock, nDTSize,
    2387             :                                         bIsByteSwapped, bIsComplex, nBlockId);
    2388        2673 :                                 if (pabyLocalSrcData == nullptr)
    2389           0 :                                     return CE_Failure;
    2390        2673 :                                 if (bByteNoXResampling)
    2391             :                                 {
    2392             :                                     REACHED(3);
    2393        1944 :                                     CopyContigByteMultiBand(
    2394             :                                         pabyLocalSrcData, nBandsPerBlockDTSize,
    2395             :                                         pabyLocalData,
    2396             :                                         static_cast<int>(nPixelSpace), nIters,
    2397             :                                         nBandCount);
    2398        1944 :                                     pabyLocalData += nIters * nPixelSpace;
    2399             :                                 }
    2400             :                                 else
    2401             :                                 {
    2402             :                                     REACHED(4);
    2403       20412 :                                     while (nIters-- > 0)
    2404             :                                     {
    2405       19683 :                                         GDALCopyWords(
    2406             :                                             pabyLocalSrcData, eDataType,
    2407             :                                             nDTSize, pabyLocalData, eBufType,
    2408             :                                             static_cast<int>(nBandSpace),
    2409             :                                             nBandCount);
    2410       19683 :                                         pabyLocalSrcData +=
    2411       19683 :                                             nBandsPerBlockDTSize;
    2412       19683 :                                         pabyLocalData += nPixelSpace;
    2413             :                                     }
    2414             :                                 }
    2415             :                             }
    2416             :                         }
    2417             : 
    2418        9837 :                         nXOffsetInBlock = 0;
    2419        9837 :                         ++nBlockXOff;
    2420        9837 :                         ++nBlockId;
    2421        9837 :                         x += nUsedBlockWidth;
    2422             :                     }
    2423             :                 }
    2424             :                 else  // Contig, tiled, potential resampling & data type change.
    2425             :                 {
    2426         207 :                     const GByte *pabyLocalSrcDataStartLine = nullptr;
    2427         207 :                     GByte *pabyLocalData = pabyData + y * nLineSpace;
    2428         207 :                     double dfSrcX = nXOff + 0.5 * dfSrcXInc;
    2429         207 :                     int nCurBlockXOff = 0;
    2430         207 :                     int nNextBlockXOff = 0;
    2431         207 :                     toff_t nCurOffset = 0;
    2432        8373 :                     for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
    2433             :                     {
    2434        8167 :                         int nSrcPixel = static_cast<int>(dfSrcX);
    2435        8167 :                         if (nSrcPixel >= nNextBlockXOff)
    2436             :                         {
    2437         611 :                             const int nBlockXOff = nSrcPixel / m_nBlockXSize;
    2438         611 :                             nCurBlockXOff = nBlockXOff * m_nBlockXSize;
    2439         611 :                             nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
    2440         611 :                             const int nBlockId = poFirstBand->ComputeBlockId(
    2441             :                                 nBlockXOff, m_nBlockYOff);
    2442         611 :                             nCurOffset = panOffsets[nBlockId];
    2443         611 :                             if (nCurOffset != 0)
    2444             :                             {
    2445         726 :                                 pabyLocalSrcDataStartLine = oFetcher.FetchBytes(
    2446         363 :                                     nCurOffset + nBaseByteOffsetIm_nBlock,
    2447         363 :                                     m_nBlockXSize * nBandsPerBlock, nDTSize,
    2448             :                                     bIsByteSwapped, bIsComplex, nBlockId);
    2449         363 :                                 if (pabyLocalSrcDataStartLine == nullptr)
    2450           1 :                                     return CE_Failure;
    2451             :                             }
    2452             :                         }
    2453        8166 :                         const int nXOffsetInBlock = nSrcPixel - nCurBlockXOff;
    2454             : 
    2455        8166 :                         if (nCurOffset == 0)
    2456             :                         {
    2457             :                             REACHED(5);
    2458        3364 :                             GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2459             :                                           pabyLocalData, eBufType,
    2460             :                                           static_cast<int>(nBandSpace),
    2461             :                                           nBandCount);
    2462        3364 :                             pabyLocalData += nPixelSpace;
    2463             :                         }
    2464             :                         else
    2465             :                         {
    2466        4802 :                             const GByte *pabyLocalSrcData =
    2467             :                                 pabyLocalSrcDataStartLine +
    2468        4802 :                                 nXOffsetInBlock * nBandsPerBlockDTSize;
    2469             : 
    2470             :                             REACHED(6);
    2471        4802 :                             if (bByteOnly)
    2472             :                             {
    2473       20809 :                                 for (int iBand = 0; iBand < nBands; ++iBand)
    2474       16007 :                                     pabyLocalData[iBand] =
    2475       16007 :                                         pabyLocalSrcData[iBand];
    2476             :                             }
    2477             :                             else
    2478             :                             {
    2479           0 :                                 GDALCopyWords(pabyLocalSrcData, eDataType,
    2480             :                                               nDTSize, pabyLocalData, eBufType,
    2481             :                                               static_cast<int>(nBandSpace),
    2482             :                                               nBandCount);
    2483             :                             }
    2484        4802 :                             pabyLocalData += nPixelSpace;
    2485             :                         }
    2486             :                     }
    2487             :                 }
    2488             :             }
    2489             :         }
    2490             :         else  // Contig, striped organized.
    2491             :         {
    2492          35 :             GByte *pabyData = static_cast<GByte *>(pData);
    2493        2618 :             for (int y = 0; y < nBufYSize; ++y)
    2494             :             {
    2495        2585 :                 const int nSrcLine =
    2496        2585 :                     nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
    2497        2585 :                 const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    2498        2585 :                 const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    2499        2585 :                 const int nBlockId = m_nBlockYOff;
    2500        2585 :                 const toff_t nCurOffset = panOffsets[nBlockId];
    2501        2585 :                 if (nCurOffset == 0)
    2502             :                 {
    2503             :                     REACHED(7);
    2504      107696 :                     for (int x = 0; x < nBufXSize; ++x)
    2505             :                     {
    2506      106656 :                         GDALCopyWords(
    2507             :                             &dfNoData, GDT_Float64, 0,
    2508      106656 :                             pabyData + y * nLineSpace + x * nPixelSpace,
    2509             :                             eBufType, static_cast<int>(nBandSpace), nBandCount);
    2510             :                     }
    2511             :                 }
    2512             :                 else
    2513             :                 {
    2514        1545 :                     GByte *pabyLocalData = pabyData + y * nLineSpace;
    2515        1545 :                     const int nBaseByteOffsetIm_nBlock =
    2516        1545 :                         (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
    2517             :                         nBandsPerBlockDTSize;
    2518             : 
    2519        1545 :                     if (bNoXResamplingNoTypeChange && nBands == nBandCount &&
    2520         936 :                         nPixelSpace == nBandsPerBlockDTSize)
    2521             :                     {
    2522             :                         REACHED(8);
    2523         693 :                         if (!oFetcher.FetchBytes(
    2524             :                                 pabyLocalData,
    2525         693 :                                 nCurOffset + nBaseByteOffsetIm_nBlock,
    2526             :                                 nXSize * nBandsPerBlock, nDTSize,
    2527             :                                 bIsByteSwapped, bIsComplex, nBlockId))
    2528             :                         {
    2529           1 :                             return CE_Failure;
    2530             :                         }
    2531             :                     }
    2532             :                     else
    2533             :                     {
    2534        1704 :                         const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
    2535         852 :                             nCurOffset + nBaseByteOffsetIm_nBlock,
    2536             :                             nXSize * nBandsPerBlock, nDTSize, bIsByteSwapped,
    2537             :                             bIsComplex, nBlockId);
    2538         852 :                         if (pabyLocalSrcData == nullptr)
    2539           1 :                             return CE_Failure;
    2540             : 
    2541         851 :                         if (bByteNoXResampling)
    2542             :                         {
    2543             :                             REACHED(9);
    2544         486 :                             CopyContigByteMultiBand(
    2545             :                                 pabyLocalSrcData, nBandsPerBlockDTSize,
    2546             :                                 pabyLocalData, static_cast<int>(nPixelSpace),
    2547             :                                 nBufXSize, nBandCount);
    2548             :                         }
    2549         365 :                         else if (bByteOnly)
    2550             :                         {
    2551             :                             REACHED(10);
    2552         122 :                             double dfSrcX = 0.5 * dfSrcXInc;
    2553        4924 :                             for (int x = 0; x < nBufXSize;
    2554             :                                  ++x, dfSrcX += dfSrcXInc)
    2555             :                             {
    2556        4802 :                                 const int nSrcPixelMinusXOff =
    2557             :                                     static_cast<int>(dfSrcX);
    2558       24010 :                                 for (int iBand = 0; iBand < nBandCount; ++iBand)
    2559             :                                 {
    2560       19208 :                                     pabyLocalData[x * nPixelSpace + iBand] =
    2561             :                                         pabyLocalSrcData
    2562       19208 :                                             [nSrcPixelMinusXOff *
    2563       19208 :                                                  nBandsPerBlockDTSize +
    2564             :                                              iBand];
    2565             :                                 }
    2566             :                             }
    2567             :                         }
    2568             :                         else
    2569             :                         {
    2570             :                             REACHED(11);
    2571         243 :                             double dfSrcX = 0.5 * dfSrcXInc;
    2572       19926 :                             for (int x = 0; x < nBufXSize;
    2573             :                                  ++x, dfSrcX += dfSrcXInc)
    2574             :                             {
    2575       19683 :                                 int nSrcPixelMinusXOff =
    2576             :                                     static_cast<int>(dfSrcX);
    2577       19683 :                                 GDALCopyWords(
    2578       19683 :                                     pabyLocalSrcData + nSrcPixelMinusXOff *
    2579             :                                                            nBandsPerBlockDTSize,
    2580             :                                     eDataType, nDTSize,
    2581       19683 :                                     pabyLocalData + x * nPixelSpace, eBufType,
    2582             :                                     static_cast<int>(nBandSpace), nBandCount);
    2583             :                             }
    2584             :                         }
    2585             :                     }
    2586             :                 }
    2587             :             }
    2588             :         }
    2589             :     }
    2590             :     else  // Non-contig reading case.
    2591             :     {
    2592             :         // cppcheck-suppress knownConditionTrueFalse
    2593         899 :         if (!FetchBuffer::bMinimizeIO && TIFFIsTiled(m_hTIFF))
    2594             :         {
    2595        1455 :             for (int iBand = 0; iBand < nBandCount; ++iBand)
    2596             :             {
    2597        1059 :                 const int nBand = panBandMap[iBand];
    2598             :                 auto poCurBand =
    2599        1059 :                     cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
    2600        1059 :                 GByte *const pabyData =
    2601        1059 :                     static_cast<GByte *>(pData) + iBand * nBandSpace;
    2602      284551 :                 for (int y = 0; y < nBufYSize; ++y)
    2603             :                 {
    2604      283506 :                     const int nSrcLine =
    2605      283506 :                         nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
    2606      283506 :                     const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    2607      283506 :                     const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    2608             : 
    2609      283506 :                     int nBaseByteOffsetIm_nBlock = nYOffsetIm_nBlock *
    2610      283506 :                                                    m_nBlockXSize *
    2611             :                                                    nBandsPerBlockDTSize;
    2612      283506 :                     if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    2613             :                     {
    2614             :                         REACHED(12);
    2615       66004 :                         nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
    2616             :                     }
    2617             :                     else
    2618             :                     {
    2619             :                         REACHED(13);
    2620             :                     }
    2621             : 
    2622      283506 :                     if (bNoXResampling)
    2623             :                     {
    2624       67404 :                         GByte *pabyLocalData = pabyData + y * nLineSpace;
    2625       67404 :                         int nBlockXOff = nXOff / m_nBlockXSize;
    2626             :                         int nBlockId =
    2627       67404 :                             poCurBand->ComputeBlockId(nBlockXOff, m_nBlockYOff);
    2628       67404 :                         int nXOffsetInBlock = nXOff % m_nBlockXSize;
    2629             : 
    2630       67404 :                         int x = 0;
    2631      331986 :                         while (x < nBufXSize)
    2632             :                         {
    2633      264592 :                             const int nByteOffsetIm_nBlock =
    2634             :                                 nBaseByteOffsetIm_nBlock +
    2635      264592 :                                 nXOffsetInBlock * nBandsPerBlockDTSize;
    2636      264592 :                             const toff_t nCurOffset = panOffsets[nBlockId];
    2637      264592 :                             const int nUsedBlockWidth = std::min(
    2638      264592 :                                 m_nBlockXSize - nXOffsetInBlock, nBufXSize - x);
    2639      264592 :                             int nIters = nUsedBlockWidth;
    2640             : 
    2641      264592 :                             if (nCurOffset == 0)
    2642             :                             {
    2643             :                                 REACHED(16);
    2644       52038 :                                 GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2645             :                                               pabyLocalData, eBufType,
    2646             :                                               static_cast<int>(nPixelSpace),
    2647             :                                               nIters);
    2648       52038 :                                 pabyLocalData += nIters * nPixelSpace;
    2649             :                             }
    2650             :                             else
    2651             :                             {
    2652      212554 :                                 if (bNoTypeChange &&
    2653      177871 :                                     nPixelSpace == nBandsPerBlockDTSize)
    2654             :                                 {
    2655             :                                     REACHED(17);
    2656       84112 :                                     if (!oFetcher.FetchBytes(
    2657             :                                             pabyLocalData,
    2658       84112 :                                             nCurOffset + nByteOffsetIm_nBlock,
    2659       84112 :                                             (nIters - 1) * nBandsPerBlock + 1,
    2660             :                                             nDTSize, bIsByteSwapped, bIsComplex,
    2661             :                                             nBlockId))
    2662             :                                     {
    2663           4 :                                         return CE_Failure;
    2664             :                                     }
    2665       84108 :                                     pabyLocalData += nIters * nPixelSpace;
    2666             :                                 }
    2667             :                                 else
    2668             :                                 {
    2669      256884 :                                     const GByte *pabyLocalSrcData =
    2670             :                                         oFetcher.FetchBytes(
    2671      128442 :                                             nCurOffset + nByteOffsetIm_nBlock,
    2672      128442 :                                             (nIters - 1) * nBandsPerBlock + 1,
    2673             :                                             nDTSize, bIsByteSwapped, bIsComplex,
    2674             :                                             nBlockId);
    2675      128442 :                                     if (pabyLocalSrcData == nullptr)
    2676           6 :                                         return CE_Failure;
    2677             : 
    2678             :                                     REACHED(18);
    2679      128436 :                                     GDALCopyWords(pabyLocalSrcData, eDataType,
    2680             :                                                   nBandsPerBlockDTSize,
    2681             :                                                   pabyLocalData, eBufType,
    2682             :                                                   static_cast<int>(nPixelSpace),
    2683             :                                                   nIters);
    2684      128436 :                                     pabyLocalData += nIters * nPixelSpace;
    2685             :                                 }
    2686             :                             }
    2687             : 
    2688      264582 :                             nXOffsetInBlock = 0;
    2689      264582 :                             ++nBlockXOff;
    2690      264582 :                             ++nBlockId;
    2691      264582 :                             x += nUsedBlockWidth;
    2692             :                         }
    2693             :                     }
    2694             :                     else
    2695             :                     {
    2696             :                         // Non-contig reading, tiled, potential resampling and
    2697             :                         // data type change.
    2698             : 
    2699      216102 :                         const GByte *pabyLocalSrcDataStartLine = nullptr;
    2700      216102 :                         GByte *pabyLocalData = pabyData + y * nLineSpace;
    2701      216102 :                         double dfSrcX = nXOff + 0.5 * dfSrcXInc;
    2702      216102 :                         int nCurBlockXOff = 0;
    2703      216102 :                         int nNextBlockXOff = 0;
    2704      216102 :                         toff_t nCurOffset = 0;
    2705    16883500 :                         for (int x = 0; x < nBufXSize; ++x, dfSrcX += dfSrcXInc)
    2706             :                         {
    2707    16667400 :                             const int nSrcPixel = static_cast<int>(dfSrcX);
    2708    16667400 :                             if (nSrcPixel >= nNextBlockXOff)
    2709             :                             {
    2710      648202 :                                 const int nBlockXOff =
    2711      648202 :                                     nSrcPixel / m_nBlockXSize;
    2712      648202 :                                 nCurBlockXOff = nBlockXOff * m_nBlockXSize;
    2713      648202 :                                 nNextBlockXOff = nCurBlockXOff + m_nBlockXSize;
    2714      648202 :                                 const int nBlockId = poCurBand->ComputeBlockId(
    2715             :                                     nBlockXOff, m_nBlockYOff);
    2716      648202 :                                 nCurOffset = panOffsets[nBlockId];
    2717      648202 :                                 if (nCurOffset != 0)
    2718             :                                 {
    2719      998236 :                                     pabyLocalSrcDataStartLine =
    2720             :                                         oFetcher.FetchBytes(
    2721      499118 :                                             nCurOffset +
    2722      499118 :                                                 nBaseByteOffsetIm_nBlock,
    2723      499118 :                                             m_nBlockXSize * nBandsPerBlock,
    2724             :                                             nDTSize, bIsByteSwapped, bIsComplex,
    2725             :                                             nBlockId);
    2726      499118 :                                     if (pabyLocalSrcDataStartLine == nullptr)
    2727           4 :                                         return CE_Failure;
    2728             :                                 }
    2729             :                             }
    2730    16667400 :                             const int nXOffsetInBlock =
    2731             :                                 nSrcPixel - nCurBlockXOff;
    2732             : 
    2733    16667400 :                             if (nCurOffset == 0)
    2734             :                             {
    2735             :                                 REACHED(21);
    2736     3920100 :                                 GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2737             :                                               pabyLocalData, eBufType, 0, 1);
    2738     3920100 :                                 pabyLocalData += nPixelSpace;
    2739             :                             }
    2740             :                             else
    2741             :                             {
    2742    12747300 :                                 const GByte *pabyLocalSrcData =
    2743             :                                     pabyLocalSrcDataStartLine +
    2744    12747300 :                                     nXOffsetInBlock * nBandsPerBlockDTSize;
    2745             : 
    2746             :                                 REACHED(22);
    2747    12747300 :                                 if (bByteOnly)
    2748             :                                 {
    2749     5192440 :                                     *pabyLocalData = *pabyLocalSrcData;
    2750             :                                 }
    2751             :                                 else
    2752             :                                 {
    2753     7554900 :                                     GDALCopyWords(pabyLocalSrcData, eDataType,
    2754             :                                                   0, pabyLocalData, eBufType, 0,
    2755             :                                                   1);
    2756             :                                 }
    2757    12747300 :                                 pabyLocalData += nPixelSpace;
    2758             :                             }
    2759             :                         }
    2760             :                     }
    2761             :                 }
    2762             :             }
    2763             :         }
    2764             :         else  // Non-contig reading, striped.
    2765             :         {
    2766        1796 :             for (int iBand = 0; iBand < nBandCount; ++iBand)
    2767             :             {
    2768        1324 :                 const int nBand = panBandMap[iBand];
    2769        1324 :                 GByte *pabyData =
    2770        1324 :                     static_cast<GByte *>(pData) + iBand * nBandSpace;
    2771      356944 :                 for (int y = 0; y < nBufYSize; ++y)
    2772             :                 {
    2773      355637 :                     const int nSrcLine =
    2774      355637 :                         nYOff + static_cast<int>((y + 0.5) * dfSrcYInc);
    2775      355637 :                     const int m_nBlockYOff = nSrcLine / m_nBlockYSize;
    2776      355637 :                     const int nYOffsetIm_nBlock = nSrcLine % m_nBlockYSize;
    2777      355637 :                     int nBlockId = m_nBlockYOff;
    2778      355637 :                     if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    2779             :                     {
    2780             :                         REACHED(23);
    2781      282397 :                         nBlockId += m_nBlocksPerBand * (nBand - 1);
    2782             :                     }
    2783             :                     else
    2784             :                     {
    2785             :                         REACHED(24);
    2786             :                     }
    2787      355637 :                     const toff_t nCurOffset = panOffsets[nBlockId];
    2788      355637 :                     if (nCurOffset == 0)
    2789             :                     {
    2790             :                         REACHED(25);
    2791       62846 :                         GDALCopyWords(&dfNoData, GDT_Float64, 0,
    2792       62846 :                                       pabyData + y * nLineSpace, eBufType,
    2793             :                                       static_cast<int>(nPixelSpace), nBufXSize);
    2794             :                     }
    2795             :                     else
    2796             :                     {
    2797      292791 :                         int nBaseByteOffsetIm_nBlock =
    2798      292791 :                             (nYOffsetIm_nBlock * m_nBlockXSize + nXOff) *
    2799             :                             nBandsPerBlockDTSize;
    2800      292791 :                         if (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    2801       43815 :                             nBaseByteOffsetIm_nBlock += (nBand - 1) * nDTSize;
    2802             : 
    2803      292791 :                         GByte *pabyLocalData = pabyData + y * nLineSpace;
    2804      292791 :                         if (bNoXResamplingNoTypeChange &&
    2805       56217 :                             nPixelSpace == nBandsPerBlockDTSize)
    2806             :                         {
    2807             :                             REACHED(26);
    2808       26844 :                             if (!oFetcher.FetchBytes(
    2809             :                                     pabyLocalData,
    2810       26844 :                                     nCurOffset + nBaseByteOffsetIm_nBlock,
    2811       26844 :                                     (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
    2812             :                                     bIsByteSwapped, bIsComplex, nBlockId))
    2813             :                             {
    2814           5 :                                 return CE_Failure;
    2815             :                             }
    2816             :                         }
    2817             :                         else
    2818             :                         {
    2819      531894 :                             const GByte *pabyLocalSrcData = oFetcher.FetchBytes(
    2820      265947 :                                 nCurOffset + nBaseByteOffsetIm_nBlock,
    2821      265947 :                                 (nXSize - 1) * nBandsPerBlock + 1, nDTSize,
    2822             :                                 bIsByteSwapped, bIsComplex, nBlockId);
    2823      265947 :                             if (pabyLocalSrcData == nullptr)
    2824          12 :                                 return CE_Failure;
    2825             : 
    2826      265935 :                             if (bNoXResamplingNoTypeChange)
    2827             :                             {
    2828             :                                 REACHED(27);
    2829       29366 :                                 GDALCopyWords(pabyLocalSrcData, eDataType,
    2830             :                                               nBandsPerBlockDTSize,
    2831             :                                               pabyLocalData, eBufType,
    2832             :                                               static_cast<int>(nPixelSpace),
    2833             :                                               nBufXSize);
    2834             :                             }
    2835      236569 :                             else if (bByteOnly)
    2836             :                             {
    2837             :                                 REACHED(28);
    2838       73619 :                                 double dfSrcX = 0.5 * dfSrcXInc;
    2839     5778430 :                                 for (int x = 0; x < nBufXSize;
    2840             :                                      ++x, dfSrcX += dfSrcXInc)
    2841             :                                 {
    2842     5704810 :                                     const int nSrcPixelMinusXOff =
    2843             :                                         static_cast<int>(dfSrcX);
    2844     5704810 :                                     pabyLocalData[x * nPixelSpace] =
    2845     5704810 :                                         pabyLocalSrcData[nSrcPixelMinusXOff *
    2846             :                                                          nBandsPerBlockDTSize];
    2847             :                                 }
    2848             :                             }
    2849             :                             else
    2850             :                             {
    2851             :                                 REACHED(29);
    2852      162950 :                                 double dfSrcX = 0.5 * dfSrcXInc;
    2853    12817000 :                                 for (int x = 0; x < nBufXSize;
    2854             :                                      ++x, dfSrcX += dfSrcXInc)
    2855             :                                 {
    2856    12654100 :                                     const int nSrcPixelMinusXOff =
    2857             :                                         static_cast<int>(dfSrcX);
    2858    12654100 :                                     GDALCopyWords(pabyLocalSrcData +
    2859    12654100 :                                                       nSrcPixelMinusXOff *
    2860             :                                                           nBandsPerBlockDTSize,
    2861             :                                                   eDataType, 0,
    2862    12654100 :                                                   pabyLocalData +
    2863    12654100 :                                                       x * nPixelSpace,
    2864             :                                                   eBufType, 0, 1);
    2865             :                                 }
    2866             :                             }
    2867             :                         }
    2868             :                     }
    2869             :                 }
    2870             :             }
    2871             :         }
    2872             :     }
    2873             : 
    2874        1691 :     return CE_None;
    2875             : }
    2876             : 
    2877             : /************************************************************************/
    2878             : /*                              DirectIO()                              */
    2879             : /************************************************************************/
    2880             : 
    2881         771 : CPLErr GTiffDataset::CommonDirectIOClassic(
    2882             :     FetchBufferDirectIO &oFetcher, int nXOff, int nYOff, int nXSize, int nYSize,
    2883             :     void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
    2884             :     int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
    2885             :     GSpacing nLineSpace, GSpacing nBandSpace)
    2886             : {
    2887         771 :     return CommonDirectIO<FetchBufferDirectIO>(
    2888             :         oFetcher, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
    2889         771 :         eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace);
    2890             : }
    2891             : 
    2892             : /************************************************************************/
    2893             : /*                              DirectIO()                              */
    2894             : /************************************************************************/
    2895             : 
    2896             : // Reads directly bytes from the file using ReadMultiRange(), and by-pass
    2897             : // block reading. Restricted to simple TIFF configurations
    2898             : // (uncompressed data, standard data types). Particularly useful to extract
    2899             : // sub-windows of data on a large /vsicurl dataset).
    2900             : // Returns -1 if DirectIO() can't be supported on that file.
    2901             : 
    2902         472 : int GTiffDataset::DirectIO(GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize,
    2903             :                            int nYSize, void *pData, int nBufXSize,
    2904             :                            int nBufYSize, GDALDataType eBufType, int nBandCount,
    2905             :                            const int *panBandMap, GSpacing nPixelSpace,
    2906             :                            GSpacing nLineSpace, GSpacing nBandSpace,
    2907             :                            GDALRasterIOExtraArg *psExtraArg)
    2908             : {
    2909         472 :     auto poProtoBand = cpl::down_cast<GTiffRasterBand *>(papoBands[0]);
    2910         472 :     const GDALDataType eDataType = poProtoBand->GetRasterDataType();
    2911         472 :     const int nDTSizeBits = GDALGetDataTypeSizeBits(eDataType);
    2912         944 :     if (!(eRWFlag == GF_Read && m_nCompression == COMPRESSION_NONE &&
    2913         472 :           (m_nPhotometric == PHOTOMETRIC_MINISBLACK ||
    2914         188 :            m_nPhotometric == PHOTOMETRIC_RGB ||
    2915           0 :            m_nPhotometric == PHOTOMETRIC_PALETTE) &&
    2916         472 :           poProtoBand->IsBaseGTiffClass()))
    2917             :     {
    2918           0 :         return -1;
    2919             :     }
    2920         472 :     Crystalize();
    2921             : 
    2922             :     // Only know how to deal with nearest neighbour in this optimized routine.
    2923         472 :     if ((nXSize != nBufXSize || nYSize != nBufYSize) && psExtraArg != nullptr &&
    2924         182 :         psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
    2925             :     {
    2926          30 :         return -1;
    2927             :     }
    2928             : 
    2929             :     // If the file is band interleave or only one band is requested, then
    2930             :     // fallback to band DirectIO.
    2931         442 :     bool bUseBandRasterIO = false;
    2932         442 :     if (m_nPlanarConfig == PLANARCONFIG_SEPARATE || nBandCount == 1)
    2933             :     {
    2934         324 :         bUseBandRasterIO = true;
    2935             :     }
    2936             :     else
    2937             :     {
    2938             :         // For simplicity, only deals with "naturally ordered" bands.
    2939         546 :         for (int iBand = 0; iBand < nBandCount; ++iBand)
    2940             :         {
    2941         436 :             if (panBandMap[iBand] != iBand + 1)
    2942             :             {
    2943           8 :                 bUseBandRasterIO = true;
    2944           8 :                 break;
    2945             :             }
    2946             :         }
    2947             :     }
    2948         442 :     if (bUseBandRasterIO)
    2949             :     {
    2950         332 :         CPLErr eErr = CE_None;
    2951        1628 :         for (int iBand = 0; eErr == CE_None && iBand < nBandCount; ++iBand)
    2952             :         {
    2953             :             eErr =
    2954        1296 :                 GetRasterBand(panBandMap[iBand])
    2955        2592 :                     ->RasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2956        1296 :                                static_cast<GByte *>(pData) + iBand * nBandSpace,
    2957             :                                nBufXSize, nBufYSize, eBufType, nPixelSpace,
    2958             :                                nLineSpace, psExtraArg);
    2959             :         }
    2960         332 :         return eErr;
    2961             :     }
    2962             : 
    2963             : #if DEBUG_VERBOSE
    2964             :     CPLDebug("GTiff", "DirectIO(%d,%d,%d,%d -> %dx%d)", nXOff, nYOff, nXSize,
    2965             :              nYSize, nBufXSize, nBufYSize);
    2966             : #endif
    2967             : 
    2968             :     // No need to look if overviews can satisfy the request as it has already */
    2969             :     // been done in GTiffDataset::IRasterIO().
    2970             : 
    2971             :     // Make sure that TIFFTAG_STRIPOFFSETS is up-to-date.
    2972         110 :     if (eAccess == GA_Update)
    2973             :     {
    2974           0 :         FlushCache(false);
    2975           0 :         VSI_TIFFFlushBufferedWrite(TIFFClientdata(m_hTIFF));
    2976             :     }
    2977             : 
    2978         110 :     if (TIFFIsTiled(m_hTIFF))
    2979             :     {
    2980          55 :         const int nDTSize = nDTSizeBits / 8;
    2981          55 :         const size_t nTempBufferForCommonDirectIOSize = static_cast<size_t>(
    2982         110 :             static_cast<GPtrDiff_t>(m_nBlockXSize) * m_nBlockYSize * nDTSize *
    2983          55 :             ((m_nPlanarConfig == PLANARCONFIG_CONTIG) ? nBands : 1));
    2984          55 :         if (m_pTempBufferForCommonDirectIO == nullptr)
    2985             :         {
    2986           0 :             m_pTempBufferForCommonDirectIO = static_cast<GByte *>(
    2987           0 :                 VSI_MALLOC_VERBOSE(nTempBufferForCommonDirectIOSize));
    2988           0 :             if (m_pTempBufferForCommonDirectIO == nullptr)
    2989           0 :                 return CE_Failure;
    2990             :         }
    2991             : 
    2992          55 :         VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
    2993             :         FetchBufferDirectIO oFetcher(fp, m_pTempBufferForCommonDirectIO,
    2994          55 :                                      nTempBufferForCommonDirectIOSize);
    2995             : 
    2996          55 :         return CommonDirectIOClassic(oFetcher, nXOff, nYOff, nXSize, nYSize,
    2997             :                                      pData, nBufXSize, nBufYSize, eBufType,
    2998             :                                      nBandCount, panBandMap, nPixelSpace,
    2999          55 :                                      nLineSpace, nBandSpace);
    3000             :     }
    3001             : 
    3002             :     // Get strip offsets.
    3003          55 :     toff_t *panTIFFOffsets = nullptr;
    3004         110 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panTIFFOffsets) ||
    3005          55 :         panTIFFOffsets == nullptr)
    3006             :     {
    3007           0 :         return CE_Failure;
    3008             :     }
    3009             : 
    3010             :     // Sub-sampling or over-sampling can only be done at last stage.
    3011          55 :     int nReqXSize = nXSize;
    3012             :     // Can do sub-sampling at the extraction stage.
    3013          55 :     const int nReqYSize = std::min(nBufYSize, nYSize);
    3014             :     void **ppData =
    3015          55 :         static_cast<void **>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(void *)));
    3016             :     vsi_l_offset *panOffsets = static_cast<vsi_l_offset *>(
    3017          55 :         VSI_MALLOC_VERBOSE(nReqYSize * sizeof(vsi_l_offset)));
    3018             :     size_t *panSizes =
    3019          55 :         static_cast<size_t *>(VSI_MALLOC_VERBOSE(nReqYSize * sizeof(size_t)));
    3020          55 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
    3021          55 :     void *pTmpBuffer = nullptr;
    3022          55 :     int eErr = CE_None;
    3023          55 :     int nContigBands = nBands;
    3024          55 :     const int nSrcPixelSize = nDTSize * nContigBands;
    3025             : 
    3026          55 :     if (ppData == nullptr || panOffsets == nullptr || panSizes == nullptr)
    3027             :     {
    3028           0 :         eErr = CE_Failure;
    3029             :     }
    3030             :     // For now we always allocate a temp buffer as it is easier.
    3031             :     else
    3032             :     // if( nXSize != nBufXSize || nYSize != nBufYSize ||
    3033             :     //   eBufType != eDataType ||
    3034             :     //   nPixelSpace != GDALGetDataTypeSizeBytes(eBufType) ||
    3035             :     //   check if the user buffer is large enough )
    3036             :     {
    3037             :         // We need a temporary buffer for over-sampling/sub-sampling
    3038             :         // and/or data type conversion.
    3039          55 :         pTmpBuffer = VSI_MALLOC3_VERBOSE(nReqXSize, nReqYSize, nSrcPixelSize);
    3040          55 :         if (pTmpBuffer == nullptr)
    3041           0 :             eErr = CE_Failure;
    3042             :     }
    3043             : 
    3044             :     // Prepare data extraction.
    3045          55 :     const double dfSrcYInc = nYSize / static_cast<double>(nBufYSize);
    3046             : 
    3047        2312 :     for (int iLine = 0; eErr == CE_None && iLine < nReqYSize; ++iLine)
    3048             :     {
    3049        2257 :         ppData[iLine] = static_cast<GByte *>(pTmpBuffer) +
    3050        2257 :                         static_cast<size_t>(iLine) * nReqXSize * nSrcPixelSize;
    3051        2257 :         int nSrcLine = 0;
    3052        2257 :         if (nBufYSize < nYSize)  // Sub-sampling in y.
    3053         164 :             nSrcLine = nYOff + static_cast<int>((iLine + 0.5) * dfSrcYInc);
    3054             :         else
    3055        2093 :             nSrcLine = nYOff + iLine;
    3056             : 
    3057        2257 :         const int nBlockXOff = 0;
    3058        2257 :         const int nBlockYOff = nSrcLine / m_nBlockYSize;
    3059        2257 :         const int nYOffsetInBlock = nSrcLine % m_nBlockYSize;
    3060             :         const int nBlockId =
    3061        2257 :             poProtoBand->ComputeBlockId(nBlockXOff, nBlockYOff);
    3062             : 
    3063        2257 :         panOffsets[iLine] = panTIFFOffsets[nBlockId];
    3064        2257 :         if (panOffsets[iLine] == 0)  // We don't support sparse files.
    3065          27 :             eErr = -1;
    3066             : 
    3067        2257 :         panOffsets[iLine] +=
    3068        2257 :             (nXOff +
    3069        2257 :              static_cast<vsi_l_offset>(nYOffsetInBlock) * m_nBlockXSize) *
    3070        2257 :             nSrcPixelSize;
    3071        2257 :         panSizes[iLine] = static_cast<size_t>(nReqXSize) * nSrcPixelSize;
    3072             :     }
    3073             : 
    3074             :     // Extract data from the file.
    3075          55 :     if (eErr == CE_None)
    3076             :     {
    3077          28 :         VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
    3078             :         const int nRet =
    3079          28 :             VSIFReadMultiRangeL(nReqYSize, ppData, panOffsets, panSizes, fp);
    3080          28 :         if (nRet != 0)
    3081           3 :             eErr = CE_Failure;
    3082             :     }
    3083             : 
    3084             :     // Byte-swap if necessary.
    3085          55 :     if (eErr == CE_None && TIFFIsByteSwapped(m_hTIFF))
    3086             :     {
    3087           0 :         for (int iLine = 0; iLine < nReqYSize; ++iLine)
    3088             :         {
    3089           0 :             if (GDALDataTypeIsComplex(eDataType))
    3090           0 :                 GDALSwapWords(ppData[iLine], nDTSize / 2,
    3091           0 :                               2 * nReqXSize * nContigBands, nDTSize / 2);
    3092             :             else
    3093           0 :                 GDALSwapWords(ppData[iLine], nDTSize, nReqXSize * nContigBands,
    3094             :                               nDTSize);
    3095             :         }
    3096             :     }
    3097             : 
    3098             :     // Over-sampling/sub-sampling and/or data type conversion.
    3099          55 :     const double dfSrcXInc = nXSize / static_cast<double>(nBufXSize);
    3100          55 :     if (eErr == CE_None && pTmpBuffer != nullptr)
    3101             :     {
    3102        7462 :         for (int iY = 0; iY < nBufYSize; ++iY)
    3103             :         {
    3104       14874 :             const int iSrcY = nBufYSize <= nYSize
    3105        7437 :                                   ? iY
    3106        5832 :                                   : static_cast<int>((iY + 0.5) * dfSrcYInc);
    3107             :             // Optimization: no resampling, no data type change, number of
    3108             :             // bands requested == number of bands and buffer is packed
    3109             :             // pixel-interleaved.
    3110        7437 :             if (nBufXSize == nXSize && nContigBands == nBandCount &&
    3111         786 :                 eDataType == eBufType && nBandSpace == nDTSize &&
    3112         474 :                 nPixelSpace == nBandCount * nBandSpace)
    3113             :             {
    3114         312 :                 memcpy(static_cast<GByte *>(pData) + iY * nLineSpace,
    3115         312 :                        ppData[iSrcY],
    3116         312 :                        static_cast<size_t>(nReqXSize * nPixelSpace));
    3117             :             }
    3118             :             // Other optimization: no resampling, no data type change,
    3119             :             // data type is Byte/Int8.
    3120        7125 :             else if (nBufXSize == nXSize && eDataType == eBufType &&
    3121           0 :                      (eDataType == GDT_UInt8 || eDataType == GDT_Int8))
    3122             :             {
    3123         808 :                 GByte *pabySrcData = static_cast<GByte *>(ppData[iSrcY]);
    3124         808 :                 GByte *pabyDstData =
    3125         808 :                     static_cast<GByte *>(pData) + iY * nLineSpace;
    3126         808 :                 if (nBandSpace == 1 && nPixelSpace > nBandCount)
    3127             :                 {
    3128             :                     // Buffer is pixel-interleaved (with some stridding
    3129             :                     // between pixels).
    3130         324 :                     CopyContigByteMultiBand(
    3131             :                         pabySrcData, nSrcPixelSize, pabyDstData,
    3132             :                         static_cast<int>(nPixelSpace), nBufXSize, nBandCount);
    3133             :                 }
    3134             :                 else
    3135             :                 {
    3136        2248 :                     for (int iBand = 0; iBand < nBandCount; ++iBand)
    3137             :                     {
    3138        1764 :                         GDALCopyWords(
    3139        1764 :                             pabySrcData + iBand, GDT_UInt8, nSrcPixelSize,
    3140        1764 :                             pabyDstData + iBand * nBandSpace, GDT_UInt8,
    3141             :                             static_cast<int>(nPixelSpace), nBufXSize);
    3142             :                     }
    3143         808 :                 }
    3144             :             }
    3145             :             else  // General case.
    3146             :             {
    3147       31585 :                 for (int iBand = 0; iBand < nBandCount; ++iBand)
    3148             :                 {
    3149       25268 :                     GByte *pabySrcData =
    3150       25268 :                         static_cast<GByte *>(ppData[iSrcY]) + iBand * nDTSize;
    3151       25268 :                     GByte *pabyDstData = static_cast<GByte *>(pData) +
    3152       25268 :                                          iBand * nBandSpace + iY * nLineSpace;
    3153       25268 :                     if ((eDataType == GDT_UInt8 && eBufType == GDT_UInt8) ||
    3154           0 :                         (eDataType == GDT_Int8 && eBufType == GDT_Int8))
    3155             :                     {
    3156       23972 :                         double dfSrcX = 0.5 * dfSrcXInc;
    3157     1718820 :                         for (int iX = 0; iX < nBufXSize;
    3158     1694850 :                              ++iX, dfSrcX += dfSrcXInc)
    3159             :                         {
    3160     1694850 :                             int iSrcX = static_cast<int>(dfSrcX);
    3161     1694850 :                             pabyDstData[iX * nPixelSpace] =
    3162     1694850 :                                 pabySrcData[iSrcX * nSrcPixelSize];
    3163       23972 :                         }
    3164             :                     }
    3165             :                     else
    3166             :                     {
    3167        1296 :                         double dfSrcX = 0.5 * dfSrcXInc;
    3168      106272 :                         for (int iX = 0; iX < nBufXSize;
    3169      104976 :                              ++iX, dfSrcX += dfSrcXInc)
    3170             :                         {
    3171      104976 :                             int iSrcX = static_cast<int>(dfSrcX);
    3172      104976 :                             GDALCopyWords(pabySrcData + iSrcX * nSrcPixelSize,
    3173             :                                           eDataType, 0,
    3174      104976 :                                           pabyDstData + iX * nPixelSpace,
    3175             :                                           eBufType, 0, 1);
    3176             :                         }
    3177             :                     }
    3178             :                 }
    3179             :             }
    3180             :         }
    3181             :     }
    3182             : 
    3183          55 :     CPLFree(pTmpBuffer);
    3184          55 :     CPLFree(ppData);
    3185          55 :     CPLFree(panOffsets);
    3186          55 :     CPLFree(panSizes);
    3187             : 
    3188          55 :     return eErr;
    3189             : }
    3190             : 
    3191             : /************************************************************************/
    3192             : /*                             ReadStrile()                             */
    3193             : /************************************************************************/
    3194             : 
    3195     2132580 : bool GTiffDataset::ReadStrile(int nBlockId, void *pOutputBuffer,
    3196             :                               GPtrDiff_t nBlockReqSize)
    3197             : {
    3198             :     // Optimization by which we can save some libtiff buffer copy
    3199     2132580 :     std::pair<vsi_l_offset, vsi_l_offset> oPair;
    3200     2132580 :     if (
    3201             : #if TIFFLIB_VERSION <= 20220520 && !defined(INTERNAL_LIBTIFF)
    3202             :         // There's a bug, up to libtiff 4.4.0, in TIFFReadFromUserBuffer()
    3203             :         // which clears the TIFF_CODERSETUP flag of tif->tif_flags, which
    3204             :         // causes the codec SetupDecode method to be called for each strile,
    3205             :         // whereas it should normally be called only for the first decoded one.
    3206             :         // For JPEG, that causes TIFFjpeg_read_header() to be called. Most
    3207             :         // of the time, that works. But for some files, at some point, the
    3208             :         // libjpeg machinery is not in the appropriate state for that.
    3209             :         m_nCompression != COMPRESSION_JPEG &&
    3210             : #endif
    3211     2132580 :         m_oCacheStrileToOffsetByteCount.tryGet(nBlockId, oPair))
    3212             :     {
    3213             :         // For the mask, use the parent TIFF handle to get cached ranges
    3214         333 :         auto th = TIFFClientdata(m_poImageryDS && m_bMaskInterleavedWithImagery
    3215          93 :                                      ? m_poImageryDS->m_hTIFF
    3216             :                                      : m_hTIFF);
    3217         480 :         void *pInputBuffer = VSI_TIFFGetCachedRange(
    3218         240 :             th, oPair.first, static_cast<size_t>(oPair.second));
    3219         480 :         if (pInputBuffer &&
    3220         240 :             TIFFReadFromUserBuffer(m_hTIFF, nBlockId, pInputBuffer,
    3221         240 :                                    static_cast<size_t>(oPair.second),
    3222             :                                    pOutputBuffer, nBlockReqSize))
    3223             :         {
    3224         240 :             return true;
    3225             :         }
    3226             :     }
    3227             : 
    3228             :     // For debugging
    3229     2132340 :     if (m_poBaseDS)
    3230        3532 :         m_poBaseDS->m_bHasUsedReadEncodedAPI = true;
    3231             :     else
    3232     2128810 :         m_bHasUsedReadEncodedAPI = true;
    3233             : 
    3234             : #if 0
    3235             :     // Can be useful to test TIFFReadFromUserBuffer() for local files
    3236             :     VSILFILE* fpTIF = VSI_TIFFGetVSILFile(TIFFClientdata( m_hTIFF ));
    3237             :     std::vector<GByte> tmp(TIFFGetStrileByteCount(m_hTIFF, nBlockId));
    3238             :     VSIFSeekL(fpTIF, TIFFGetStrileOffset(m_hTIFF, nBlockId), SEEK_SET);
    3239             :     VSIFReadL(&tmp[0], 1, TIFFGetStrileByteCount(m_hTIFF, nBlockId), fpTIF);
    3240             :     if( !TIFFReadFromUserBuffer( m_hTIFF, nBlockId,
    3241             :                                 &tmp[0], tmp.size(),
    3242             :                                 pOutputBuffer, nBlockReqSize ) )
    3243             :     {
    3244             :         return false;
    3245             :     }
    3246             : #else
    3247             :     // Set to 1 to allow GTiffErrorHandler to implement limitation on error
    3248             :     // messages
    3249     2132340 :     GTIFFGetThreadLocalLibtiffError() = 1;
    3250     2132340 :     if (TIFFIsTiled(m_hTIFF))
    3251             :     {
    3252       30309 :         if (TIFFReadEncodedTile(m_hTIFF, nBlockId, pOutputBuffer,
    3253       30343 :                                 nBlockReqSize) == -1 &&
    3254          34 :             !m_bIgnoreReadErrors)
    3255             :         {
    3256          34 :             CPLError(CE_Failure, CPLE_AppDefined,
    3257             :                      "TIFFReadEncodedTile() failed.");
    3258          34 :             GTIFFGetThreadLocalLibtiffError() = 0;
    3259          34 :             return false;
    3260             :         }
    3261             :     }
    3262             :     else
    3263             :     {
    3264     2102030 :         if (TIFFReadEncodedStrip(m_hTIFF, nBlockId, pOutputBuffer,
    3265     2102110 :                                  nBlockReqSize) == -1 &&
    3266          76 :             !m_bIgnoreReadErrors)
    3267             :         {
    3268          75 :             CPLError(CE_Failure, CPLE_AppDefined,
    3269             :                      "TIFFReadEncodedStrip() failed.");
    3270          75 :             GTIFFGetThreadLocalLibtiffError() = 0;
    3271          75 :             return false;
    3272             :         }
    3273             :     }
    3274     2132230 :     GTIFFGetThreadLocalLibtiffError() = 0;
    3275             : #endif
    3276     2132230 :     return true;
    3277             : }
    3278             : 
    3279             : /************************************************************************/
    3280             : /*                            LoadBlockBuf()                            */
    3281             : /*                                                                      */
    3282             : /*      Load working block buffer with request block (tile/strip).      */
    3283             : /************************************************************************/
    3284             : 
    3285      231426 : CPLErr GTiffDataset::LoadBlockBuf(int nBlockId, bool bReadFromDisk)
    3286             : 
    3287             : {
    3288      231426 :     if (m_nLoadedBlock == nBlockId && m_pabyBlockBuf != nullptr)
    3289      140342 :         return CE_None;
    3290             : 
    3291             :     /* -------------------------------------------------------------------- */
    3292             :     /*      If we have a dirty loaded block, flush it out first.            */
    3293             :     /* -------------------------------------------------------------------- */
    3294       91084 :     if (m_nLoadedBlock != -1 && m_bLoadedBlockDirty)
    3295             :     {
    3296        4577 :         const CPLErr eErr = FlushBlockBuf();
    3297        4577 :         if (eErr != CE_None)
    3298           0 :             return eErr;
    3299             :     }
    3300             : 
    3301             :     /* -------------------------------------------------------------------- */
    3302             :     /*      Get block size.                                                 */
    3303             :     /* -------------------------------------------------------------------- */
    3304       91084 :     const GPtrDiff_t nBlockBufSize = static_cast<GPtrDiff_t>(
    3305       91084 :         TIFFIsTiled(m_hTIFF) ? TIFFTileSize(m_hTIFF) : TIFFStripSize(m_hTIFF));
    3306       91084 :     if (!nBlockBufSize)
    3307             :     {
    3308           0 :         ReportError(CE_Failure, CPLE_AppDefined,
    3309             :                     "Bogus block size; unable to allocate a buffer.");
    3310           0 :         return CE_Failure;
    3311             :     }
    3312             : 
    3313             :     /* -------------------------------------------------------------------- */
    3314             :     /*      Allocate a temporary buffer for this strip.                     */
    3315             :     /* -------------------------------------------------------------------- */
    3316       91084 :     if (m_pabyBlockBuf == nullptr)
    3317             :     {
    3318        7270 :         m_pabyBlockBuf =
    3319        7270 :             static_cast<GByte *>(VSI_CALLOC_VERBOSE(1, nBlockBufSize));
    3320        7270 :         if (m_pabyBlockBuf == nullptr)
    3321             :         {
    3322           1 :             return CE_Failure;
    3323             :         }
    3324             :     }
    3325             : 
    3326       91083 :     if (m_nLoadedBlock == nBlockId)
    3327        4838 :         return CE_None;
    3328             : 
    3329             :     /* -------------------------------------------------------------------- */
    3330             :     /*  When called from ::IWriteBlock in separate cases (or in single band */
    3331             :     /*  geotiffs), the ::IWriteBlock will override the content of the buffer*/
    3332             :     /*  with pImage, so we don't need to read data from disk                */
    3333             :     /* -------------------------------------------------------------------- */
    3334       86245 :     if (!bReadFromDisk || m_bStreamingOut)
    3335             :     {
    3336       35291 :         m_nLoadedBlock = nBlockId;
    3337       35291 :         return CE_None;
    3338             :     }
    3339             : 
    3340             :     // libtiff 3.X doesn't like mixing read&write of JPEG compressed blocks
    3341             :     // The below hack is necessary due to another hack that consist in
    3342             :     // writing zero block to force creation of JPEG tables.
    3343       50954 :     if (nBlockId == 0 && m_bDontReloadFirstBlock)
    3344             :     {
    3345           0 :         m_bDontReloadFirstBlock = false;
    3346           0 :         memset(m_pabyBlockBuf, 0, nBlockBufSize);
    3347           0 :         m_nLoadedBlock = nBlockId;
    3348           0 :         return CE_None;
    3349             :     }
    3350             : 
    3351             :     /* -------------------------------------------------------------------- */
    3352             :     /*      The bottom most partial tiles and strips are sometimes only     */
    3353             :     /*      partially encoded.  This code reduces the requested data so     */
    3354             :     /*      an error won't be reported in this case. (#1179)                */
    3355             :     /*      We exclude tiled WEBP, because as it is a new codec, whole tiles*/
    3356             :     /*      are written by libtiff. This helps avoiding creating a temporary*/
    3357             :     /*      decode buffer.                                                  */
    3358             :     /* -------------------------------------------------------------------- */
    3359       50954 :     auto nBlockReqSize = nBlockBufSize;
    3360       50954 :     const int nBlockYOff = (nBlockId % m_nBlocksPerBand) / m_nBlocksPerRow;
    3361             : 
    3362       52282 :     if (nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize &&
    3363        1328 :         !(m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF)))
    3364             :     {
    3365        1325 :         nBlockReqSize =
    3366        1325 :             (nBlockBufSize / m_nBlockYSize) *
    3367        1325 :             (m_nBlockYSize -
    3368             :              static_cast<int>(
    3369        1325 :                  (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
    3370        1325 :                  nRasterYSize));
    3371        1325 :         memset(m_pabyBlockBuf, 0, nBlockBufSize);
    3372             :     }
    3373             : 
    3374             :     /* -------------------------------------------------------------------- */
    3375             :     /*      If we don't have this block already loaded, and we know it      */
    3376             :     /*      doesn't yet exist on disk, just zero the memory buffer and      */
    3377             :     /*      pretend we loaded it.                                           */
    3378             :     /* -------------------------------------------------------------------- */
    3379       50954 :     bool bErrOccurred = false;
    3380       50954 :     if (!IsBlockAvailable(nBlockId, nullptr, nullptr, &bErrOccurred))
    3381             :     {
    3382         797 :         memset(m_pabyBlockBuf, 0, nBlockBufSize);
    3383         797 :         m_nLoadedBlock = nBlockId;
    3384         797 :         if (bErrOccurred)
    3385           0 :             return CE_Failure;
    3386         797 :         return CE_None;
    3387             :     }
    3388             : 
    3389             :     /* -------------------------------------------------------------------- */
    3390             :     /*      Load the block, if it isn't our current block.                  */
    3391             :     /* -------------------------------------------------------------------- */
    3392       50157 :     CPLErr eErr = CE_None;
    3393             : 
    3394       50157 :     if (!ReadStrile(nBlockId, m_pabyBlockBuf, nBlockReqSize))
    3395             :     {
    3396          26 :         memset(m_pabyBlockBuf, 0, nBlockBufSize);
    3397          26 :         eErr = CE_Failure;
    3398             :     }
    3399             : 
    3400       50157 :     if (eErr == CE_None)
    3401             :     {
    3402       50941 :         if (m_nCompression == COMPRESSION_WEBP && TIFFIsTiled(m_hTIFF) &&
    3403         810 :             nBlockYOff * m_nBlockYSize > nRasterYSize - m_nBlockYSize)
    3404             :         {
    3405           3 :             const auto nValidBytes =
    3406           3 :                 (nBlockBufSize / m_nBlockYSize) *
    3407           3 :                 (m_nBlockYSize -
    3408             :                  static_cast<int>(
    3409           3 :                      (static_cast<GIntBig>(nBlockYOff + 1) * m_nBlockYSize) %
    3410           3 :                      nRasterYSize));
    3411             :             // Zero-out unused area
    3412           3 :             memset(m_pabyBlockBuf + nValidBytes, 0,
    3413           3 :                    nBlockBufSize - nValidBytes);
    3414             :         }
    3415             : 
    3416       50131 :         m_nLoadedBlock = nBlockId;
    3417             :     }
    3418             :     else
    3419             :     {
    3420          26 :         m_nLoadedBlock = -1;
    3421             :     }
    3422       50157 :     m_bLoadedBlockDirty = false;
    3423             : 
    3424       50157 :     return eErr;
    3425             : }
    3426             : 
    3427             : /************************************************************************/
    3428             : /*                              Identify()                              */
    3429             : /************************************************************************/
    3430             : 
    3431      122823 : int GTiffDataset::Identify(GDALOpenInfo *poOpenInfo)
    3432             : 
    3433             : {
    3434      122823 :     const char *pszFilename = poOpenInfo->pszFilename;
    3435      122823 :     if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
    3436             :     {
    3437          20 :         pszFilename += strlen("GTIFF_RAW:");
    3438          40 :         GDALOpenInfo oOpenInfo(pszFilename, poOpenInfo->eAccess);
    3439          20 :         return Identify(&oOpenInfo);
    3440             :     }
    3441             : 
    3442             :     /* -------------------------------------------------------------------- */
    3443             :     /*      We have a special hook for handling opening a specific          */
    3444             :     /*      directory of a TIFF file.                                       */
    3445             :     /* -------------------------------------------------------------------- */
    3446      122803 :     if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
    3447          60 :         return TRUE;
    3448             : 
    3449             :     /* -------------------------------------------------------------------- */
    3450             :     /*      First we check to see if the file has the expected header       */
    3451             :     /*      bytes.                                                          */
    3452             :     /* -------------------------------------------------------------------- */
    3453      122743 :     if (poOpenInfo->fpL == nullptr || poOpenInfo->nHeaderBytes < 2)
    3454       62943 :         return FALSE;
    3455             : 
    3456       59800 :     if ((poOpenInfo->pabyHeader[0] != 'I' ||
    3457       48367 :          poOpenInfo->pabyHeader[1] != 'I') &&
    3458       11453 :         (poOpenInfo->pabyHeader[0] != 'M' || poOpenInfo->pabyHeader[1] != 'M'))
    3459       11185 :         return FALSE;
    3460             : 
    3461       48615 :     if ((poOpenInfo->pabyHeader[2] != 0x2A || poOpenInfo->pabyHeader[3] != 0) &&
    3462         555 :         (poOpenInfo->pabyHeader[3] != 0x2A || poOpenInfo->pabyHeader[2] != 0) &&
    3463         309 :         (poOpenInfo->pabyHeader[2] != 0x2B || poOpenInfo->pabyHeader[3] != 0) &&
    3464          22 :         (poOpenInfo->pabyHeader[3] != 0x2B || poOpenInfo->pabyHeader[2] != 0))
    3465           0 :         return FALSE;
    3466             : 
    3467       48615 :     return TRUE;
    3468             : }
    3469             : 
    3470             : /************************************************************************/
    3471             : /*                       GTIFFExtendMemoryFile()                        */
    3472             : /************************************************************************/
    3473             : 
    3474          14 : static bool GTIFFExtendMemoryFile(const CPLString &osTmpFilename,
    3475             :                                   VSILFILE *fpTemp, VSILFILE *fpL,
    3476             :                                   int nNewLength, GByte *&pabyBuffer,
    3477             :                                   vsi_l_offset &nDataLength)
    3478             : {
    3479          14 :     if (nNewLength <= static_cast<int>(nDataLength))
    3480          10 :         return true;
    3481           4 :     if (VSIFSeekL(fpTemp, nNewLength - 1, SEEK_SET) != 0)
    3482           0 :         return false;
    3483           4 :     char ch = 0;
    3484           4 :     if (VSIFWriteL(&ch, 1, 1, fpTemp) != 1)
    3485           0 :         return false;
    3486           4 :     const int nOldDataLength = static_cast<int>(nDataLength);
    3487           4 :     pabyBuffer = static_cast<GByte *>(
    3488           4 :         VSIGetMemFileBuffer(osTmpFilename, &nDataLength, FALSE));
    3489           4 :     const int nToRead = nNewLength - nOldDataLength;
    3490             :     const int nRead = static_cast<int>(
    3491           4 :         VSIFReadL(pabyBuffer + nOldDataLength, 1, nToRead, fpL));
    3492           4 :     if (nRead != nToRead)
    3493             :     {
    3494           0 :         CPLError(CE_Failure, CPLE_FileIO,
    3495             :                  "Needed to read %d bytes. Only %d got", nToRead, nRead);
    3496           0 :         return false;
    3497             :     }
    3498           4 :     return true;
    3499             : }
    3500             : 
    3501             : /************************************************************************/
    3502             : /*                      GTIFFMakeBufferedStream()                       */
    3503             : /************************************************************************/
    3504             : 
    3505           9 : static bool GTIFFMakeBufferedStream(GDALOpenInfo *poOpenInfo)
    3506             : {
    3507             :     const CPLString osTmpFilename(
    3508          18 :         VSIMemGenerateHiddenFilename("GTIFFMakeBufferedStream.tif"));
    3509           9 :     VSILFILE *fpTemp = VSIFOpenL(osTmpFilename, "wb+");
    3510           9 :     if (fpTemp == nullptr)
    3511           0 :         return false;
    3512             :     // The seek is needed for /vsistdin/ that has some rewind capabilities.
    3513          18 :     if (VSIFSeekL(poOpenInfo->fpL,
    3514           9 :                   static_cast<vsi_l_offset>(poOpenInfo->nHeaderBytes),
    3515           9 :                   SEEK_SET) != 0)
    3516             :     {
    3517           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3518           0 :         return false;
    3519             :     }
    3520           9 :     CPLAssert(static_cast<int>(VSIFTellL(poOpenInfo->fpL)) ==
    3521             :               poOpenInfo->nHeaderBytes);
    3522           9 :     if (VSIFWriteL(poOpenInfo->pabyHeader, poOpenInfo->nHeaderBytes, 1,
    3523           9 :                    fpTemp) != 1)
    3524             :     {
    3525           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3526           0 :         return false;
    3527             :     }
    3528           9 :     vsi_l_offset nDataLength = 0;
    3529             :     GByte *pabyBuffer = static_cast<GByte *>(
    3530           9 :         VSIGetMemFileBuffer(osTmpFilename, &nDataLength, FALSE));
    3531           9 :     const bool bLittleEndian = (pabyBuffer[0] == 'I');
    3532           9 :     const bool bSwap = CPL_IS_LSB ^ bLittleEndian;
    3533           9 :     const bool bBigTIFF = pabyBuffer[2] == 43 || pabyBuffer[3] == 43;
    3534           9 :     vsi_l_offset nMaxOffset = 0;
    3535           9 :     if (bBigTIFF)
    3536             :     {
    3537           2 :         GUInt64 nTmp = 0;
    3538           2 :         memcpy(&nTmp, pabyBuffer + 8, 8);
    3539           2 :         if (bSwap)
    3540           0 :             CPL_SWAP64PTR(&nTmp);
    3541           2 :         if (nTmp != 16)
    3542             :         {
    3543           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    3544             :                      "IFD start should be at offset 16 for a streamed BigTIFF");
    3545           1 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3546           1 :             VSIUnlink(osTmpFilename);
    3547           1 :             return false;
    3548             :         }
    3549           1 :         memcpy(&nTmp, pabyBuffer + 16, 8);
    3550           1 :         if (bSwap)
    3551           0 :             CPL_SWAP64PTR(&nTmp);
    3552           1 :         if (nTmp > 1024)
    3553             :         {
    3554           0 :             CPLError(CE_Failure, CPLE_NotSupported,
    3555             :                      "Too many tags : " CPL_FRMT_GIB, nTmp);
    3556           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3557           0 :             VSIUnlink(osTmpFilename);
    3558           0 :             return false;
    3559             :         }
    3560           1 :         const int nTags = static_cast<int>(nTmp);
    3561           1 :         const int nSpaceForTags = nTags * 20;
    3562           1 :         if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
    3563             :                                    24 + nSpaceForTags, pabyBuffer, nDataLength))
    3564             :         {
    3565           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3566           0 :             VSIUnlink(osTmpFilename);
    3567           0 :             return false;
    3568             :         }
    3569           1 :         nMaxOffset = 24 + nSpaceForTags + 8;
    3570          18 :         for (int i = 0; i < nTags; ++i)
    3571             :         {
    3572          17 :             GUInt16 nTmp16 = 0;
    3573          17 :             memcpy(&nTmp16, pabyBuffer + 24 + i * 20, 2);
    3574          17 :             if (bSwap)
    3575           0 :                 CPL_SWAP16PTR(&nTmp16);
    3576          17 :             const int nTag = nTmp16;
    3577          17 :             memcpy(&nTmp16, pabyBuffer + 24 + i * 20 + 2, 2);
    3578          17 :             if (bSwap)
    3579           0 :                 CPL_SWAP16PTR(&nTmp16);
    3580          17 :             const int nDataType = nTmp16;
    3581          17 :             memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 4, 8);
    3582          17 :             if (bSwap)
    3583           0 :                 CPL_SWAP64PTR(&nTmp);
    3584          17 :             if (nTmp >= 16 * 1024 * 1024)
    3585             :             {
    3586           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3587             :                          "Too many elements for tag %d : " CPL_FRMT_GUIB, nTag,
    3588             :                          nTmp);
    3589           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3590           0 :                 VSIUnlink(osTmpFilename);
    3591           0 :                 return false;
    3592             :             }
    3593          17 :             const GUInt32 nCount = static_cast<GUInt32>(nTmp);
    3594             :             const GUInt32 nTagSize =
    3595          17 :                 TIFFDataWidth(static_cast<TIFFDataType>(nDataType)) * nCount;
    3596          17 :             if (nTagSize > 8)
    3597             :             {
    3598           7 :                 memcpy(&nTmp, pabyBuffer + 24 + i * 20 + 12, 8);
    3599           7 :                 if (bSwap)
    3600           0 :                     CPL_SWAP64PTR(&nTmp);
    3601           7 :                 if (nTmp > GUINT64_MAX - nTagSize)
    3602             :                 {
    3603           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    3604             :                              "Overflow with tag %d", nTag);
    3605           0 :                     CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3606           0 :                     VSIUnlink(osTmpFilename);
    3607           0 :                     return false;
    3608             :                 }
    3609           7 :                 if (static_cast<vsi_l_offset>(nTmp + nTagSize) > nMaxOffset)
    3610           6 :                     nMaxOffset = nTmp + nTagSize;
    3611             :             }
    3612             :         }
    3613             :     }
    3614             :     else
    3615             :     {
    3616           7 :         GUInt32 nTmp = 0;
    3617           7 :         memcpy(&nTmp, pabyBuffer + 4, 4);
    3618           7 :         if (bSwap)
    3619           0 :             CPL_SWAP32PTR(&nTmp);
    3620           7 :         if (nTmp != 8)
    3621             :         {
    3622           1 :             CPLError(CE_Failure, CPLE_NotSupported,
    3623             :                      "IFD start should be at offset 8 for a streamed TIFF");
    3624           1 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3625           1 :             VSIUnlink(osTmpFilename);
    3626           1 :             return false;
    3627             :         }
    3628           6 :         GUInt16 nTmp16 = 0;
    3629           6 :         memcpy(&nTmp16, pabyBuffer + 8, 2);
    3630           6 :         if (bSwap)
    3631           0 :             CPL_SWAP16PTR(&nTmp16);
    3632           6 :         if (nTmp16 > 1024)
    3633             :         {
    3634           0 :             CPLError(CE_Failure, CPLE_NotSupported, "Too many tags : %d",
    3635             :                      nTmp16);
    3636           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3637           0 :             VSIUnlink(osTmpFilename);
    3638           0 :             return false;
    3639             :         }
    3640           6 :         const int nTags = nTmp16;
    3641           6 :         const int nSpaceForTags = nTags * 12;
    3642           6 :         if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
    3643             :                                    10 + nSpaceForTags, pabyBuffer, nDataLength))
    3644             :         {
    3645           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3646           0 :             VSIUnlink(osTmpFilename);
    3647           0 :             return false;
    3648             :         }
    3649           6 :         nMaxOffset = 10 + nSpaceForTags + 4;
    3650          95 :         for (int i = 0; i < nTags; ++i)
    3651             :         {
    3652          89 :             memcpy(&nTmp16, pabyBuffer + 10 + i * 12, 2);
    3653          89 :             if (bSwap)
    3654           0 :                 CPL_SWAP16PTR(&nTmp16);
    3655          89 :             const int nTag = nTmp16;
    3656          89 :             memcpy(&nTmp16, pabyBuffer + 10 + i * 12 + 2, 2);
    3657          89 :             if (bSwap)
    3658           0 :                 CPL_SWAP16PTR(&nTmp16);
    3659          89 :             const int nDataType = nTmp16;
    3660          89 :             memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 4, 4);
    3661          89 :             if (bSwap)
    3662           0 :                 CPL_SWAP32PTR(&nTmp);
    3663          89 :             if (nTmp >= 16 * 1024 * 1024)
    3664             :             {
    3665           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
    3666             :                          "Too many elements for tag %d : %u", nTag, nTmp);
    3667           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3668           0 :                 VSIUnlink(osTmpFilename);
    3669           0 :                 return false;
    3670             :             }
    3671          89 :             const GUInt32 nCount = nTmp;
    3672             :             const GUInt32 nTagSize =
    3673          89 :                 TIFFDataWidth(static_cast<TIFFDataType>(nDataType)) * nCount;
    3674          89 :             if (nTagSize > 4)
    3675             :             {
    3676          37 :                 memcpy(&nTmp, pabyBuffer + 10 + i * 12 + 8, 4);
    3677          37 :                 if (bSwap)
    3678           0 :                     CPL_SWAP32PTR(&nTmp);
    3679          37 :                 if (nTmp > static_cast<GUInt32>(UINT_MAX - nTagSize))
    3680             :                 {
    3681           0 :                     CPLError(CE_Failure, CPLE_NotSupported,
    3682             :                              "Overflow with tag %d", nTag);
    3683           0 :                     CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3684           0 :                     VSIUnlink(osTmpFilename);
    3685           0 :                     return false;
    3686             :                 }
    3687          37 :                 if (nTmp + nTagSize > nMaxOffset)
    3688          32 :                     nMaxOffset = nTmp + nTagSize;
    3689             :             }
    3690             :         }
    3691             :     }
    3692           7 :     if (nMaxOffset > 10 * 1024 * 1024)
    3693             :     {
    3694           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3695           0 :         VSIUnlink(osTmpFilename);
    3696           0 :         return false;
    3697             :     }
    3698           7 :     if (!GTIFFExtendMemoryFile(osTmpFilename, fpTemp, poOpenInfo->fpL,
    3699             :                                static_cast<int>(nMaxOffset), pabyBuffer,
    3700             :                                nDataLength))
    3701             :     {
    3702           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fpTemp));
    3703           0 :         VSIUnlink(osTmpFilename);
    3704           0 :         return false;
    3705             :     }
    3706           7 :     CPLAssert(nDataLength == VSIFTellL(poOpenInfo->fpL));
    3707           7 :     poOpenInfo->fpL = VSICreateBufferedReaderHandle(
    3708             :         poOpenInfo->fpL, pabyBuffer, static_cast<vsi_l_offset>(INT_MAX) << 32);
    3709           7 :     if (VSIFCloseL(fpTemp) != 0)
    3710           0 :         return false;
    3711           7 :     VSIUnlink(osTmpFilename);
    3712             : 
    3713           7 :     return true;
    3714             : }
    3715             : 
    3716             : /************************************************************************/
    3717             : /*                       AssociateExternalMask()                        */
    3718             : /************************************************************************/
    3719             : 
    3720             : // Used by GTIFFBuildOverviewsEx() for the COG driver
    3721           5 : bool GTiffDataset::AssociateExternalMask()
    3722             : {
    3723           5 :     if (m_poMaskExtOvrDS->GetRasterBand(1)->GetOverviewCount() !=
    3724           5 :         GetRasterBand(1)->GetOverviewCount())
    3725           0 :         return false;
    3726           5 :     if (m_apoOverviewDS.empty())
    3727           0 :         return false;
    3728           5 :     if (m_poMaskDS)
    3729           0 :         return false;
    3730          10 :     if (m_poMaskExtOvrDS->GetRasterXSize() != nRasterXSize ||
    3731           5 :         m_poMaskExtOvrDS->GetRasterYSize() != nRasterYSize)
    3732           0 :         return false;
    3733           5 :     m_poExternalMaskDS = m_poMaskExtOvrDS.get();
    3734           5 :     int i = 0;
    3735          13 :     for (auto &poOvrDS : m_apoOverviewDS)
    3736             :     {
    3737           8 :         if (poOvrDS->m_poMaskDS)
    3738           0 :             return false;
    3739          16 :         poOvrDS->m_poExternalMaskDS =
    3740           8 :             m_poMaskExtOvrDS->GetRasterBand(1)->GetOverview(i)->GetDataset();
    3741           8 :         if (!poOvrDS->m_poExternalMaskDS)
    3742           0 :             return false;
    3743           8 :         auto poOvrBand = poOvrDS->GetRasterBand(1);
    3744           8 :         if (poOvrDS->m_poExternalMaskDS->GetRasterXSize() !=
    3745          16 :                 poOvrBand->GetXSize() ||
    3746           8 :             poOvrDS->m_poExternalMaskDS->GetRasterYSize() !=
    3747           8 :                 poOvrBand->GetYSize())
    3748           0 :             return false;
    3749           8 :         ++i;
    3750             :     }
    3751           5 :     return true;
    3752             : }
    3753             : 
    3754             : /************************************************************************/
    3755             : /*                                Open()                                */
    3756             : /************************************************************************/
    3757             : 
    3758       24053 : GDALDataset *GTiffDataset::Open(GDALOpenInfo *poOpenInfo)
    3759             : 
    3760             : {
    3761       24053 :     const char *pszFilename = poOpenInfo->pszFilename;
    3762             : 
    3763             :     /* -------------------------------------------------------------------- */
    3764             :     /*      Check if it looks like a TIFF file.                             */
    3765             :     /* -------------------------------------------------------------------- */
    3766       24053 :     if (!Identify(poOpenInfo))
    3767           0 :         return nullptr;
    3768             : 
    3769       24053 :     bool bAllowRGBAInterface = true;
    3770       24053 :     if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
    3771             :     {
    3772          10 :         bAllowRGBAInterface = false;
    3773          10 :         pszFilename += strlen("GTIFF_RAW:");
    3774             :     }
    3775             : 
    3776             :     /* -------------------------------------------------------------------- */
    3777             :     /*      We have a special hook for handling opening a specific          */
    3778             :     /*      directory of a TIFF file.                                       */
    3779             :     /* -------------------------------------------------------------------- */
    3780       24053 :     if (STARTS_WITH_CI(pszFilename, "GTIFF_DIR:"))
    3781          30 :         return OpenDir(poOpenInfo);
    3782             : 
    3783       24023 :     GTiffOneTimeInit();
    3784             : 
    3785             :     /* -------------------------------------------------------------------- */
    3786             :     /*      Try opening the dataset.                                        */
    3787             :     /* -------------------------------------------------------------------- */
    3788       24023 :     bool bStreaming = false;
    3789             :     const char *pszReadStreaming =
    3790       24023 :         CPLGetConfigOption("TIFF_READ_STREAMING", nullptr);
    3791       24023 :     if (poOpenInfo->fpL == nullptr)
    3792             :     {
    3793           9 :         poOpenInfo->fpL = VSIFOpenL(
    3794           9 :             pszFilename, poOpenInfo->eAccess == GA_ReadOnly ? "rb" : "r+b");
    3795           9 :         if (poOpenInfo->fpL == nullptr)
    3796           0 :             return nullptr;
    3797             :     }
    3798           7 :     else if (!(pszReadStreaming && !CPLTestBool(pszReadStreaming)) &&
    3799       48034 :              poOpenInfo->nHeaderBytes >= 24 &&
    3800             :              // A pipe has no seeking capability, so its position is 0 despite
    3801             :              // having read bytes.
    3802       24013 :              (static_cast<int>(VSIFTellL(poOpenInfo->fpL)) ==
    3803       24013 :                   poOpenInfo->nHeaderBytes ||
    3804       24013 :               strcmp(pszFilename, "/vsistdin/") == 0 ||
    3805             :               // STARTS_WITH(pszFilename, "/vsicurl_streaming/") ||
    3806           7 :               (pszReadStreaming && CPLTestBool(pszReadStreaming))))
    3807             :     {
    3808           9 :         bStreaming = true;
    3809           9 :         if (!GTIFFMakeBufferedStream(poOpenInfo))
    3810           2 :             return nullptr;
    3811             :     }
    3812             : 
    3813             :     // Store errors/warnings and emit them later.
    3814             :     TIFF *l_hTIFF;
    3815       48042 :     CPLErrorAccumulator oErrorAccumulator;
    3816             :     {
    3817       24021 :         auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
    3818       24021 :         CPL_IGNORE_RET_VAL(oAccumulator);
    3819       24021 :         const bool bDeferStrileLoading = CPLTestBool(
    3820             :             CPLGetConfigOption("GTIFF_USE_DEFER_STRILE_LOADING", "YES"));
    3821       24021 :         l_hTIFF = VSI_TIFFOpen(
    3822             :             pszFilename,
    3823       24021 :             poOpenInfo->eAccess == GA_ReadOnly
    3824       23212 :                 ? ((bStreaming || !bDeferStrileLoading) ? "rC" : "rDOC")
    3825         809 :                 : (!bDeferStrileLoading ? "r+C" : "r+DC"),
    3826             :             poOpenInfo->fpL);
    3827             :     };
    3828             : 
    3829             :     // Now emit errors and change their criticality if needed
    3830             :     // We only emit failures if we didn't manage to open the file.
    3831             :     // Otherwise it makes Python bindings unhappy (#5616).
    3832       24116 :     for (const auto &oError : oErrorAccumulator.GetErrors())
    3833             :     {
    3834         190 :         ReportError(pszFilename,
    3835           1 :                     (l_hTIFF == nullptr && oError.type == CE_Failure)
    3836             :                         ? CE_Failure
    3837             :                         : CE_Warning,
    3838          95 :                     oError.no, "%s", oError.msg.c_str());
    3839             :     }
    3840             : 
    3841       24021 :     if (l_hTIFF == nullptr)
    3842           2 :         return nullptr;
    3843             : 
    3844       24019 :     uint32_t nXSize = 0;
    3845       24019 :     TIFFGetField(l_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
    3846       24019 :     uint32_t nYSize = 0;
    3847       24019 :     TIFFGetField(l_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
    3848             : 
    3849       24019 :     if (nXSize > INT_MAX || nYSize > INT_MAX)
    3850             :     {
    3851             :         // GDAL only supports signed 32bit dimensions.
    3852           1 :         ReportError(pszFilename, CE_Failure, CPLE_NotSupported,
    3853             :                     "Too large image size: %u x %u", nXSize, nYSize);
    3854           1 :         XTIFFClose(l_hTIFF);
    3855           1 :         return nullptr;
    3856             :     }
    3857             : 
    3858       24018 :     uint16_t l_nCompression = 0;
    3859       24018 :     if (!TIFFGetField(l_hTIFF, TIFFTAG_COMPRESSION, &(l_nCompression)))
    3860           0 :         l_nCompression = COMPRESSION_NONE;
    3861             : 
    3862             :     /* -------------------------------------------------------------------- */
    3863             :     /*      Create a corresponding GDALDataset.                             */
    3864             :     /* -------------------------------------------------------------------- */
    3865       48036 :     auto poDS = std::make_unique<GTiffDataset>();
    3866       24018 :     poDS->SetDescription(pszFilename);
    3867       24018 :     poDS->m_osFilename = pszFilename;
    3868       24018 :     poDS->m_fpL = poOpenInfo->fpL;
    3869       24018 :     poOpenInfo->fpL = nullptr;
    3870       24018 :     poDS->m_bStreamingIn = bStreaming;
    3871       24018 :     poDS->m_nCompression = l_nCompression;
    3872             : 
    3873             :     // Check structural metadata (for COG)
    3874       24018 :     const int nOffsetOfStructuralMetadata =
    3875       24009 :         poOpenInfo->nHeaderBytes && ((poOpenInfo->pabyHeader[2] == 0x2B ||
    3876       23869 :                                       poOpenInfo->pabyHeader[3] == 0x2B))
    3877       48027 :             ? 16
    3878             :             : 8;
    3879       24018 :     if (poOpenInfo->nHeaderBytes >
    3880       24018 :             nOffsetOfStructuralMetadata +
    3881       24009 :                 static_cast<int>(strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) &&
    3882       24009 :         memcmp(poOpenInfo->pabyHeader + nOffsetOfStructuralMetadata,
    3883             :                "GDAL_STRUCTURAL_METADATA_SIZE=",
    3884             :                strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) == 0)
    3885             :     {
    3886         271 :         const char *pszStructuralMD = reinterpret_cast<const char *>(
    3887         271 :             poOpenInfo->pabyHeader + nOffsetOfStructuralMetadata);
    3888         542 :         poDS->m_bLayoutIFDSBeforeData =
    3889         271 :             strstr(pszStructuralMD, "LAYOUT=IFDS_BEFORE_DATA") != nullptr;
    3890         542 :         poDS->m_bBlockOrderRowMajor =
    3891         271 :             strstr(pszStructuralMD, "BLOCK_ORDER=ROW_MAJOR") != nullptr;
    3892         271 :         poDS->m_bLeaderSizeAsUInt4 =
    3893         542 :             strstr(pszStructuralMD, "BLOCK_LEADER=SIZE_AS_UINT4") != nullptr &&
    3894         271 :             (strstr(pszStructuralMD, "INTERLEAVE=") == nullptr ||
    3895          23 :              strstr(pszStructuralMD, "INTERLEAVE=BAND") != nullptr ||
    3896           0 :              strstr(pszStructuralMD, "INTERLEAVE=TILE") != nullptr);
    3897         271 :         poDS->m_bTrailerRepeatedLast4BytesRepeated =
    3898         271 :             strstr(pszStructuralMD, "BLOCK_TRAILER=LAST_4_BYTES_REPEATED") !=
    3899         542 :                 nullptr &&
    3900         271 :             (strstr(pszStructuralMD, "INTERLEAVE=") == nullptr ||
    3901          23 :              strstr(pszStructuralMD, "INTERLEAVE=BAND") != nullptr ||
    3902           0 :              strstr(pszStructuralMD, "INTERLEAVE=TILE") != nullptr);
    3903         271 :         poDS->m_bMaskInterleavedWithImagery =
    3904         271 :             strstr(pszStructuralMD, "MASK_INTERLEAVED_WITH_IMAGERY=YES") !=
    3905         312 :                 nullptr &&
    3906          41 :             strstr(pszStructuralMD, "INTERLEAVE=") == nullptr;
    3907         542 :         poDS->m_bKnownIncompatibleEdition =
    3908         271 :             strstr(pszStructuralMD, "KNOWN_INCOMPATIBLE_EDITION=YES") !=
    3909             :             nullptr;
    3910         271 :         if (poDS->m_bKnownIncompatibleEdition)
    3911             :         {
    3912           7 :             poDS->ReportError(
    3913             :                 CE_Warning, CPLE_AppDefined,
    3914             :                 "This file used to have optimizations in its layout, "
    3915             :                 "but those have been, at least partly, invalidated by "
    3916             :                 "later changes");
    3917             :         }
    3918         528 :         else if (poDS->m_bLayoutIFDSBeforeData && poDS->m_bBlockOrderRowMajor &&
    3919         792 :                  poDS->m_bLeaderSizeAsUInt4 &&
    3920         264 :                  poDS->m_bTrailerRepeatedLast4BytesRepeated)
    3921             :         {
    3922         279 :             if (poOpenInfo->eAccess == GA_Update &&
    3923          15 :                 !CPLTestBool(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
    3924             :                                                   "IGNORE_COG_LAYOUT_BREAK",
    3925             :                                                   "FALSE")))
    3926             :             {
    3927           6 :                 CPLError(CE_Failure, CPLE_AppDefined,
    3928             :                          "File %s has C(loud) O(ptimized) G(eoTIFF) layout. "
    3929             :                          "Updating it will generally result in losing part of "
    3930             :                          "the optimizations (but will still produce a valid "
    3931             :                          "GeoTIFF file). If this is acceptable, open the file "
    3932             :                          "with the IGNORE_COG_LAYOUT_BREAK open option set "
    3933             :                          "to YES.",
    3934             :                          pszFilename);
    3935           6 :                 XTIFFClose(l_hTIFF);
    3936           6 :                 return nullptr;
    3937             :             }
    3938         258 :             poDS->m_oGTiffMDMD.SetMetadataItem("LAYOUT", "COG",
    3939             :                                                "IMAGE_STRUCTURE");
    3940             :         }
    3941             :     }
    3942             : 
    3943             :     // In the case of GDAL_DISABLE_READDIR_ON_OPEN = NO / EMPTY_DIR
    3944       24012 :     if (poOpenInfo->AreSiblingFilesLoaded())
    3945             :     {
    3946         342 :         poDS->oOvManager.TransferSiblingFiles(
    3947         171 :             CSLDuplicate(poOpenInfo->GetSiblingFiles()));
    3948         171 :         poDS->m_bHasGotSiblingFiles = true;
    3949             :     }
    3950             : 
    3951             :     // Should be capped by 257, to avoid 65535 / m_nColorTableMultiplier to overflow 255
    3952       24012 :     poDS->m_nColorTableMultiplier = std::max(
    3953       72036 :         0, std::min(257,
    3954       24012 :                     atoi(CSLFetchNameValueDef(poOpenInfo->papszOpenOptions,
    3955       24012 :                                               "COLOR_TABLE_MULTIPLIER", "0"))));
    3956             : 
    3957       24012 :     if (poDS->OpenOffset(l_hTIFF, TIFFCurrentDirOffset(l_hTIFF),
    3958             :                          poOpenInfo->eAccess, bAllowRGBAInterface,
    3959       24012 :                          true) != CE_None)
    3960             :     {
    3961           9 :         return nullptr;
    3962             :     }
    3963             : 
    3964             :     // Do we want blocks that are set to zero and that haven't yet being
    3965             :     // allocated as tile/strip to remain implicit?
    3966       24003 :     if (CPLFetchBool(poOpenInfo->papszOpenOptions, "SPARSE_OK", false))
    3967          46 :         poDS->m_bWriteEmptyTiles = false;
    3968             : 
    3969       24003 :     poDS->InitCreationOrOpenOptions(poOpenInfo->eAccess == GA_Update,
    3970       24003 :                                     poOpenInfo->papszOpenOptions);
    3971             : 
    3972       24003 :     poDS->m_bLoadPam = true;
    3973       24003 :     poDS->m_bColorProfileMetadataChanged = false;
    3974       24003 :     poDS->m_bMetadataChanged = false;
    3975       24003 :     poDS->m_bGeoTIFFInfoChanged = false;
    3976       24003 :     poDS->m_bNoDataChanged = false;
    3977       24003 :     poDS->m_bForceUnsetGTOrGCPs = false;
    3978       24003 :     poDS->m_bForceUnsetProjection = false;
    3979             : 
    3980             :     // Used by GTIFFBuildOverviewsEx() for the COG driver
    3981       48006 :     const char *pszMaskOverviewDS = CSLFetchNameValue(
    3982       24003 :         poOpenInfo->papszOpenOptions, "MASK_OVERVIEW_DATASET");
    3983       24003 :     if (pszMaskOverviewDS)
    3984             :     {
    3985           5 :         poDS->m_poMaskExtOvrDS.reset(GDALDataset::Open(
    3986             :             pszMaskOverviewDS, GDAL_OF_RASTER | GDAL_OF_INTERNAL));
    3987           5 :         if (!poDS->m_poMaskExtOvrDS || !poDS->AssociateExternalMask())
    3988             :         {
    3989           0 :             CPLDebug("GTiff",
    3990             :                      "Association with external mask overview file failed");
    3991             :         }
    3992             :     }
    3993             : 
    3994             :     /* -------------------------------------------------------------------- */
    3995             :     /*      Initialize info for external overviews.                         */
    3996             :     /* -------------------------------------------------------------------- */
    3997       24003 :     poDS->oOvManager.Initialize(poDS.get(), poOpenInfo, pszFilename);
    3998             : 
    3999             :     // For backward compatibility, in case GTIFF_POINT_GEO_IGNORE is defined
    4000             :     // load georeferencing right now so as to not require it to be defined
    4001             :     // at the GetGeoTransform() time.
    4002       24003 :     if (CPLGetConfigOption("GTIFF_POINT_GEO_IGNORE", nullptr) != nullptr)
    4003             :     {
    4004          14 :         poDS->LoadGeoreferencingAndPamIfNeeded();
    4005             :     }
    4006             : 
    4007       24003 :     return poDS.release();
    4008             : }
    4009             : 
    4010             : /************************************************************************/
    4011             : /*                    GTiffDatasetSetAreaOrPointMD()                    */
    4012             : /************************************************************************/
    4013             : 
    4014       14191 : static void GTiffDatasetSetAreaOrPointMD(GTIF *hGTIF,
    4015             :                                          GDALMultiDomainMetadata &m_oGTiffMDMD)
    4016             : {
    4017             :     // Is this a pixel-is-point dataset?
    4018       14191 :     unsigned short nRasterType = 0;
    4019             : 
    4020       14191 :     if (GDALGTIFKeyGetSHORT(hGTIF, GTRasterTypeGeoKey, &nRasterType, 0, 1) == 1)
    4021             :     {
    4022        8826 :         if (nRasterType == static_cast<short>(RasterPixelIsPoint))
    4023         262 :             m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT,
    4024             :                                          GDALMD_AOP_POINT);
    4025             :         else
    4026        8564 :             m_oGTiffMDMD.SetMetadataItem(GDALMD_AREA_OR_POINT, GDALMD_AOP_AREA);
    4027             :     }
    4028       14191 : }
    4029             : 
    4030             : /************************************************************************/
    4031             : /*                         LoadMDAreaOrPoint()                          */
    4032             : /************************************************************************/
    4033             : 
    4034             : // This is a light version of LookForProjection(), which saves the
    4035             : // potential costly cost of GTIFGetOGISDefn(), since we just need to
    4036             : // access to a raw GeoTIFF key, and not build the full projection object.
    4037             : 
    4038       17189 : void GTiffDataset::LoadMDAreaOrPoint()
    4039             : {
    4040       18261 :     if (m_bLookedForProjection || m_bLookedForMDAreaOrPoint ||
    4041        1072 :         m_oGTiffMDMD.GetMetadataItem(GDALMD_AREA_OR_POINT) != nullptr)
    4042       16117 :         return;
    4043             : 
    4044        1072 :     m_bLookedForMDAreaOrPoint = true;
    4045             : 
    4046        1072 :     GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
    4047             : 
    4048        1072 :     if (!hGTIF)
    4049             :     {
    4050           0 :         ReportError(CE_Warning, CPLE_AppDefined,
    4051             :                     "GeoTIFF tags apparently corrupt, they are being ignored.");
    4052             :     }
    4053             :     else
    4054             :     {
    4055        1072 :         GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
    4056             : 
    4057        1072 :         GTIFFree(hGTIF);
    4058             :     }
    4059             : }
    4060             : 
    4061             : /************************************************************************/
    4062             : /*                         LookForProjection()                          */
    4063             : /************************************************************************/
    4064             : 
    4065      332914 : void GTiffDataset::LookForProjection()
    4066             : 
    4067             : {
    4068      332914 :     if (m_bLookedForProjection)
    4069      319788 :         return;
    4070             : 
    4071       13126 :     m_bLookedForProjection = true;
    4072             : 
    4073       13126 :     IdentifyAuthorizedGeoreferencingSources();
    4074             : 
    4075       13126 :     m_oSRS.Clear();
    4076             : 
    4077       26252 :     std::set<signed char> aoSetPriorities;
    4078       13126 :     if (m_nINTERNALGeorefSrcIndex >= 0)
    4079       13119 :         aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
    4080       13126 :     if (m_nXMLGeorefSrcIndex >= 0)
    4081       13089 :         aoSetPriorities.insert(m_nXMLGeorefSrcIndex);
    4082       39334 :     for (const auto nIndex : aoSetPriorities)
    4083             :     {
    4084       26208 :         if (m_nINTERNALGeorefSrcIndex == nIndex)
    4085             :         {
    4086       13119 :             LookForProjectionFromGeoTIFF();
    4087             :         }
    4088       13089 :         else if (m_nXMLGeorefSrcIndex == nIndex)
    4089             :         {
    4090       13089 :             LookForProjectionFromXML();
    4091             :         }
    4092             :     }
    4093             : }
    4094             : 
    4095             : /************************************************************************/
    4096             : /*                    LookForProjectionFromGeoTIFF()                    */
    4097             : /************************************************************************/
    4098             : 
    4099       13119 : void GTiffDataset::LookForProjectionFromGeoTIFF()
    4100             : {
    4101             :     /* -------------------------------------------------------------------- */
    4102             :     /*      Capture the GeoTIFF projection, if available.                   */
    4103             :     /* -------------------------------------------------------------------- */
    4104             : 
    4105       13119 :     GTIF *hGTIF = GTiffDataset::GTIFNew(m_hTIFF);
    4106             : 
    4107       13119 :     if (!hGTIF)
    4108             :     {
    4109           0 :         ReportError(CE_Warning, CPLE_AppDefined,
    4110             :                     "GeoTIFF tags apparently corrupt, they are being ignored.");
    4111             :     }
    4112             :     else
    4113             :     {
    4114       13119 :         GTIFDefn *psGTIFDefn = GTIFAllocDefn();
    4115             : 
    4116       13119 :         bool bHasErrorBefore = CPLGetLastErrorType() != 0;
    4117             :         // Collect (PROJ) error messages and remit them later as warnings
    4118             :         int ret;
    4119       26238 :         CPLErrorAccumulator oErrorAccumulator;
    4120             :         {
    4121       13119 :             auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
    4122       13119 :             ret = GTIFGetDefn(hGTIF, psGTIFDefn);
    4123             :         }
    4124             : 
    4125       13119 :         bool bWarnAboutEllipsoid = true;
    4126             : 
    4127       13119 :         if (ret)
    4128             :         {
    4129       16694 :             auto oAccumulator = oErrorAccumulator.InstallForCurrentScope();
    4130             : 
    4131        8347 :             if (psGTIFDefn->Ellipsoid == 4326 &&
    4132           1 :                 psGTIFDefn->SemiMajor == 6378137 &&
    4133           1 :                 psGTIFDefn->SemiMinor == 6356752.314245)
    4134             :             {
    4135             :                 // Buggy Sentinel1 geotiff files use a wrong 4326 code for the
    4136             :                 // ellipsoid instead of 7030.
    4137           1 :                 psGTIFDefn->Ellipsoid = 7030;
    4138           1 :                 bWarnAboutEllipsoid = false;
    4139             :             }
    4140             : 
    4141        8347 :             OGRSpatialReferenceH hSRS = GTIFGetOGISDefnAsOSR(hGTIF, psGTIFDefn);
    4142             : 
    4143        8347 :             if (hSRS)
    4144             :             {
    4145        8347 :                 CPLFree(m_pszXMLFilename);
    4146        8347 :                 m_pszXMLFilename = nullptr;
    4147             : 
    4148        8347 :                 m_oSRS = *(OGRSpatialReference::FromHandle(hSRS));
    4149        8347 :                 OSRDestroySpatialReference(hSRS);
    4150             :             }
    4151             :         }
    4152             : 
    4153       26238 :         std::set<std::string> oSetErrorMsg;
    4154       13131 :         for (const auto &oError : oErrorAccumulator.GetErrors())
    4155             :         {
    4156          13 :             if (!bWarnAboutEllipsoid &&
    4157           1 :                 oError.msg.find("ellipsoid not found") != std::string::npos)
    4158             :             {
    4159           1 :                 continue;
    4160             :             }
    4161             : 
    4162             :             // Some error messages might be duplicated in GTIFGetDefn()
    4163             :             // and GTIFGetOGISDefnAsOSR(). Emit them just once.
    4164          11 :             if (oSetErrorMsg.find(oError.msg) == oSetErrorMsg.end())
    4165             :             {
    4166           8 :                 oSetErrorMsg.insert(oError.msg);
    4167          16 :                 CPLError(oError.type == CE_Failure ? CE_Warning : oError.type,
    4168           8 :                          oError.no, "%s", oError.msg.c_str());
    4169             :             }
    4170             :         }
    4171             : 
    4172       13119 :         if (!bHasErrorBefore && oSetErrorMsg.empty())
    4173             :         {
    4174       13042 :             CPLErrorReset();
    4175             :         }
    4176             : 
    4177       13119 :         if (ret && m_oSRS.IsCompound())
    4178             :         {
    4179          35 :             const char *pszVertUnit = nullptr;
    4180          35 :             m_oSRS.GetTargetLinearUnits("COMPD_CS|VERT_CS", &pszVertUnit);
    4181          35 :             if (pszVertUnit && !EQUAL(pszVertUnit, "unknown"))
    4182             :             {
    4183          35 :                 CPLFree(m_pszVertUnit);
    4184          35 :                 m_pszVertUnit = CPLStrdup(pszVertUnit);
    4185             :             }
    4186             : 
    4187             :             int versions[3];
    4188          35 :             GTIFDirectoryInfo(hGTIF, versions, nullptr);
    4189             : 
    4190             :             // If GeoTIFF 1.0, strip vertical by default
    4191          35 :             const char *pszDefaultReportCompdCS =
    4192          35 :                 (versions[0] == 1 && versions[1] == 1 && versions[2] == 0)
    4193          70 :                     ? "NO"
    4194             :                     : "YES";
    4195             : 
    4196             :             // Should we simplify away vertical CS stuff?
    4197          35 :             if (!CPLTestBool(CPLGetConfigOption("GTIFF_REPORT_COMPD_CS",
    4198             :                                                 pszDefaultReportCompdCS)))
    4199             :             {
    4200          10 :                 CPLDebug("GTiff", "Got COMPD_CS, but stripping it.");
    4201             : 
    4202          10 :                 m_oSRS.StripVertical();
    4203             :             }
    4204             :         }
    4205             : 
    4206       13119 :         GTIFFreeDefn(psGTIFDefn);
    4207             : 
    4208       13119 :         GTiffDatasetSetAreaOrPointMD(hGTIF, m_oGTiffMDMD);
    4209             : 
    4210       13119 :         GTIFFree(hGTIF);
    4211             :     }
    4212       13119 : }
    4213             : 
    4214             : /************************************************************************/
    4215             : /*            GetSidecarFilenameWithReplacedExtension()    ¨            */
    4216             : /************************************************************************/
    4217             : 
    4218             : std::string
    4219       21725 : GTiffDataset::GetSidecarFilenameWithReplacedExtension(const char *pszExt)
    4220             : {
    4221       21725 :     if (!GDALCanFileAcceptSidecarFile(m_osFilename.c_str()))
    4222           0 :         return std::string();
    4223             : 
    4224       21725 :     CSLConstList papszSiblingFiles = GetSiblingFiles();
    4225             :     const std::string osSidecarFilenameLowerCaseExt = CPLResetExtensionSafe(
    4226       43450 :         m_osFilename.c_str(), CPLString(pszExt).tolower());
    4227             : 
    4228       21725 :     if (papszSiblingFiles && GDALCanReliablyUseSiblingFileList(
    4229             :                                  osSidecarFilenameLowerCaseExt.c_str()))
    4230             :     {
    4231       21364 :         const int iSibling = CSLFindString(
    4232             :             papszSiblingFiles,
    4233             :             CPLGetFilename(osSidecarFilenameLowerCaseExt.c_str()));
    4234       21364 :         if (iSibling >= 0)
    4235             :         {
    4236        2028 :             std::string osRet = m_osFilename.c_str();
    4237        1014 :             osRet.resize(m_osFilename.size() -
    4238        1014 :                          strlen(CPLGetFilename(m_osFilename.c_str())));
    4239        1014 :             osRet += papszSiblingFiles[iSibling];
    4240        1014 :             return osRet;
    4241             :         }
    4242             :         else
    4243             :         {
    4244       20350 :             return std::string();
    4245             :         }
    4246             :     }
    4247             : 
    4248             :     VSIStatBufL sStatBuf;
    4249         361 :     bool bGotSidecar = VSIStatExL(osSidecarFilenameLowerCaseExt.c_str(),
    4250         361 :                                   &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
    4251             : 
    4252         361 :     if (bGotSidecar)
    4253             :     {
    4254           1 :         return osSidecarFilenameLowerCaseExt;
    4255             :     }
    4256         360 :     else if (VSIIsCaseSensitiveFS(osSidecarFilenameLowerCaseExt.c_str()))
    4257             :     {
    4258             :         const std::string osSidecarFilenameUppercaseExt = CPLResetExtensionSafe(
    4259         360 :             m_osFilename.c_str(), CPLString(pszExt).toupper());
    4260         360 :         bGotSidecar = VSIStatExL(osSidecarFilenameUppercaseExt.c_str(),
    4261             :                                  &sStatBuf, VSI_STAT_EXISTS_FLAG) == 0;
    4262         360 :         if (bGotSidecar)
    4263             :         {
    4264           0 :             return osSidecarFilenameUppercaseExt;
    4265             :         }
    4266             :     }
    4267             : 
    4268         360 :     return std::string();
    4269             : }
    4270             : 
    4271             : /************************************************************************/
    4272             : /*                      LookForProjectionFromXML()                      */
    4273             : /************************************************************************/
    4274             : 
    4275       13089 : void GTiffDataset::LookForProjectionFromXML()
    4276             : {
    4277       13089 :     if (m_poBaseDS != nullptr)
    4278       13087 :         return;
    4279             : 
    4280             :     const std::string osXMLFilename =
    4281       13057 :         GetSidecarFilenameWithReplacedExtension("xml");
    4282       13057 :     if (osXMLFilename.empty())
    4283       13053 :         return;
    4284             : 
    4285           4 :     GByte *pabyRet = nullptr;
    4286           4 :     vsi_l_offset nSize = 0;
    4287           4 :     constexpr int nMaxSize = 10 * 1024 * 1024;
    4288           4 :     if (!VSIIngestFile(nullptr, osXMLFilename.c_str(), &pabyRet, &nSize,
    4289             :                        nMaxSize))
    4290           0 :         return;
    4291             :     CPLXMLTreeCloser oXML(
    4292           4 :         CPLParseXMLString(reinterpret_cast<const char *>(pabyRet)));
    4293           4 :     VSIFree(pabyRet);
    4294           4 :     if (!oXML.get())
    4295           0 :         return;
    4296           4 :     const char *pszCode = CPLGetXMLValue(
    4297           4 :         oXML.get(), "=metadata.refSysInfo.RefSystem.refSysID.identCode.code",
    4298             :         "0");
    4299           4 :     const int nCode = atoi(pszCode);
    4300           4 :     if (nCode <= 0)
    4301           2 :         return;
    4302           2 :     if (nCode <= 32767)
    4303           2 :         m_oSRS.importFromEPSG(nCode);
    4304             :     else
    4305           0 :         m_oSRS.SetFromUserInput(CPLSPrintf("ESRI:%d", nCode));
    4306             : 
    4307           2 :     CPLFree(m_pszXMLFilename);
    4308           2 :     m_pszXMLFilename = CPLStrdup(osXMLFilename.c_str());
    4309             : }
    4310             : 
    4311             : /************************************************************************/
    4312             : /*                            ApplyPamInfo()                            */
    4313             : /*                                                                      */
    4314             : /*      PAM Information, if available, overrides the GeoTIFF            */
    4315             : /*      geotransform and projection definition.  Check for them         */
    4316             : /*      now.                                                            */
    4317             : /************************************************************************/
    4318             : 
    4319       14967 : void GTiffDataset::ApplyPamInfo()
    4320             : 
    4321             : {
    4322       14967 :     bool bGotGTFromPAM = false;
    4323             : 
    4324       14967 :     if (m_nPAMGeorefSrcIndex >= 0 &&
    4325       14967 :         ((m_bGeoTransformValid &&
    4326        9529 :           m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
    4327        5448 :          m_nGeoTransformGeorefSrcIndex < 0 || !m_bGeoTransformValid))
    4328             :     {
    4329       14957 :         GDALGeoTransform pamGT;
    4330       14957 :         if (GDALPamDataset::GetGeoTransform(pamGT) == CE_None)
    4331             :         {
    4332          43 :             if (m_nGeoTransformGeorefSrcIndex == m_nWORLDFILEGeorefSrcIndex)
    4333             :             {
    4334          12 :                 CPLFree(m_pszGeorefFilename);
    4335          12 :                 m_pszGeorefFilename = nullptr;
    4336             :             }
    4337          43 :             m_gt = pamGT;
    4338          43 :             m_bGeoTransformValid = true;
    4339          43 :             bGotGTFromPAM = true;
    4340             :         }
    4341             :     }
    4342             : 
    4343       14967 :     if (m_nPAMGeorefSrcIndex >= 0)
    4344             :     {
    4345       14967 :         if ((m_nTABFILEGeorefSrcIndex < 0 ||
    4346       14933 :              m_nPAMGeorefSrcIndex < m_nTABFILEGeorefSrcIndex) &&
    4347       14965 :             (m_nINTERNALGeorefSrcIndex < 0 ||
    4348       14951 :              m_nPAMGeorefSrcIndex < m_nINTERNALGeorefSrcIndex))
    4349             :         {
    4350       14953 :             const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
    4351       14953 :             if (poPamSRS)
    4352             :             {
    4353          45 :                 m_oSRS = *poPamSRS;
    4354          45 :                 m_bLookedForProjection = true;
    4355             :                 // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
    4356       14953 :             }
    4357             :         }
    4358             :         else
    4359             :         {
    4360          14 :             if (m_nINTERNALGeorefSrcIndex >= 0)
    4361          12 :                 LookForProjection();
    4362          14 :             if (m_oSRS.IsEmpty())
    4363             :             {
    4364           8 :                 const auto *poPamSRS = GDALPamDataset::GetSpatialRef();
    4365           8 :                 if (poPamSRS)
    4366             :                 {
    4367           8 :                     m_oSRS = *poPamSRS;
    4368           8 :                     m_bLookedForProjection = true;
    4369             :                     // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
    4370             :                 }
    4371             :             }
    4372             :         }
    4373             :     }
    4374             : 
    4375             :     int nPamGCPCount;
    4376       14967 :     if (m_nPAMGeorefSrcIndex >= 0 && !oMDMD.GetMetadata("xml:ESRI") &&
    4377       29953 :         (nPamGCPCount = GDALPamDataset::GetGCPCount()) > 0 &&
    4378          19 :         ((!m_aoGCPs.empty() &&
    4379          11 :           m_nPAMGeorefSrcIndex < m_nGeoTransformGeorefSrcIndex) ||
    4380          10 :          m_nGeoTransformGeorefSrcIndex < 0 || m_aoGCPs.empty()))
    4381             :     {
    4382          17 :         m_aoGCPs = gdal::GCP::fromC(GDALPamDataset::GetGCPs(), nPamGCPCount);
    4383             : 
    4384             :         // Invalidate Geotransorm got from less priority sources
    4385          19 :         if (!m_aoGCPs.empty() && m_bGeoTransformValid && !bGotGTFromPAM &&
    4386           2 :             m_nPAMGeorefSrcIndex == 0)
    4387             :         {
    4388           2 :             m_bGeoTransformValid = false;
    4389             :         }
    4390             : 
    4391             :         // m_nProjectionGeorefSrcIndex = m_nPAMGeorefSrcIndex;
    4392             : 
    4393          17 :         const auto *poPamGCPSRS = GDALPamDataset::GetGCPSpatialRef();
    4394          17 :         if (poPamGCPSRS)
    4395          15 :             m_oSRS = *poPamGCPSRS;
    4396             :         else
    4397           2 :             m_oSRS.Clear();
    4398             : 
    4399          17 :         m_bLookedForProjection = true;
    4400             :     }
    4401             : 
    4402       14967 :     if (m_nPAMGeorefSrcIndex >= 0)
    4403             :     {
    4404       14967 :         CPLXMLNode *psValueAsXML = nullptr;
    4405       14967 :         CPLXMLNode *psGeodataXform = nullptr;
    4406       14967 :         char **papszXML = oMDMD.GetMetadata("xml:ESRI");
    4407       14967 :         if (CSLCount(papszXML) == 1)
    4408             :         {
    4409           9 :             psValueAsXML = CPLParseXMLString(papszXML[0]);
    4410           9 :             if (psValueAsXML)
    4411           9 :                 psGeodataXform = CPLGetXMLNode(psValueAsXML, "=GeodataXform");
    4412             :         }
    4413             : 
    4414             :         const char *pszTIFFTagResUnit =
    4415       14967 :             GetMetadataItem("TIFFTAG_RESOLUTIONUNIT");
    4416       14967 :         const char *pszTIFFTagXRes = GetMetadataItem("TIFFTAG_XRESOLUTION");
    4417       14967 :         const char *pszTIFFTagYRes = GetMetadataItem("TIFFTAG_YRESOLUTION");
    4418       14967 :         if (psGeodataXform && pszTIFFTagXRes && pszTIFFTagYRes &&
    4419           1 :             pszTIFFTagResUnit && atoi(pszTIFFTagResUnit) == 2)
    4420             :         {
    4421             :             CPLXMLNode *psSourceGCPs =
    4422           1 :                 CPLGetXMLNode(psGeodataXform, "SourceGCPs");
    4423             :             CPLXMLNode *psTargetGCPs =
    4424           1 :                 CPLGetXMLNode(psGeodataXform, "TargetGCPs");
    4425           1 :             if (psSourceGCPs && psTargetGCPs)
    4426             :             {
    4427           2 :                 std::vector<double> adfSourceGCPs, adfTargetGCPs;
    4428           1 :                 for (CPLXMLNode *psIter = psSourceGCPs->psChild;
    4429          34 :                      psIter != nullptr; psIter = psIter->psNext)
    4430             :                 {
    4431          33 :                     if (psIter->eType == CXT_Element &&
    4432          32 :                         EQUAL(psIter->pszValue, "Double"))
    4433             :                     {
    4434          32 :                         adfSourceGCPs.push_back(
    4435          32 :                             CPLAtof(CPLGetXMLValue(psIter, nullptr, "")));
    4436             :                     }
    4437             :                 }
    4438           1 :                 for (CPLXMLNode *psIter = psTargetGCPs->psChild;
    4439          34 :                      psIter != nullptr; psIter = psIter->psNext)
    4440             :                 {
    4441          33 :                     if (psIter->eType == CXT_Element &&
    4442          32 :                         EQUAL(psIter->pszValue, "Double"))
    4443             :                     {
    4444          32 :                         adfTargetGCPs.push_back(
    4445          32 :                             CPLAtof(CPLGetXMLValue(psIter, nullptr, "")));
    4446             :                     }
    4447             :                 }
    4448           2 :                 if (adfSourceGCPs.size() == adfTargetGCPs.size() &&
    4449           1 :                     (adfSourceGCPs.size() % 2) == 0)
    4450             :                 {
    4451           1 :                     const char *pszESRI_WKT = CPLGetXMLValue(
    4452             :                         psGeodataXform, "SpatialReference.WKT", nullptr);
    4453           1 :                     if (pszESRI_WKT)
    4454             :                     {
    4455           1 :                         m_bLookedForProjection = true;
    4456           1 :                         m_oSRS.SetAxisMappingStrategy(
    4457             :                             OAMS_TRADITIONAL_GIS_ORDER);
    4458           1 :                         if (m_oSRS.importFromWkt(pszESRI_WKT) != OGRERR_NONE)
    4459             :                         {
    4460           0 :                             m_oSRS.Clear();
    4461             :                         }
    4462             :                     }
    4463             : 
    4464           1 :                     m_aoGCPs.clear();
    4465           1 :                     const size_t nNewGCPCount = adfSourceGCPs.size() / 2;
    4466          17 :                     for (size_t i = 0; i < nNewGCPCount; ++i)
    4467             :                     {
    4468             :                         m_aoGCPs.emplace_back(
    4469             :                             "", "",
    4470             :                             // The origin used is the bottom left corner,
    4471             :                             // and raw values to be multiplied by the
    4472             :                             // TIFFTAG_XRESOLUTION/TIFFTAG_YRESOLUTION
    4473             :                             /* pixel  = */
    4474          16 :                             adfSourceGCPs[2 * i] * CPLAtof(pszTIFFTagXRes),
    4475             :                             /* line = */
    4476          32 :                             nRasterYSize - adfSourceGCPs[2 * i + 1] *
    4477          16 :                                                CPLAtof(pszTIFFTagYRes),
    4478          16 :                             /* X = */ adfTargetGCPs[2 * i],
    4479          32 :                             /* Y = */ adfTargetGCPs[2 * i + 1]);
    4480             :                     }
    4481             : 
    4482             :                     // Invalidate Geotransform got from less priority sources
    4483           2 :                     if (!m_aoGCPs.empty() && m_bGeoTransformValid &&
    4484           2 :                         !bGotGTFromPAM && m_nPAMGeorefSrcIndex == 0)
    4485             :                     {
    4486           0 :                         m_bGeoTransformValid = false;
    4487             :                     }
    4488             :                 }
    4489             :             }
    4490             :         }
    4491             : 
    4492       14967 :         if (psValueAsXML)
    4493           9 :             CPLDestroyXMLNode(psValueAsXML);
    4494             :     }
    4495             : 
    4496             :     /* -------------------------------------------------------------------- */
    4497             :     /*      Copy any PAM metadata into our GeoTIFF context, and with        */
    4498             :     /*      the PAM info overriding the GeoTIFF context.                    */
    4499             :     /* -------------------------------------------------------------------- */
    4500       14967 :     CSLConstList papszPamDomains = oMDMD.GetDomainList();
    4501             : 
    4502       14995 :     for (int iDomain = 0;
    4503       14995 :          papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
    4504             :     {
    4505          28 :         const char *pszDomain = papszPamDomains[iDomain];
    4506             :         // We skip IMAGE_STRUCTURE as PAM content is not supposed to modify
    4507             :         // it and it could cause consistency issues if doing GetMetadata("IMAGE_STRUCTURE")
    4508             :         // which doesn't load PAM, then GetMetadata(other_domain) and
    4509             :         // GetMetadata("IMAGE_STRUCTURE")
    4510          28 :         if (!EQUAL(pszDomain, "IMAGE_STRUCTURE"))
    4511             :         {
    4512             :             char **papszGT_MD =
    4513          28 :                 CSLDuplicate(m_oGTiffMDMD.GetMetadata(pszDomain));
    4514          28 :             char **papszPAM_MD = oMDMD.GetMetadata(pszDomain);
    4515             : 
    4516          28 :             papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
    4517             : 
    4518          28 :             m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
    4519          28 :             CSLDestroy(papszGT_MD);
    4520             :         }
    4521             :     }
    4522             : 
    4523      399223 :     for (int i = 1; i <= GetRasterCount(); ++i)
    4524             :     {
    4525             :         GTiffRasterBand *poBand =
    4526      384256 :             cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
    4527      384256 :         papszPamDomains = poBand->oMDMD.GetDomainList();
    4528             : 
    4529      384328 :         for (int iDomain = 0;
    4530      384328 :              papszPamDomains && papszPamDomains[iDomain] != nullptr; ++iDomain)
    4531             :         {
    4532          72 :             const char *pszDomain = papszPamDomains[iDomain];
    4533             :             char **papszGT_MD =
    4534          72 :                 CSLDuplicate(poBand->m_oGTiffMDMD.GetMetadata(pszDomain));
    4535          72 :             char **papszPAM_MD = poBand->oMDMD.GetMetadata(pszDomain);
    4536             : 
    4537          72 :             papszGT_MD = CSLMerge(papszGT_MD, papszPAM_MD);
    4538             : 
    4539          72 :             poBand->m_oGTiffMDMD.SetMetadata(papszGT_MD, pszDomain);
    4540          72 :             CSLDestroy(papszGT_MD);
    4541             :         }
    4542             :     }
    4543             : 
    4544      399223 :     for (int i = 1; i <= nBands; ++i)
    4545             :     {
    4546             :         GTiffRasterBand *poBand =
    4547      384256 :             cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i));
    4548             : 
    4549             :         /* Load scale, offset and unittype from PAM if available */
    4550      384256 :         int nHaveOffsetScale = false;
    4551      384256 :         double dfScale = poBand->GDALPamRasterBand::GetScale(&nHaveOffsetScale);
    4552      384256 :         if (nHaveOffsetScale)
    4553             :         {
    4554           2 :             poBand->m_bHaveOffsetScale = true;
    4555           2 :             poBand->m_dfScale = dfScale;
    4556           2 :             poBand->m_dfOffset = poBand->GDALPamRasterBand::GetOffset();
    4557             :         }
    4558             : 
    4559      384256 :         const char *pszUnitType = poBand->GDALPamRasterBand::GetUnitType();
    4560      384256 :         if (pszUnitType && pszUnitType[0])
    4561           3 :             poBand->m_osUnitType = pszUnitType;
    4562             : 
    4563             :         const char *pszDescription =
    4564      384256 :             poBand->GDALPamRasterBand::GetDescription();
    4565      384256 :         if (pszDescription && pszDescription[0])
    4566           4 :             poBand->m_osDescription = pszDescription;
    4567             : 
    4568             :         GDALColorInterp ePAMColorInterp =
    4569      384256 :             poBand->GDALPamRasterBand::GetColorInterpretation();
    4570      384256 :         if (ePAMColorInterp != GCI_Undefined)
    4571          51 :             poBand->m_eBandInterp = ePAMColorInterp;
    4572             : 
    4573      384256 :         if (i == 1)
    4574             :         {
    4575       14967 :             const auto poCT = poBand->GDALPamRasterBand::GetColorTable();
    4576       14967 :             if (poCT)
    4577             :             {
    4578           4 :                 m_poColorTable.reset(poCT->Clone());
    4579             :             }
    4580             :         }
    4581             :     }
    4582       14967 : }
    4583             : 
    4584             : /************************************************************************/
    4585             : /*                              OpenDir()                               */
    4586             : /*                                                                      */
    4587             : /*      Open a specific directory as encoded into a filename.           */
    4588             : /************************************************************************/
    4589             : 
    4590          30 : GDALDataset *GTiffDataset::OpenDir(GDALOpenInfo *poOpenInfo)
    4591             : 
    4592             : {
    4593          30 :     bool bAllowRGBAInterface = true;
    4594          30 :     const char *pszFilename = poOpenInfo->pszFilename;
    4595          30 :     if (STARTS_WITH_CI(pszFilename, "GTIFF_RAW:"))
    4596             :     {
    4597           1 :         bAllowRGBAInterface = false;
    4598           1 :         pszFilename += strlen("GTIFF_RAW:");
    4599             :     }
    4600             : 
    4601          30 :     if (!STARTS_WITH_CI(pszFilename, "GTIFF_DIR:") ||
    4602          30 :         pszFilename[strlen("GTIFF_DIR:")] == '\0')
    4603             :     {
    4604           5 :         return nullptr;
    4605             :     }
    4606             : 
    4607             :     /* -------------------------------------------------------------------- */
    4608             :     /*      Split out filename, and dir#/offset.                            */
    4609             :     /* -------------------------------------------------------------------- */
    4610          25 :     pszFilename += strlen("GTIFF_DIR:");
    4611          25 :     bool bAbsolute = false;
    4612             : 
    4613          25 :     if (STARTS_WITH_CI(pszFilename, "off:"))
    4614             :     {
    4615           2 :         bAbsolute = true;
    4616           2 :         pszFilename += 4;
    4617             :     }
    4618             : 
    4619          25 :     toff_t nOffset = atol(pszFilename);
    4620          25 :     pszFilename += 1;
    4621             : 
    4622          54 :     while (*pszFilename != '\0' && pszFilename[-1] != ':')
    4623          29 :         ++pszFilename;
    4624             : 
    4625          25 :     if (*pszFilename == '\0' || nOffset == 0)
    4626             :     {
    4627           0 :         ReportError(
    4628             :             pszFilename, CE_Failure, CPLE_OpenFailed,
    4629             :             "Unable to extract offset or filename, should take the form:\n"
    4630             :             "GTIFF_DIR:<dir>:filename or GTIFF_DIR:off:<dir_offset>:filename");
    4631           0 :         return nullptr;
    4632             :     }
    4633             : 
    4634          25 :     if (poOpenInfo->eAccess == GA_Update)
    4635             :     {
    4636           1 :         ReportError(pszFilename, CE_Warning, CPLE_AppDefined,
    4637             :                     "Opening a specific TIFF directory is not supported in "
    4638             :                     "update mode. Switching to read-only");
    4639             :     }
    4640             : 
    4641             :     /* -------------------------------------------------------------------- */
    4642             :     /*      Try opening the dataset.                                        */
    4643             :     /* -------------------------------------------------------------------- */
    4644          25 :     GTiffOneTimeInit();
    4645             : 
    4646          25 :     const char *pszFlag = poOpenInfo->eAccess == GA_Update ? "r+DC" : "rDOC";
    4647          25 :     VSILFILE *l_fpL = VSIFOpenL(pszFilename, pszFlag);
    4648          25 :     if (l_fpL == nullptr)
    4649           0 :         return nullptr;
    4650          25 :     TIFF *l_hTIFF = VSI_TIFFOpen(pszFilename, pszFlag, l_fpL);
    4651          25 :     if (l_hTIFF == nullptr)
    4652             :     {
    4653           0 :         CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    4654           0 :         return nullptr;
    4655             :     }
    4656             : 
    4657             :     /* -------------------------------------------------------------------- */
    4658             :     /*      If a directory was requested by index, advance to it now.       */
    4659             :     /* -------------------------------------------------------------------- */
    4660          25 :     if (!bAbsolute)
    4661             :     {
    4662          23 :         const toff_t nOffsetRequested = nOffset;
    4663          38 :         while (nOffset > 1)
    4664             :         {
    4665          15 :             if (TIFFReadDirectory(l_hTIFF) == 0)
    4666             :             {
    4667           0 :                 XTIFFClose(l_hTIFF);
    4668           0 :                 ReportError(pszFilename, CE_Failure, CPLE_OpenFailed,
    4669             :                             "Requested directory %lu not found.",
    4670             :                             static_cast<long unsigned int>(nOffsetRequested));
    4671           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(l_fpL));
    4672           0 :                 return nullptr;
    4673             :             }
    4674          15 :             nOffset--;
    4675             :         }
    4676             : 
    4677          23 :         nOffset = TIFFCurrentDirOffset(l_hTIFF);
    4678             :     }
    4679             : 
    4680             :     /* -------------------------------------------------------------------- */
    4681             :     /*      Create a corresponding GDALDataset.                             */
    4682             :     /* -------------------------------------------------------------------- */
    4683          50 :     auto poDS = std::make_unique<GTiffDataset>();
    4684          25 :     poDS->SetDescription(poOpenInfo->pszFilename);
    4685          25 :     poDS->m_osFilename = pszFilename;
    4686          25 :     poDS->m_fpL = l_fpL;
    4687          25 :     poDS->m_hTIFF = l_hTIFF;
    4688          25 :     poDS->m_bSingleIFDOpened = true;
    4689             : 
    4690          25 :     if (!EQUAL(pszFilename, poOpenInfo->pszFilename) &&
    4691          25 :         !STARTS_WITH_CI(poOpenInfo->pszFilename, "GTIFF_RAW:"))
    4692             :     {
    4693          24 :         poDS->SetPhysicalFilename(pszFilename);
    4694          24 :         poDS->SetSubdatasetName(poOpenInfo->pszFilename);
    4695             :     }
    4696             : 
    4697          25 :     if (poOpenInfo->AreSiblingFilesLoaded())
    4698          25 :         poDS->oOvManager.TransferSiblingFiles(poOpenInfo->StealSiblingFiles());
    4699             : 
    4700          25 :     if (poDS->OpenOffset(l_hTIFF, nOffset, poOpenInfo->eAccess,
    4701          25 :                          bAllowRGBAInterface, true) != CE_None)
    4702             :     {
    4703           1 :         return nullptr;
    4704             :     }
    4705             : 
    4706          24 :     return poDS.release();
    4707             : }
    4708             : 
    4709             : /************************************************************************/
    4710             : /*                   ConvertTransferFunctionToString()                  */
    4711             : /*                                                                      */
    4712             : /*      Convert a transfer function table into a string.                */
    4713             : /*      Used by LoadICCProfile().                                       */
    4714             : /************************************************************************/
    4715          21 : static CPLString ConvertTransferFunctionToString(const uint16_t *pTable,
    4716             :                                                  uint32_t nTableEntries)
    4717             : {
    4718          21 :     CPLString sValue;
    4719             : 
    4720        5397 :     for (uint32_t i = 0; i < nTableEntries; ++i)
    4721             :     {
    4722        5376 :         if (i > 0)
    4723        5355 :             sValue += ", ";
    4724        5376 :         sValue += CPLSPrintf("%d", static_cast<uint32_t>(pTable[i]));
    4725             :     }
    4726             : 
    4727          21 :     return sValue;
    4728             : }
    4729             : 
    4730             : /************************************************************************/
    4731             : /*                             LoadICCProfile()                         */
    4732             : /*                                                                      */
    4733             : /*      Load ICC Profile or colorimetric data into metadata             */
    4734             : /************************************************************************/
    4735             : 
    4736        5692 : void GTiffDataset::LoadICCProfile()
    4737             : {
    4738        5692 :     if (m_bICCMetadataLoaded)
    4739        5143 :         return;
    4740         562 :     m_bICCMetadataLoaded = true;
    4741             : 
    4742         562 :     uint32_t nEmbedLen = 0;
    4743         562 :     uint8_t *pEmbedBuffer = nullptr;
    4744             : 
    4745         562 :     if (TIFFGetField(m_hTIFF, TIFFTAG_ICCPROFILE, &nEmbedLen, &pEmbedBuffer))
    4746             :     {
    4747          12 :         char *pszBase64Profile = CPLBase64Encode(
    4748             :             nEmbedLen, reinterpret_cast<const GByte *>(pEmbedBuffer));
    4749             : 
    4750          12 :         m_oGTiffMDMD.SetMetadataItem("SOURCE_ICC_PROFILE", pszBase64Profile,
    4751             :                                      "COLOR_PROFILE");
    4752             : 
    4753          12 :         CPLFree(pszBase64Profile);
    4754             : 
    4755          12 :         return;
    4756             :     }
    4757             : 
    4758             :     // Check for colorimetric tiff.
    4759         550 :     float *pCHR = nullptr;
    4760         550 :     float *pWP = nullptr;
    4761         550 :     uint16_t *pTFR = nullptr;
    4762         550 :     uint16_t *pTFG = nullptr;
    4763         550 :     uint16_t *pTFB = nullptr;
    4764         550 :     uint16_t *pTransferRange = nullptr;
    4765             : 
    4766         550 :     if (TIFFGetField(m_hTIFF, TIFFTAG_PRIMARYCHROMATICITIES, &pCHR))
    4767             :     {
    4768           8 :         if (TIFFGetField(m_hTIFF, TIFFTAG_WHITEPOINT, &pWP))
    4769             :         {
    4770          24 :             if (m_nBitsPerSample > 24 ||
    4771           8 :                 !TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERFUNCTION, &pTFR,
    4772           8 :                                        &pTFG, &pTFB) ||
    4773          16 :                 pTFR == nullptr || pTFG == nullptr || pTFB == nullptr)
    4774             :             {
    4775           1 :                 return;
    4776             :             }
    4777             : 
    4778           7 :             const int TIFFTAG_TRANSFERRANGE = 0x0156;
    4779           7 :             TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_TRANSFERRANGE,
    4780             :                                   &pTransferRange);
    4781             : 
    4782             :             // Set all the colorimetric metadata.
    4783           7 :             m_oGTiffMDMD.SetMetadataItem(
    4784             :                 "SOURCE_PRIMARIES_RED",
    4785          14 :                 CPLString().Printf("%.9f, %.9f, 1.0",
    4786           7 :                                    static_cast<double>(pCHR[0]),
    4787           7 :                                    static_cast<double>(pCHR[1])),
    4788             :                 "COLOR_PROFILE");
    4789           7 :             m_oGTiffMDMD.SetMetadataItem(
    4790             :                 "SOURCE_PRIMARIES_GREEN",
    4791          14 :                 CPLString().Printf("%.9f, %.9f, 1.0",
    4792           7 :                                    static_cast<double>(pCHR[2]),
    4793           7 :                                    static_cast<double>(pCHR[3])),
    4794             :                 "COLOR_PROFILE");
    4795           7 :             m_oGTiffMDMD.SetMetadataItem(
    4796             :                 "SOURCE_PRIMARIES_BLUE",
    4797          14 :                 CPLString().Printf("%.9f, %.9f, 1.0",
    4798           7 :                                    static_cast<double>(pCHR[4]),
    4799           7 :                                    static_cast<double>(pCHR[5])),
    4800             :                 "COLOR_PROFILE");
    4801             : 
    4802           7 :             m_oGTiffMDMD.SetMetadataItem(
    4803             :                 "SOURCE_WHITEPOINT",
    4804          14 :                 CPLString().Printf("%.9f, %.9f, 1.0",
    4805           7 :                                    static_cast<double>(pWP[0]),
    4806           7 :                                    static_cast<double>(pWP[1])),
    4807             :                 "COLOR_PROFILE");
    4808             : 
    4809             :             // Set transfer function metadata.
    4810             : 
    4811             :             // Get length of table.
    4812           7 :             const uint32_t nTransferFunctionLength = 1 << m_nBitsPerSample;
    4813             : 
    4814           7 :             m_oGTiffMDMD.SetMetadataItem(
    4815             :                 "TIFFTAG_TRANSFERFUNCTION_RED",
    4816          14 :                 ConvertTransferFunctionToString(pTFR, nTransferFunctionLength),
    4817             :                 "COLOR_PROFILE");
    4818             : 
    4819           7 :             m_oGTiffMDMD.SetMetadataItem(
    4820             :                 "TIFFTAG_TRANSFERFUNCTION_GREEN",
    4821          14 :                 ConvertTransferFunctionToString(pTFG, nTransferFunctionLength),
    4822             :                 "COLOR_PROFILE");
    4823             : 
    4824           7 :             m_oGTiffMDMD.SetMetadataItem(
    4825             :                 "TIFFTAG_TRANSFERFUNCTION_BLUE",
    4826          14 :                 ConvertTransferFunctionToString(pTFB, nTransferFunctionLength),
    4827             :                 "COLOR_PROFILE");
    4828             : 
    4829             :             // Set transfer range.
    4830           7 :             if (pTransferRange)
    4831             :             {
    4832           0 :                 m_oGTiffMDMD.SetMetadataItem(
    4833             :                     "TIFFTAG_TRANSFERRANGE_BLACK",
    4834           0 :                     CPLString().Printf("%d, %d, %d",
    4835           0 :                                        static_cast<int>(pTransferRange[0]),
    4836           0 :                                        static_cast<int>(pTransferRange[2]),
    4837           0 :                                        static_cast<int>(pTransferRange[4])),
    4838             :                     "COLOR_PROFILE");
    4839           0 :                 m_oGTiffMDMD.SetMetadataItem(
    4840             :                     "TIFFTAG_TRANSFERRANGE_WHITE",
    4841           0 :                     CPLString().Printf("%d, %d, %d",
    4842           0 :                                        static_cast<int>(pTransferRange[1]),
    4843           0 :                                        static_cast<int>(pTransferRange[3]),
    4844           0 :                                        static_cast<int>(pTransferRange[5])),
    4845             :                     "COLOR_PROFILE");
    4846             :             }
    4847             :         }
    4848             :     }
    4849             : }
    4850             : 
    4851             : /************************************************************************/
    4852             : /*                             OpenOffset()                             */
    4853             : /*                                                                      */
    4854             : /*      Initialize the GTiffDataset based on a passed in file           */
    4855             : /*      handle, and directory offset to utilize.  This is called for    */
    4856             : /*      full res, and overview pages.                                   */
    4857             : /************************************************************************/
    4858             : 
    4859       27928 : CPLErr GTiffDataset::OpenOffset(TIFF *hTIFFIn, toff_t nDirOffsetIn,
    4860             :                                 GDALAccess eAccessIn, bool bAllowRGBAInterface,
    4861             :                                 bool bReadGeoTransform)
    4862             : 
    4863             : {
    4864       27928 :     if (!hTIFFIn)
    4865           0 :         return CE_Failure;
    4866             : 
    4867       27928 :     eAccess = eAccessIn;
    4868             : 
    4869       27928 :     m_hTIFF = hTIFFIn;
    4870             : 
    4871       27928 :     m_nDirOffset = nDirOffsetIn;
    4872             : 
    4873       27928 :     if (!SetDirectory())
    4874           0 :         return CE_Failure;
    4875             : 
    4876             :     /* -------------------------------------------------------------------- */
    4877             :     /*      Capture some information from the file that is of interest.     */
    4878             :     /* -------------------------------------------------------------------- */
    4879       27928 :     uint32_t nXSize = 0;
    4880       27928 :     uint32_t nYSize = 0;
    4881       27928 :     TIFFGetField(m_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
    4882       27928 :     TIFFGetField(m_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
    4883             : 
    4884             :     // Unlikely to occur, but could happen on a disk full situation.
    4885       27928 :     if (nXSize == 0 || nYSize == 0)
    4886           0 :         return CE_Failure;
    4887             : 
    4888       27928 :     if (nXSize > INT_MAX || nYSize > INT_MAX)
    4889             :     {
    4890             :         // GDAL only supports signed 32bit dimensions.
    4891           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    4892             :                     "Too large image size: %u x %u", nXSize, nYSize);
    4893           1 :         return CE_Failure;
    4894             :     }
    4895       27927 :     nRasterXSize = nXSize;
    4896       27927 :     nRasterYSize = nYSize;
    4897             : 
    4898       27927 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLESPERPIXEL, &m_nSamplesPerPixel))
    4899           7 :         nBands = 1;
    4900             :     else
    4901       27920 :         nBands = m_nSamplesPerPixel;
    4902             : 
    4903       27927 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_BITSPERSAMPLE, &(m_nBitsPerSample)))
    4904           7 :         m_nBitsPerSample = 1;
    4905             : 
    4906       27927 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_PLANARCONFIG, &(m_nPlanarConfig)))
    4907           0 :         m_nPlanarConfig = PLANARCONFIG_CONTIG;
    4908             : 
    4909       27927 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_PHOTOMETRIC, &(m_nPhotometric)))
    4910          10 :         m_nPhotometric = PHOTOMETRIC_MINISBLACK;
    4911             : 
    4912       27927 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLEFORMAT, &(m_nSampleFormat)))
    4913         148 :         m_nSampleFormat = SAMPLEFORMAT_UINT;
    4914             : 
    4915       27927 :     if (!TIFFGetField(m_hTIFF, TIFFTAG_COMPRESSION, &(m_nCompression)))
    4916           0 :         m_nCompression = COMPRESSION_NONE;
    4917             : 
    4918       31750 :     if (m_nCompression != COMPRESSION_NONE &&
    4919        3823 :         !TIFFIsCODECConfigured(m_nCompression))
    4920             :     {
    4921             :         const char *pszCompressionMethodName =
    4922           3 :             GTIFFGetCompressionMethodName(m_nCompression);
    4923           3 :         if (pszCompressionMethodName)
    4924             :         {
    4925           1 :             ReportError(CE_Failure, CPLE_AppDefined,
    4926             :                         "Cannot open TIFF file due to missing codec %s.",
    4927             :                         pszCompressionMethodName);
    4928             :         }
    4929             :         else
    4930             :         {
    4931           2 :             ReportError(
    4932             :                 CE_Failure, CPLE_AppDefined,
    4933             :                 "Cannot open TIFF file due to missing codec of code %d.",
    4934           2 :                 m_nCompression);
    4935             :         }
    4936           3 :         return CE_Failure;
    4937             :     }
    4938             : 
    4939             :     /* -------------------------------------------------------------------- */
    4940             :     /*      YCbCr JPEG compressed images should be translated on the fly    */
    4941             :     /*      to RGB by libtiff/libjpeg unless specifically requested         */
    4942             :     /*      otherwise.                                                      */
    4943             :     /* -------------------------------------------------------------------- */
    4944       56312 :     if (m_nCompression == COMPRESSION_JPEG &&
    4945       28176 :         m_nPhotometric == PHOTOMETRIC_YCBCR &&
    4946         252 :         CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
    4947             :     {
    4948         252 :         m_oGTiffMDMD.SetMetadataItem("SOURCE_COLOR_SPACE", "YCbCr",
    4949             :                                      "IMAGE_STRUCTURE");
    4950         252 :         int nColorMode = 0;
    4951         504 :         if (!TIFFGetField(m_hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode) ||
    4952         252 :             nColorMode != JPEGCOLORMODE_RGB)
    4953             :         {
    4954         252 :             TIFFSetField(m_hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
    4955             :         }
    4956             :     }
    4957             : 
    4958             :     /* -------------------------------------------------------------------- */
    4959             :     /*      Get strip/tile layout.                                          */
    4960             :     /* -------------------------------------------------------------------- */
    4961       27924 :     if (TIFFIsTiled(m_hTIFF))
    4962             :     {
    4963        3879 :         uint32_t l_nBlockXSize = 0;
    4964        3879 :         uint32_t l_nBlockYSize = 0;
    4965        3879 :         TIFFGetField(m_hTIFF, TIFFTAG_TILEWIDTH, &(l_nBlockXSize));
    4966        3879 :         TIFFGetField(m_hTIFF, TIFFTAG_TILELENGTH, &(l_nBlockYSize));
    4967        3879 :         if (l_nBlockXSize > INT_MAX || l_nBlockYSize > INT_MAX)
    4968             :         {
    4969           2 :             ReportError(CE_Failure, CPLE_NotSupported,
    4970             :                         "Too large block size: %u x %u", l_nBlockXSize,
    4971             :                         l_nBlockYSize);
    4972           2 :             return CE_Failure;
    4973             :         }
    4974        3877 :         m_nBlockXSize = static_cast<int>(l_nBlockXSize);
    4975        3877 :         m_nBlockYSize = static_cast<int>(l_nBlockYSize);
    4976             :     }
    4977             :     else
    4978             :     {
    4979       24045 :         if (!TIFFGetField(m_hTIFF, TIFFTAG_ROWSPERSTRIP, &(m_nRowsPerStrip)))
    4980             :         {
    4981           6 :             ReportError(CE_Warning, CPLE_AppDefined,
    4982             :                         "RowsPerStrip not defined ... assuming all one strip.");
    4983           6 :             m_nRowsPerStrip = nYSize;  // Dummy value.
    4984             :         }
    4985             : 
    4986             :         // If the rows per strip is larger than the file we will get
    4987             :         // confused.  libtiff internally will treat the rowsperstrip as
    4988             :         // the image height and it is best if we do too. (#4468)
    4989       24045 :         if (m_nRowsPerStrip > static_cast<uint32_t>(nRasterYSize))
    4990          24 :             m_nRowsPerStrip = nRasterYSize;
    4991             : 
    4992       24045 :         m_nBlockXSize = nRasterXSize;
    4993       24045 :         m_nBlockYSize = m_nRowsPerStrip;
    4994             :     }
    4995             : 
    4996       27922 :     if (!ComputeBlocksPerColRowAndBand(nBands))
    4997           2 :         return CE_Failure;
    4998             : 
    4999             :     /* -------------------------------------------------------------------- */
    5000             :     /*      Should we handle this using the GTiffBitmapBand?                */
    5001             :     /* -------------------------------------------------------------------- */
    5002       27920 :     bool bTreatAsBitmap = false;
    5003             : 
    5004       27920 :     if (m_nBitsPerSample == 1 && nBands == 1)
    5005             :     {
    5006         409 :         bTreatAsBitmap = true;
    5007             : 
    5008             :         // Lets treat large "one row" bitmaps using the scanline api.
    5009         572 :         if (!TIFFIsTiled(m_hTIFF) && m_nBlockYSize == nRasterYSize &&
    5010         135 :             nRasterYSize > 2000
    5011             :             // libtiff does not support reading JBIG files with
    5012             :             // TIFFReadScanline().
    5013         572 :             && m_nCompression != COMPRESSION_JBIG)
    5014             :         {
    5015          11 :             m_bTreatAsSplitBitmap = true;
    5016             :         }
    5017             :     }
    5018             : 
    5019             :     /* -------------------------------------------------------------------- */
    5020             :     /*      Should we treat this via the RGBA interface?                    */
    5021             :     /* -------------------------------------------------------------------- */
    5022       27920 :     bool bTreatAsRGBA = false;
    5023       27920 :     if (
    5024             : #ifdef DEBUG
    5025       53705 :         CPLTestBool(CPLGetConfigOption("GTIFF_FORCE_RGBA", "NO")) ||
    5026             : #endif
    5027       25785 :         (bAllowRGBAInterface && !bTreatAsBitmap && !(m_nBitsPerSample > 8) &&
    5028       19795 :          (m_nPhotometric == PHOTOMETRIC_CIELAB ||
    5029       19794 :           m_nPhotometric == PHOTOMETRIC_LOGL ||
    5030       19794 :           m_nPhotometric == PHOTOMETRIC_LOGLUV ||
    5031       19794 :           m_nPhotometric == PHOTOMETRIC_SEPARATED ||
    5032       19784 :           (m_nPhotometric == PHOTOMETRIC_YCBCR &&
    5033         230 :            m_nCompression != COMPRESSION_JPEG))))
    5034             :     {
    5035          35 :         char szMessage[1024] = {};
    5036             : 
    5037          35 :         if (TIFFRGBAImageOK(m_hTIFF, szMessage) == 1)
    5038             :         {
    5039          35 :             const char *pszSourceColorSpace = nullptr;
    5040          35 :             nBands = 4;
    5041          35 :             switch (m_nPhotometric)
    5042             :             {
    5043           1 :                 case PHOTOMETRIC_CIELAB:
    5044           1 :                     pszSourceColorSpace = "CIELAB";
    5045           1 :                     break;
    5046           1 :                 case PHOTOMETRIC_LOGL:
    5047           1 :                     pszSourceColorSpace = "LOGL";
    5048           1 :                     break;
    5049           0 :                 case PHOTOMETRIC_LOGLUV:
    5050           0 :                     pszSourceColorSpace = "LOGLUV";
    5051           0 :                     break;
    5052          10 :                 case PHOTOMETRIC_SEPARATED:
    5053          10 :                     pszSourceColorSpace = "CMYK";
    5054          10 :                     break;
    5055          13 :                 case PHOTOMETRIC_YCBCR:
    5056          13 :                     pszSourceColorSpace = "YCbCr";
    5057          13 :                     nBands = 3;  // probably true for other photometric values
    5058          13 :                     break;
    5059             :             }
    5060          35 :             if (pszSourceColorSpace)
    5061          25 :                 m_oGTiffMDMD.SetMetadataItem("SOURCE_COLOR_SPACE",
    5062             :                                              pszSourceColorSpace,
    5063             :                                              "IMAGE_STRUCTURE");
    5064          35 :             bTreatAsRGBA = true;
    5065             :         }
    5066             :         else
    5067             :         {
    5068           0 :             CPLDebug("GTiff", "TIFFRGBAImageOK says:\n%s", szMessage);
    5069             :         }
    5070             :     }
    5071             : 
    5072             :     // libtiff has various issues with OJPEG compression and chunky-strip
    5073             :     // support with the "classic" scanline/strip/tile interfaces, and that
    5074             :     // wouldn't work either, so better bail out.
    5075       27920 :     if (m_nCompression == COMPRESSION_OJPEG && !bTreatAsRGBA)
    5076             :     {
    5077           0 :         ReportError(
    5078             :             CE_Failure, CPLE_NotSupported,
    5079             :             "Old-JPEG compression only supported through RGBA interface, "
    5080             :             "which cannot be used probably because the file is corrupted");
    5081           0 :         return CE_Failure;
    5082             :     }
    5083             : 
    5084             :     // If photometric is YCbCr, scanline/strip/tile interfaces assumes that
    5085             :     // we are ready with downsampled data. And we are not.
    5086       27920 :     if (m_nCompression != COMPRESSION_JPEG &&
    5087       27456 :         m_nCompression != COMPRESSION_OJPEG &&
    5088       27454 :         m_nPhotometric == PHOTOMETRIC_YCBCR &&
    5089          12 :         m_nPlanarConfig == PLANARCONFIG_CONTIG && !bTreatAsRGBA)
    5090             :     {
    5091             :         uint16_t nF1, nF2;
    5092           1 :         TIFFGetFieldDefaulted(m_hTIFF, TIFFTAG_YCBCRSUBSAMPLING, &nF1, &nF2);
    5093           1 :         if (nF1 != 1 || nF2 != 1)
    5094             :         {
    5095           1 :             ReportError(CE_Failure, CPLE_AppDefined,
    5096             :                         "Cannot open TIFF file with YCbCr, subsampling and "
    5097             :                         "BitsPerSample > 8 that is not JPEG compressed");
    5098           1 :             return CE_Failure;
    5099             :         }
    5100             :     }
    5101             : 
    5102             :     /* -------------------------------------------------------------------- */
    5103             :     /*      Should we treat this via the split interface?                   */
    5104             :     /* -------------------------------------------------------------------- */
    5105       51963 :     if (!TIFFIsTiled(m_hTIFF) && m_nBitsPerSample == 8 &&
    5106       51987 :         m_nBlockYSize == nRasterYSize && nRasterYSize > 2000 && !bTreatAsRGBA &&
    5107          24 :         CPLTestBool(CPLGetConfigOption("GDAL_ENABLE_TIFF_SPLIT", "YES")))
    5108             :     {
    5109          24 :         m_bTreatAsSplit = true;
    5110             :     }
    5111             : 
    5112             :     /* -------------------------------------------------------------------- */
    5113             :     /*      Should we treat this via the odd bits interface?                */
    5114             :     /* -------------------------------------------------------------------- */
    5115       27919 :     bool bTreatAsOdd = false;
    5116       27919 :     if (m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
    5117             :     {
    5118        1849 :         if (m_nBitsPerSample == 24)
    5119           2 :             bTreatAsOdd = true;
    5120        1847 :         else if (m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
    5121         737 :                  m_nBitsPerSample != 64)
    5122             :         {
    5123           0 :             ReportError(CE_Failure, CPLE_AppDefined,
    5124             :                         "Cannot open TIFF file with SampleFormat=IEEEFP "
    5125             :                         "and BitsPerSample=%d",
    5126           0 :                         m_nBitsPerSample);
    5127           0 :             return CE_Failure;
    5128             :         }
    5129             :     }
    5130       26070 :     else if (!bTreatAsRGBA && !bTreatAsBitmap && m_nBitsPerSample != 8 &&
    5131        4185 :              m_nBitsPerSample != 16 && m_nBitsPerSample != 32 &&
    5132        1368 :              m_nBitsPerSample != 64 && m_nBitsPerSample != 128)
    5133             :     {
    5134         203 :         bTreatAsOdd = true;
    5135             :     }
    5136             : 
    5137             : /* -------------------------------------------------------------------- */
    5138             : /*      We can't support 'chunks' bigger than 2GB on 32 bit builds      */
    5139             : /* -------------------------------------------------------------------- */
    5140             : #if SIZEOF_VOIDP == 4
    5141             :     uint64_t nChunkSize = 0;
    5142             :     if (m_bTreatAsSplit || m_bTreatAsSplitBitmap)
    5143             :     {
    5144             :         nChunkSize = TIFFScanlineSize64(m_hTIFF);
    5145             :     }
    5146             :     else
    5147             :     {
    5148             :         if (TIFFIsTiled(m_hTIFF))
    5149             :             nChunkSize = TIFFTileSize64(m_hTIFF);
    5150             :         else
    5151             :             nChunkSize = TIFFStripSize64(m_hTIFF);
    5152             :     }
    5153             :     if (bTreatAsRGBA)
    5154             :     {
    5155             :         nChunkSize =
    5156             :             std::max(nChunkSize,
    5157             :                      4 * static_cast<uint64_t>(m_nBlockXSize) * m_nBlockYSize);
    5158             :     }
    5159             :     if (nChunkSize > static_cast<uint64_t>(INT_MAX))
    5160             :     {
    5161             :         ReportError(CE_Failure, CPLE_NotSupported,
    5162             :                     "Scanline/tile/strip size bigger than 2GB unsupported "
    5163             :                     "on 32-bit builds.");
    5164             :         return CE_Failure;
    5165             :     }
    5166             : #endif
    5167             : 
    5168       27919 :     const bool bMinIsWhite = m_nPhotometric == PHOTOMETRIC_MINISWHITE;
    5169             : 
    5170             :     /* -------------------------------------------------------------------- */
    5171             :     /*      Check for NODATA                                                */
    5172             :     /* -------------------------------------------------------------------- */
    5173       27919 :     char *pszText = nullptr;
    5174       29352 :     if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_NODATA, &pszText) &&
    5175        1433 :         !EQUAL(pszText, ""))
    5176             :     {
    5177        1432 :         if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
    5178         120 :             m_nSampleFormat == SAMPLEFORMAT_INT)
    5179             :         {
    5180           5 :             m_bNoDataSetAsInt64 = true;
    5181           5 :             m_nNoDataValueInt64 =
    5182           5 :                 static_cast<int64_t>(std::strtoll(pszText, nullptr, 10));
    5183             :         }
    5184        1427 :         else if (m_nBitsPerSample > 32 && m_nBitsPerSample <= 64 &&
    5185         115 :                  m_nSampleFormat == SAMPLEFORMAT_UINT)
    5186             :         {
    5187           5 :             m_bNoDataSetAsUInt64 = true;
    5188           5 :             m_nNoDataValueUInt64 =
    5189           5 :                 static_cast<uint64_t>(std::strtoull(pszText, nullptr, 10));
    5190             :         }
    5191             :         else
    5192             :         {
    5193        1422 :             m_bNoDataSet = true;
    5194        1422 :             m_dfNoDataValue = CPLAtofM(pszText);
    5195        1422 :             if (m_nBitsPerSample == 32 &&
    5196         206 :                 m_nSampleFormat == SAMPLEFORMAT_IEEEFP)
    5197             :             {
    5198         148 :                 m_dfNoDataValue =
    5199         148 :                     GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
    5200         148 :                 m_dfNoDataValue =
    5201         148 :                     static_cast<double>(static_cast<float>(m_dfNoDataValue));
    5202             :             }
    5203             :         }
    5204             :     }
    5205             : 
    5206             :     /* -------------------------------------------------------------------- */
    5207             :     /*      Capture the color table if there is one.                        */
    5208             :     /* -------------------------------------------------------------------- */
    5209       27919 :     unsigned short *panRed = nullptr;
    5210       27919 :     unsigned short *panGreen = nullptr;
    5211       27919 :     unsigned short *panBlue = nullptr;
    5212             : 
    5213       51630 :     if (bTreatAsRGBA || m_nBitsPerSample > 16 ||
    5214       23711 :         TIFFGetField(m_hTIFF, TIFFTAG_COLORMAP, &panRed, &panGreen, &panBlue) ==
    5215             :             0)
    5216             :     {
    5217             :         // Build inverted palette if we have inverted photometric.
    5218             :         // Pixel values remains unchanged.  Avoid doing this for *deep*
    5219             :         // data types (per #1882)
    5220       27755 :         if (m_nBitsPerSample <= 16 && m_nPhotometric == PHOTOMETRIC_MINISWHITE)
    5221             :         {
    5222          13 :             m_poColorTable = std::make_unique<GDALColorTable>();
    5223          13 :             const int nColorCount = 1 << m_nBitsPerSample;
    5224             : 
    5225          39 :             for (int iColor = 0; iColor < nColorCount; ++iColor)
    5226             :             {
    5227          26 :                 const short nValue = static_cast<short>(
    5228          26 :                     ((255 * (nColorCount - 1 - iColor)) / (nColorCount - 1)));
    5229          26 :                 const GDALColorEntry oEntry = {nValue, nValue, nValue,
    5230          26 :                                                static_cast<short>(255)};
    5231          26 :                 m_poColorTable->SetColorEntry(iColor, &oEntry);
    5232             :             }
    5233             : 
    5234          13 :             m_nPhotometric = PHOTOMETRIC_PALETTE;
    5235             :         }
    5236             :         else
    5237             :         {
    5238       27742 :             m_poColorTable.reset();
    5239             :         }
    5240             :     }
    5241             :     else
    5242             :     {
    5243         164 :         const int nColorCount = 1 << m_nBitsPerSample;
    5244         164 :         m_poColorTable = gdal::tiff_common::TIFFColorMapTagToColorTable(
    5245         164 :             panRed, panGreen, panBlue, nColorCount, m_nColorTableMultiplier,
    5246         164 :             DEFAULT_COLOR_TABLE_MULTIPLIER_257, m_bNoDataSet, m_dfNoDataValue);
    5247             :     }
    5248             : 
    5249             :     /* -------------------------------------------------------------------- */
    5250             :     /*      Create band information objects.                                */
    5251             :     /* -------------------------------------------------------------------- */
    5252      758584 :     for (int iBand = 0; iBand < nBands; ++iBand)
    5253             :     {
    5254      730665 :         if (bTreatAsRGBA)
    5255         127 :             SetBand(iBand + 1,
    5256         254 :                     std::make_unique<GTiffRGBABand>(this, iBand + 1));
    5257      730538 :         else if (m_bTreatAsSplitBitmap)
    5258          11 :             SetBand(iBand + 1,
    5259          22 :                     std::make_unique<GTiffSplitBitmapBand>(this, iBand + 1));
    5260      730527 :         else if (m_bTreatAsSplit)
    5261      131118 :             SetBand(iBand + 1,
    5262      262236 :                     std::make_unique<GTiffSplitBand>(this, iBand + 1));
    5263      599409 :         else if (bTreatAsBitmap)
    5264         398 :             SetBand(iBand + 1,
    5265         796 :                     std::make_unique<GTiffBitmapBand>(this, iBand + 1));
    5266      599011 :         else if (bTreatAsOdd)
    5267         346 :             SetBand(iBand + 1,
    5268         692 :                     std::make_unique<GTiffOddBitsBand>(this, iBand + 1));
    5269             :         else
    5270      598665 :             SetBand(iBand + 1,
    5271     1197330 :                     std::make_unique<GTiffRasterBand>(this, iBand + 1));
    5272             :     }
    5273             : 
    5274       27919 :     if (GetRasterBand(1)->GetRasterDataType() == GDT_Unknown)
    5275             :     {
    5276           1 :         ReportError(CE_Failure, CPLE_NotSupported,
    5277             :                     "Unsupported TIFF configuration: BitsPerSample(=%d) and "
    5278             :                     "SampleType(=%d)",
    5279           1 :                     m_nBitsPerSample, m_nSampleFormat);
    5280           1 :         return CE_Failure;
    5281             :     }
    5282             : 
    5283       27918 :     m_bReadGeoTransform = bReadGeoTransform;
    5284             : 
    5285             :     /* -------------------------------------------------------------------- */
    5286             :     /*      Capture some other potentially interesting information.         */
    5287             :     /* -------------------------------------------------------------------- */
    5288       27918 :     char szWorkMDI[200] = {};
    5289       27918 :     uint16_t nShort = 0;
    5290             : 
    5291       27918 :     const auto *pasTIFFTags = GetTIFFTags();
    5292      418770 :     for (size_t iTag = 0; pasTIFFTags[iTag].pszTagName; ++iTag)
    5293             :     {
    5294      390852 :         if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_STRING)
    5295             :         {
    5296      223344 :             if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &pszText))
    5297         128 :                 m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
    5298             :                                              pszText);
    5299             :         }
    5300      167508 :         else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_FLOAT)
    5301             :         {
    5302       55836 :             float fVal = 0.0;
    5303       55836 :             if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &fVal))
    5304             :             {
    5305         172 :                 CPLsnprintf(szWorkMDI, sizeof(szWorkMDI), "%.8g",
    5306             :                             static_cast<double>(fVal));
    5307         172 :                 m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
    5308             :                                              szWorkMDI);
    5309             :             }
    5310             :         }
    5311      111672 :         else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_SHORT &&
    5312       83754 :                  pasTIFFTags[iTag].nTagVal != TIFFTAG_RESOLUTIONUNIT)
    5313             :         {
    5314       55836 :             if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nShort))
    5315             :             {
    5316           8 :                 snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
    5317           8 :                 m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
    5318             :                                              szWorkMDI);
    5319             :             }
    5320             :         }
    5321       55836 :         else if (pasTIFFTags[iTag].eType == GTIFFTAGTYPE_BYTE_STRING)
    5322             :         {
    5323       27918 :             uint32_t nCount = 0;
    5324       27918 :             if (TIFFGetField(m_hTIFF, pasTIFFTags[iTag].nTagVal, &nCount,
    5325       27918 :                              &pszText))
    5326             :             {
    5327           2 :                 std::string osStr;
    5328           1 :                 osStr.assign(pszText, nCount);
    5329           1 :                 m_oGTiffMDMD.SetMetadataItem(pasTIFFTags[iTag].pszTagName,
    5330             :                                              osStr.c_str());
    5331             :             }
    5332             :         }
    5333             :     }
    5334             : 
    5335       27918 :     if (TIFFGetField(m_hTIFF, TIFFTAG_RESOLUTIONUNIT, &nShort))
    5336             :     {
    5337          88 :         if (nShort == RESUNIT_NONE)
    5338          34 :             snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (unitless)", nShort);
    5339          54 :         else if (nShort == RESUNIT_INCH)
    5340          53 :             snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/inch)", nShort);
    5341           1 :         else if (nShort == RESUNIT_CENTIMETER)
    5342           1 :             snprintf(szWorkMDI, sizeof(szWorkMDI), "%d (pixels/cm)", nShort);
    5343             :         else
    5344           0 :             snprintf(szWorkMDI, sizeof(szWorkMDI), "%d", nShort);
    5345          88 :         m_oGTiffMDMD.SetMetadataItem("TIFFTAG_RESOLUTIONUNIT", szWorkMDI);
    5346             :     }
    5347             : 
    5348       27918 :     int nTagSize = 0;
    5349       27918 :     void *pData = nullptr;
    5350       27918 :     if (TIFFGetField(m_hTIFF, TIFFTAG_XMLPACKET, &nTagSize, &pData))
    5351             :     {
    5352          35 :         char *pszXMP = static_cast<char *>(VSI_MALLOC_VERBOSE(nTagSize + 1));
    5353          35 :         if (pszXMP)
    5354             :         {
    5355          35 :             memcpy(pszXMP, pData, nTagSize);
    5356          35 :             pszXMP[nTagSize] = '\0';
    5357             : 
    5358          35 :             char *apszMDList[2] = {pszXMP, nullptr};
    5359          35 :             m_oGTiffMDMD.SetMetadata(apszMDList, "xml:XMP");
    5360             : 
    5361          35 :             CPLFree(pszXMP);
    5362             :         }
    5363             :     }
    5364             : 
    5365       27918 :     if (m_nCompression != COMPRESSION_NONE)
    5366             :     {
    5367             :         const char *pszCompressionMethodName =
    5368        3820 :             GTIFFGetCompressionMethodName(m_nCompression);
    5369        3820 :         if (pszCompressionMethodName)
    5370             :         {
    5371        3820 :             m_oGTiffMDMD.SetMetadataItem(
    5372             :                 "COMPRESSION", pszCompressionMethodName, "IMAGE_STRUCTURE");
    5373             :         }
    5374             :         else
    5375             :         {
    5376           0 :             CPLString oComp;
    5377           0 :             oComp.Printf("%d", m_nCompression);
    5378           0 :             m_oGTiffMDMD.SetMetadataItem("COMPRESSION", oComp.c_str());
    5379             :         }
    5380             :     }
    5381             : 
    5382       27918 :     if (m_nCompression == COMPRESSION_JPEG &&
    5383         464 :         m_nPhotometric == PHOTOMETRIC_YCBCR)
    5384             :     {
    5385         252 :         m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "YCbCr JPEG",
    5386             :                                      "IMAGE_STRUCTURE");
    5387             :     }
    5388       27666 :     else if (m_nCompression == COMPRESSION_LERC)
    5389             :     {
    5390         317 :         uint32_t nLercParamCount = 0;
    5391         317 :         uint32_t *panLercParams = nullptr;
    5392         317 :         if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_PARAMETERS, &nLercParamCount,
    5393         634 :                          &panLercParams) &&
    5394         317 :             nLercParamCount == 2)
    5395             :         {
    5396         317 :             memcpy(m_anLercAddCompressionAndVersion, panLercParams,
    5397             :                    sizeof(m_anLercAddCompressionAndVersion));
    5398             :         }
    5399             : 
    5400         317 :         uint32_t nAddVersion = LERC_ADD_COMPRESSION_NONE;
    5401         634 :         if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_ADD_COMPRESSION, &nAddVersion) &&
    5402         317 :             nAddVersion != LERC_ADD_COMPRESSION_NONE)
    5403             :         {
    5404         173 :             if (nAddVersion == LERC_ADD_COMPRESSION_DEFLATE)
    5405             :             {
    5406          90 :                 m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "LERC_DEFLATE",
    5407             :                                              "IMAGE_STRUCTURE");
    5408             :             }
    5409          83 :             else if (nAddVersion == LERC_ADD_COMPRESSION_ZSTD)
    5410             :             {
    5411          83 :                 m_oGTiffMDMD.SetMetadataItem("COMPRESSION", "LERC_ZSTD",
    5412             :                                              "IMAGE_STRUCTURE");
    5413             :             }
    5414             :         }
    5415         317 :         uint32_t nLercVersion = LERC_VERSION_2_4;
    5416         317 :         if (TIFFGetField(m_hTIFF, TIFFTAG_LERC_VERSION, &nLercVersion))
    5417             :         {
    5418         317 :             if (nLercVersion == LERC_VERSION_2_4)
    5419             :             {
    5420         317 :                 m_oGTiffMDMD.SetMetadataItem("LERC_VERSION", "2.4",
    5421             :                                              "IMAGE_STRUCTURE");
    5422             :             }
    5423             :             else
    5424             :             {
    5425           0 :                 ReportError(CE_Warning, CPLE_AppDefined,
    5426             :                             "Unknown Lerc version: %d", nLercVersion);
    5427             :             }
    5428             :         }
    5429             :     }
    5430             : 
    5431       27918 :     if (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands != 1)
    5432        3049 :         m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "PIXEL", "IMAGE_STRUCTURE");
    5433             :     else
    5434       24869 :         m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "BAND", "IMAGE_STRUCTURE");
    5435             : 
    5436       27918 :     if ((GetRasterBand(1)->GetRasterDataType() == GDT_UInt8 &&
    5437       21791 :          m_nBitsPerSample != 8) ||
    5438       27424 :         (GetRasterBand(1)->GetRasterDataType() == GDT_UInt16 &&
    5439       56475 :          m_nBitsPerSample != 16) ||
    5440       27337 :         ((GetRasterBand(1)->GetRasterDataType() == GDT_UInt32 ||
    5441       26951 :           GetRasterBand(1)->GetRasterDataType() == GDT_Float32) &&
    5442        1367 :          m_nBitsPerSample != 32))
    5443             :     {
    5444        1372 :         for (int i = 0; i < nBands; ++i)
    5445         758 :             cpl::down_cast<GTiffRasterBand *>(GetRasterBand(i + 1))
    5446         758 :                 ->m_oGTiffMDMD.SetMetadataItem(
    5447             :                     "NBITS",
    5448        1516 :                     CPLString().Printf("%d",
    5449         758 :                                        static_cast<int>(m_nBitsPerSample)),
    5450             :                     "IMAGE_STRUCTURE");
    5451             :     }
    5452             : 
    5453       27918 :     if (bMinIsWhite)
    5454          15 :         m_oGTiffMDMD.SetMetadataItem("MINISWHITE", "YES", "IMAGE_STRUCTURE");
    5455             : 
    5456       27918 :     if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
    5457             :     {
    5458        6734 :         auto psRoot = CPLXMLTreeCloser(CPLParseXMLString(pszText));
    5459             :         const CPLXMLNode *psItem =
    5460        3367 :             psRoot.get() ? CPLGetXMLNode(psRoot.get(), "=GDALMetadata")
    5461        3367 :                          : nullptr;
    5462        3367 :         if (psItem)
    5463        3367 :             psItem = psItem->psChild;
    5464        3367 :         bool bMaxZErrorFound = false;
    5465        3367 :         bool bMaxZErrorOverviewFound = false;
    5466       18452 :         for (; psItem != nullptr; psItem = psItem->psNext)
    5467             :         {
    5468             : 
    5469       15085 :             if (psItem->eType != CXT_Element ||
    5470       15085 :                 !EQUAL(psItem->pszValue, "Item"))
    5471           0 :                 continue;
    5472             : 
    5473       15085 :             const char *pszKey = CPLGetXMLValue(psItem, "name", nullptr);
    5474       15085 :             const char *pszValue = CPLGetXMLValue(psItem, nullptr, nullptr);
    5475       15085 :             int nBand = atoi(CPLGetXMLValue(psItem, "sample", "-1"));
    5476       15085 :             if (nBand < -1 || nBand > nBands - 1)
    5477           0 :                 continue;
    5478       15085 :             nBand++;
    5479       15085 :             const char *pszRole = CPLGetXMLValue(psItem, "role", "");
    5480       15085 :             const char *pszDomain = CPLGetXMLValue(psItem, "domain", "");
    5481             : 
    5482       15085 :             if (nBand > 0 && pszKey &&
    5483        3891 :                 strcmp(pszKey, DEFAULT_RASTER_ATTRIBUTE_TABLE) == 0 &&
    5484          25 :                 strcmp(pszRole, RAT_ROLE) == 0)
    5485             :             {
    5486          25 :                 const CPLXMLNode *psValueNode = psItem->psChild;
    5487         100 :                 while (psValueNode && psValueNode->eType != CXT_Element)
    5488          75 :                     psValueNode = psValueNode->psNext;
    5489          25 :                 if (psValueNode && psValueNode->eType == CXT_Element)
    5490             :                 {
    5491             :                     auto poRAT =
    5492          50 :                         std::make_unique<GDALDefaultRasterAttributeTable>();
    5493          25 :                     if (poRAT->XMLInit(psValueNode, nullptr) == CE_None)
    5494             :                     {
    5495             :                         GTiffRasterBand *poBand =
    5496          25 :                             cpl::down_cast<GTiffRasterBand *>(
    5497             :                                 GetRasterBand(nBand));
    5498          25 :                         if (poBand != nullptr)
    5499             :                         {
    5500          25 :                             poBand->m_poRAT = std::move(poRAT);
    5501          25 :                             poBand->m_bRATSet = true;
    5502             :                         }
    5503             :                     }
    5504             :                 }
    5505             :             }
    5506             : 
    5507       15085 :             if (pszKey == nullptr || pszValue == nullptr)
    5508         312 :                 continue;
    5509       14773 :             if (EQUAL(pszDomain, "IMAGE_STRUCTURE"))
    5510             :             {
    5511         848 :                 if (EQUAL(pszKey, "OVERVIEW_RESAMPLING"))
    5512             :                 {
    5513         104 :                     m_oGTiffMDMD.SetMetadataItem(pszKey, pszValue,
    5514             :                                                  "IMAGE_STRUCTURE");
    5515             :                 }
    5516         744 :                 else if (EQUAL(pszKey, "INTERLEAVE"))
    5517             :                 {
    5518          39 :                     if (EQUAL(pszValue, "TILE"))
    5519             :                     {
    5520          17 :                         m_bTileInterleave = true;
    5521          17 :                         m_oGTiffMDMD.SetMetadataItem("INTERLEAVE", "TILE",
    5522             :                                                      "IMAGE_STRUCTURE");
    5523             :                     }
    5524             :                     else
    5525             :                     {
    5526          22 :                         CPLDebug("GTiff",
    5527             :                                  "Unhandled INTERLEAVE=%s found in "
    5528             :                                  "GDAL_METADATA tag",
    5529             :                                  pszValue);
    5530             :                     }
    5531             :                 }
    5532         705 :                 else if (m_nCompression == COMPRESSION_WEBP &&
    5533          73 :                          EQUAL(pszKey, "COMPRESSION_REVERSIBILITY"))
    5534             :                 {
    5535          13 :                     if (EQUAL(pszValue, "LOSSLESS"))
    5536          13 :                         m_bWebPLossless = true;
    5537           0 :                     else if (EQUAL(pszValue, "LOSSY"))
    5538           0 :                         m_bWebPLossless = false;
    5539             :                 }
    5540         692 :                 else if (m_nCompression == COMPRESSION_WEBP &&
    5541          60 :                          EQUAL(pszKey, "WEBP_LEVEL"))
    5542             :                 {
    5543          60 :                     const int nLevel = atoi(pszValue);
    5544          60 :                     if (nLevel >= 1 && nLevel <= 100)
    5545             :                     {
    5546          60 :                         m_oGTiffMDMD.SetMetadataItem(
    5547             :                             "COMPRESSION_REVERSIBILITY", "LOSSY",
    5548             :                             "IMAGE_STRUCTURE");
    5549          60 :                         m_bWebPLossless = false;
    5550          60 :                         m_nWebPLevel = static_cast<signed char>(nLevel);
    5551          60 :                     }
    5552             :                 }
    5553         632 :                 else if (m_nCompression == COMPRESSION_LERC &&
    5554         196 :                          EQUAL(pszKey, "MAX_Z_ERROR"))
    5555             :                 {
    5556          28 :                     bMaxZErrorFound = true;
    5557          28 :                     m_dfMaxZError = CPLAtof(pszValue);
    5558             :                 }
    5559         604 :                 else if (m_nCompression == COMPRESSION_LERC &&
    5560         168 :                          EQUAL(pszKey, "MAX_Z_ERROR_OVERVIEW"))
    5561             :                 {
    5562           4 :                     bMaxZErrorOverviewFound = true;
    5563           4 :                     m_dfMaxZErrorOverview = CPLAtof(pszValue);
    5564             :                 }
    5565             : #if HAVE_JXL
    5566         600 :                 else if ((m_nCompression == COMPRESSION_JXL ||
    5567         598 :                           m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
    5568         420 :                          EQUAL(pszKey, "COMPRESSION_REVERSIBILITY"))
    5569             :                 {
    5570         169 :                     if (EQUAL(pszValue, "LOSSLESS"))
    5571         169 :                         m_bJXLLossless = true;
    5572           0 :                     else if (EQUAL(pszValue, "LOSSY"))
    5573           0 :                         m_bJXLLossless = false;
    5574             :                 }
    5575         431 :                 else if ((m_nCompression == COMPRESSION_JXL ||
    5576         430 :                           m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
    5577         251 :                          EQUAL(pszKey, "JXL_DISTANCE"))
    5578             :                 {
    5579          39 :                     const double dfVal = CPLAtof(pszValue);
    5580          39 :                     if (dfVal > 0 && dfVal <= 15)
    5581             :                     {
    5582          39 :                         m_oGTiffMDMD.SetMetadataItem(
    5583             :                             "COMPRESSION_REVERSIBILITY", "LOSSY",
    5584             :                             "IMAGE_STRUCTURE");
    5585          39 :                         m_bJXLLossless = false;
    5586          39 :                         m_fJXLDistance = static_cast<float>(dfVal);
    5587          39 :                     }
    5588             :                 }
    5589         392 :                 else if ((m_nCompression == COMPRESSION_JXL ||
    5590         391 :                           m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
    5591         212 :                          EQUAL(pszKey, "JXL_ALPHA_DISTANCE"))
    5592             :                 {
    5593           4 :                     const double dfVal = CPLAtof(pszValue);
    5594           4 :                     if (dfVal > 0 && dfVal <= 15)
    5595             :                     {
    5596           0 :                         m_oGTiffMDMD.SetMetadataItem(
    5597             :                             "COMPRESSION_REVERSIBILITY", "LOSSY",
    5598             :                             "IMAGE_STRUCTURE");
    5599           0 :                         m_fJXLAlphaDistance = static_cast<float>(dfVal);
    5600           4 :                     }
    5601             :                 }
    5602         388 :                 else if ((m_nCompression == COMPRESSION_JXL ||
    5603         387 :                           m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
    5604         208 :                          EQUAL(pszKey, "JXL_EFFORT"))
    5605             :                 {
    5606         208 :                     const int nEffort = atoi(pszValue);
    5607         208 :                     if (nEffort >= 1 && nEffort <= 9)
    5608             :                     {
    5609         208 :                         m_nJXLEffort = nEffort;
    5610         208 :                     }
    5611             :                 }
    5612             : #endif
    5613             :                 else
    5614             :                 {
    5615         180 :                     continue;
    5616             :                 }
    5617             :             }
    5618             : 
    5619       14593 :             bool bIsXMLOrJSON = false;
    5620             : 
    5621       14593 :             if (STARTS_WITH_CI(pszDomain, "xml:") ||
    5622       14591 :                 STARTS_WITH_CI(pszDomain, "json:"))
    5623          22 :                 bIsXMLOrJSON = true;
    5624             : 
    5625             :             // Note: this un-escaping should not normally be done, as the
    5626             :             // deserialization of the tree from XML also does it, so we end up
    5627             :             // width double XML escaping, but keep it for backward
    5628             :             // compatibility.
    5629             :             char *pszUnescapedValue =
    5630       14593 :                 CPLUnescapeString(pszValue, nullptr, CPLES_XML);
    5631       14593 :             if (nBand == 0)
    5632             :             {
    5633       10732 :                 if (bIsXMLOrJSON)
    5634             :                 {
    5635          22 :                     char *apszMD[2] = {pszUnescapedValue, nullptr};
    5636          22 :                     m_oGTiffMDMD.SetMetadata(apszMD, pszDomain);
    5637             :                 }
    5638             :                 else
    5639             :                 {
    5640       10710 :                     m_oGTiffMDMD.SetMetadataItem(pszKey, pszUnescapedValue,
    5641             :                                                  pszDomain);
    5642             :                 }
    5643             :             }
    5644             :             else
    5645             :             {
    5646             :                 GTiffRasterBand *poBand =
    5647        3861 :                     cpl::down_cast<GTiffRasterBand *>(GetRasterBand(nBand));
    5648        3861 :                 if (poBand != nullptr)
    5649             :                 {
    5650        3861 :                     if (EQUAL(pszRole, "scale"))
    5651             :                     {
    5652          40 :                         poBand->m_bHaveOffsetScale = true;
    5653          40 :                         poBand->m_dfScale = CPLAtofM(pszUnescapedValue);
    5654             :                     }
    5655        3821 :                     else if (EQUAL(pszRole, "offset"))
    5656             :                     {
    5657          40 :                         poBand->m_bHaveOffsetScale = true;
    5658          40 :                         poBand->m_dfOffset = CPLAtofM(pszUnescapedValue);
    5659             :                     }
    5660        3781 :                     else if (EQUAL(pszRole, "unittype"))
    5661             :                     {
    5662         309 :                         poBand->m_osUnitType = pszUnescapedValue;
    5663             :                     }
    5664        3472 :                     else if (EQUAL(pszRole, "description"))
    5665             :                     {
    5666          73 :                         poBand->m_osDescription = pszUnescapedValue;
    5667             :                     }
    5668        3399 :                     else if (EQUAL(pszRole, "colorinterp"))
    5669             :                     {
    5670         644 :                         if (EQUAL(pszUnescapedValue, "undefined"))
    5671         192 :                             poBand->m_eBandInterp = GCI_Undefined;
    5672             :                         else
    5673             :                         {
    5674         452 :                             poBand->m_eBandInterp =
    5675         452 :                                 GDALGetColorInterpretationByName(
    5676             :                                     pszUnescapedValue);
    5677         452 :                             if (poBand->m_eBandInterp == GCI_Undefined)
    5678             :                             {
    5679           1 :                                 poBand->m_oGTiffMDMD.SetMetadataItem(
    5680             :                                     "COLOR_INTERPRETATION", pszUnescapedValue);
    5681             :                             }
    5682             :                         }
    5683             :                     }
    5684             :                     else
    5685             :                     {
    5686        2755 :                         if (bIsXMLOrJSON)
    5687             :                         {
    5688           0 :                             char *apszMD[2] = {pszUnescapedValue, nullptr};
    5689           0 :                             poBand->m_oGTiffMDMD.SetMetadata(apszMD, pszDomain);
    5690             :                         }
    5691             :                         else
    5692             :                         {
    5693        2755 :                             poBand->m_oGTiffMDMD.SetMetadataItem(
    5694             :                                 pszKey, pszUnescapedValue, pszDomain);
    5695             :                         }
    5696             :                     }
    5697             :                 }
    5698             :             }
    5699       14593 :             CPLFree(pszUnescapedValue);
    5700             :         }
    5701             : 
    5702        3367 :         if (bMaxZErrorFound && !bMaxZErrorOverviewFound)
    5703             :         {
    5704          27 :             m_dfMaxZErrorOverview = m_dfMaxZError;
    5705             :         }
    5706             :     }
    5707             : 
    5708       27918 :     if (m_bStreamingIn)
    5709             :     {
    5710           7 :         toff_t *panOffsets = nullptr;
    5711           7 :         TIFFGetField(m_hTIFF,
    5712           7 :                      TIFFIsTiled(m_hTIFF) ? TIFFTAG_TILEOFFSETS
    5713             :                                           : TIFFTAG_STRIPOFFSETS,
    5714             :                      &panOffsets);
    5715           7 :         if (panOffsets)
    5716             :         {
    5717           7 :             int nBlockCount = TIFFIsTiled(m_hTIFF)
    5718           7 :                                   ? TIFFNumberOfTiles(m_hTIFF)
    5719           6 :                                   : TIFFNumberOfStrips(m_hTIFF);
    5720        1437 :             for (int i = 1; i < nBlockCount; ++i)
    5721             :             {
    5722        1431 :                 if (panOffsets[i] < panOffsets[i - 1])
    5723             :                 {
    5724           1 :                     m_oGTiffMDMD.SetMetadataItem("UNORDERED_BLOCKS", "YES",
    5725             :                                                  "TIFF");
    5726           1 :                     CPLDebug("GTIFF",
    5727             :                              "Offset of block %d is lower than previous block. "
    5728             :                              "Reader must be careful",
    5729             :                              i);
    5730           1 :                     break;
    5731             :                 }
    5732             :             }
    5733             :         }
    5734             :     }
    5735             : 
    5736       27918 :     if (m_nCompression == COMPRESSION_JPEG)
    5737             :     {
    5738         464 :         bool bHasQuantizationTable = false;
    5739         464 :         bool bHasHuffmanTable = false;
    5740             :         int nQuality =
    5741         464 :             GuessJPEGQuality(bHasQuantizationTable, bHasHuffmanTable);
    5742         464 :         if (nQuality > 0)
    5743             :         {
    5744         440 :             m_oGTiffMDMD.SetMetadataItem(
    5745             :                 "JPEG_QUALITY", CPLSPrintf("%d", nQuality), "IMAGE_STRUCTURE");
    5746         440 :             int nJpegTablesMode = JPEGTABLESMODE_QUANT;
    5747         440 :             if (bHasHuffmanTable)
    5748             :             {
    5749          91 :                 nJpegTablesMode |= JPEGTABLESMODE_HUFF;
    5750             :             }
    5751         440 :             m_oGTiffMDMD.SetMetadataItem("JPEGTABLESMODE",
    5752             :                                          CPLSPrintf("%d", nJpegTablesMode),
    5753             :                                          "IMAGE_STRUCTURE");
    5754             :         }
    5755         464 :         if (eAccess == GA_Update)
    5756             :         {
    5757         161 :             SetJPEGQualityAndTablesModeFromFile(nQuality, bHasQuantizationTable,
    5758             :                                                 bHasHuffmanTable);
    5759             :         }
    5760             :     }
    5761       31112 :     else if (eAccess == GA_Update &&
    5762        3658 :              m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
    5763             :                                           "IMAGE_STRUCTURE") == nullptr)
    5764             :     {
    5765        3551 :         if (m_nCompression == COMPRESSION_WEBP)
    5766             :         {
    5767             :             const char *pszReversibility =
    5768          37 :                 GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
    5769          37 :             if (pszReversibility && strstr(pszReversibility, "LOSSLESS"))
    5770             :             {
    5771           2 :                 m_bWebPLossless = true;
    5772             :             }
    5773          35 :             else if (pszReversibility && strstr(pszReversibility, "LOSSY"))
    5774             :             {
    5775           8 :                 m_bWebPLossless = false;
    5776             :             }
    5777             :         }
    5778             : #ifdef HAVE_JXL
    5779        3514 :         else if (m_nCompression == COMPRESSION_JXL ||
    5780        3514 :                  m_nCompression == COMPRESSION_JXL_DNG_1_7)
    5781             :         {
    5782             :             const char *pszReversibility =
    5783          16 :                 GetMetadataItem("COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
    5784          16 :             if (pszReversibility && strstr(pszReversibility, "LOSSLESS"))
    5785             :             {
    5786           2 :                 m_bJXLLossless = true;
    5787             :             }
    5788          14 :             else if (pszReversibility && strstr(pszReversibility, "LOSSY"))
    5789             :             {
    5790           6 :                 m_bJXLLossless = false;
    5791             :             }
    5792             :         }
    5793             : #endif
    5794             :     }
    5795             : 
    5796       27918 :     if (GTIFFSupportsPredictor(m_nCompression))
    5797             :     {
    5798        2184 :         uint16_t nPredictor = 0;
    5799        4336 :         if (TIFFGetField(m_hTIFF, TIFFTAG_PREDICTOR, &nPredictor) &&
    5800        2152 :             nPredictor > 1)
    5801             :         {
    5802          96 :             m_oGTiffMDMD.SetMetadataItem(
    5803             :                 "PREDICTOR", CPLSPrintf("%d", nPredictor), "IMAGE_STRUCTURE");
    5804             :         }
    5805             :     }
    5806             : 
    5807       27918 :     CPLAssert(m_bReadGeoTransform == bReadGeoTransform);
    5808       27918 :     CPLAssert(!m_bMetadataChanged);
    5809       27918 :     m_bMetadataChanged = false;
    5810             : 
    5811       27918 :     return CE_None;
    5812             : }
    5813             : 
    5814             : /************************************************************************/
    5815             : /*                          GetSiblingFiles()                           */
    5816             : /************************************************************************/
    5817             : 
    5818       52301 : CSLConstList GTiffDataset::GetSiblingFiles()
    5819             : {
    5820       52301 :     if (m_poBaseDS != nullptr)
    5821           0 :         return nullptr;
    5822             : 
    5823       52301 :     if (m_bHasGotSiblingFiles)
    5824             :     {
    5825       35339 :         return oOvManager.GetSiblingFiles();
    5826             :     }
    5827             : 
    5828       16962 :     m_bHasGotSiblingFiles = true;
    5829             :     const int nMaxFiles =
    5830       16962 :         atoi(CPLGetConfigOption("GDAL_READDIR_LIMIT_ON_OPEN", "1000"));
    5831       33924 :     const std::string osDirname = CPLGetDirnameSafe(m_osFilename.c_str());
    5832       16962 :     CPLDebugOnly("GTiff", "Doing '%s' file listing", osDirname.c_str());
    5833       33924 :     CPLStringList aosSiblingFiles(VSIReadDirEx(osDirname.c_str(), nMaxFiles));
    5834       16962 :     if (nMaxFiles > 0 && aosSiblingFiles.size() > nMaxFiles)
    5835             :     {
    5836           1 :         CPLDebug("GTiff", "GDAL_READDIR_LIMIT_ON_OPEN reached on %s",
    5837             :                  osDirname.c_str());
    5838           1 :         aosSiblingFiles.clear();
    5839             :     }
    5840       16962 :     oOvManager.TransferSiblingFiles(aosSiblingFiles.StealList());
    5841             : 
    5842       16962 :     return oOvManager.GetSiblingFiles();
    5843             : }
    5844             : 
    5845             : /************************************************************************/
    5846             : /*              IdentifyAuthorizedGeoreferencingSources()               */
    5847             : /************************************************************************/
    5848             : 
    5849       30238 : void GTiffDataset::IdentifyAuthorizedGeoreferencingSources()
    5850             : {
    5851       30238 :     if (m_bHasIdentifiedAuthorizedGeoreferencingSources)
    5852       13094 :         return;
    5853       17144 :     m_bHasIdentifiedAuthorizedGeoreferencingSources = true;
    5854             :     CPLString osGeorefSources = CSLFetchNameValueDef(
    5855       17144 :         papszOpenOptions, "GEOREF_SOURCES",
    5856             :         CPLGetConfigOption("GDAL_GEOREF_SOURCES",
    5857       34288 :                            "PAM,INTERNAL,TABFILE,WORLDFILE,XML"));
    5858       17144 :     char **papszTokens = CSLTokenizeString2(osGeorefSources, ",", 0);
    5859       17144 :     m_nPAMGeorefSrcIndex =
    5860       17144 :         static_cast<signed char>(CSLFindString(papszTokens, "PAM"));
    5861       17144 :     m_nINTERNALGeorefSrcIndex =
    5862       17144 :         static_cast<signed char>(CSLFindString(papszTokens, "INTERNAL"));
    5863       17144 :     m_nTABFILEGeorefSrcIndex =
    5864       17144 :         static_cast<signed char>(CSLFindString(papszTokens, "TABFILE"));
    5865       17144 :     m_nWORLDFILEGeorefSrcIndex =
    5866       17144 :         static_cast<signed char>(CSLFindString(papszTokens, "WORLDFILE"));
    5867       17144 :     m_nXMLGeorefSrcIndex =
    5868       17144 :         static_cast<signed char>(CSLFindString(papszTokens, "XML"));
    5869       17144 :     CSLDestroy(papszTokens);
    5870             : }
    5871             : 
    5872             : /************************************************************************/
    5873             : /*                  LoadGeoreferencingAndPamIfNeeded()                  */
    5874             : /************************************************************************/
    5875             : 
    5876     3214200 : void GTiffDataset::LoadGeoreferencingAndPamIfNeeded()
    5877             : 
    5878             : {
    5879     3214200 :     if (!m_bReadGeoTransform && !m_bLoadPam)
    5880     3197090 :         return;
    5881       17112 :     if (m_poBaseDS != nullptr)
    5882           0 :         return;
    5883             : 
    5884       17112 :     IdentifyAuthorizedGeoreferencingSources();
    5885             : 
    5886             :     /* -------------------------------------------------------------------- */
    5887             :     /*      Get the transform or gcps from the GeoTIFF file.                */
    5888             :     /* -------------------------------------------------------------------- */
    5889       17112 :     if (m_bReadGeoTransform)
    5890             :     {
    5891       17112 :         m_bReadGeoTransform = false;
    5892             : 
    5893       17112 :         char *pszTabWKT = nullptr;
    5894       17112 :         double *padfTiePoints = nullptr;
    5895       17112 :         double *padfScale = nullptr;
    5896       17112 :         double *padfMatrix = nullptr;
    5897       17112 :         uint16_t nCount = 0;
    5898       17112 :         bool bPixelIsPoint = false;
    5899       17112 :         unsigned short nRasterType = 0;
    5900       17112 :         bool bPointGeoIgnore = false;
    5901             : 
    5902       34224 :         std::set<signed char> aoSetPriorities;
    5903       17112 :         if (m_nINTERNALGeorefSrcIndex >= 0)
    5904       17086 :             aoSetPriorities.insert(m_nINTERNALGeorefSrcIndex);
    5905       17112 :         if (m_nTABFILEGeorefSrcIndex >= 0)
    5906       17060 :             aoSetPriorities.insert(m_nTABFILEGeorefSrcIndex);
    5907       17112 :         if (m_nWORLDFILEGeorefSrcIndex >= 0)
    5908       17076 :             aoSetPriorities.insert(m_nWORLDFILEGeorefSrcIndex);
    5909       34764 :         for (const auto nIndex : aoSetPriorities)
    5910             :         {
    5911       28872 :             if (m_nINTERNALGeorefSrcIndex == nIndex)
    5912             :             {
    5913             :                 GTIF *psGTIF =
    5914       17078 :                     GTiffDataset::GTIFNew(m_hTIFF);  // How expensive this is?
    5915             : 
    5916       17078 :                 if (psGTIF)
    5917             :                 {
    5918       17078 :                     if (GDALGTIFKeyGetSHORT(psGTIF, GTRasterTypeGeoKey,
    5919       27325 :                                             &nRasterType, 0, 1) == 1 &&
    5920       10247 :                         nRasterType == static_cast<short>(RasterPixelIsPoint))
    5921             :                     {
    5922         283 :                         bPixelIsPoint = true;
    5923         283 :                         bPointGeoIgnore = CPLTestBool(CPLGetConfigOption(
    5924             :                             "GTIFF_POINT_GEO_IGNORE", "FALSE"));
    5925             :                     }
    5926             : 
    5927       17078 :                     GTIFFree(psGTIF);
    5928             :                 }
    5929             : 
    5930       17078 :                 m_gt = GDALGeoTransform();
    5931             : 
    5932       17078 :                 uint16_t nCountScale = 0;
    5933       17078 :                 if (TIFFGetField(m_hTIFF, TIFFTAG_GEOPIXELSCALE, &nCountScale,
    5934       11008 :                                  &padfScale) &&
    5935       28086 :                     nCountScale >= 2 && padfScale[0] != 0.0 &&
    5936       11008 :                     padfScale[1] != 0.0)
    5937             :                 {
    5938       11008 :                     m_gt.xscale = padfScale[0];
    5939       11008 :                     if (padfScale[1] < 0)
    5940             :                     {
    5941           3 :                         const char *pszOptionVal = CPLGetConfigOption(
    5942             :                             "GTIFF_HONOUR_NEGATIVE_SCALEY", nullptr);
    5943           3 :                         if (pszOptionVal == nullptr)
    5944             :                         {
    5945           1 :                             ReportError(
    5946             :                                 CE_Warning, CPLE_AppDefined,
    5947             :                                 "File with negative value for ScaleY in "
    5948             :                                 "GeoPixelScale tag. This is rather "
    5949             :                                 "unusual. GDAL, contrary to the GeoTIFF "
    5950             :                                 "specification, assumes that the file "
    5951             :                                 "was intended to be north-up, and will "
    5952             :                                 "treat this file as if ScaleY was "
    5953             :                                 "positive. You may override this behavior "
    5954             :                                 "by setting the GTIFF_HONOUR_NEGATIVE_SCALEY "
    5955             :                                 "configuration option to YES");
    5956           1 :                             m_gt.yscale = padfScale[1];
    5957             :                         }
    5958           2 :                         else if (CPLTestBool(pszOptionVal))
    5959             :                         {
    5960           1 :                             m_gt.yscale = -padfScale[1];
    5961             :                         }
    5962             :                         else
    5963             :                         {
    5964           1 :                             m_gt.yscale = padfScale[1];
    5965             :                         }
    5966             :                     }
    5967             :                     else
    5968             :                     {
    5969       11005 :                         m_gt.yscale = -padfScale[1];
    5970             :                     }
    5971             : 
    5972       11008 :                     if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
    5973       22016 :                                      &padfTiePoints) &&
    5974       11008 :                         nCount >= 6)
    5975             :                     {
    5976       11008 :                         m_gt.xorig =
    5977       11008 :                             padfTiePoints[3] - padfTiePoints[0] * m_gt.xscale;
    5978       11008 :                         m_gt.yorig =
    5979       11008 :                             padfTiePoints[4] - padfTiePoints[1] * m_gt.yscale;
    5980             : 
    5981       11008 :                         if (bPixelIsPoint && !bPointGeoIgnore)
    5982             :                         {
    5983         242 :                             m_gt.xorig -= (m_gt.xscale * 0.5 + m_gt.xrot * 0.5);
    5984         242 :                             m_gt.yorig -= (m_gt.yrot * 0.5 + m_gt.yscale * 0.5);
    5985             :                         }
    5986             : 
    5987       11008 :                         m_bGeoTransformValid = true;
    5988       11008 :                         m_nGeoTransformGeorefSrcIndex = nIndex;
    5989             : 
    5990       18328 :                         if (nCountScale >= 3 && GetRasterCount() == 1 &&
    5991        7320 :                             (padfScale[2] != 0.0 || padfTiePoints[2] != 0.0 ||
    5992        7294 :                              padfTiePoints[5] != 0.0))
    5993             :                         {
    5994          28 :                             LookForProjection();
    5995          28 :                             if (!m_oSRS.IsEmpty() && m_oSRS.IsVertical())
    5996             :                             {
    5997             :                                 /* modelTiePointTag = (pixel, line, z0, X, Y,
    5998             :                                  * Z0) */
    5999             :                                 /* thus Z(some_point) = (z(some_point) - z0) *
    6000             :                                  * scaleZ + Z0 */
    6001             :                                 /* equivalently written as */
    6002             :                                 /* Z(some_point) = z(some_point) * scaleZ +
    6003             :                                  * offsetZ with */
    6004             :                                 /* offsetZ = - z0 * scaleZ + Z0 */
    6005          18 :                                 double dfScale = padfScale[2];
    6006          18 :                                 double dfOffset = -padfTiePoints[2] * dfScale +
    6007          18 :                                                   padfTiePoints[5];
    6008             :                                 GTiffRasterBand *poBand =
    6009          18 :                                     cpl::down_cast<GTiffRasterBand *>(
    6010             :                                         GetRasterBand(1));
    6011          18 :                                 poBand->m_bHaveOffsetScale = true;
    6012          18 :                                 poBand->m_dfScale = dfScale;
    6013          18 :                                 poBand->m_dfOffset = dfOffset;
    6014             :                             }
    6015             :                         }
    6016             :                     }
    6017             :                 }
    6018             : 
    6019        6070 :                 else if (TIFFGetField(m_hTIFF, TIFFTAG_GEOTRANSMATRIX, &nCount,
    6020        6231 :                                       &padfMatrix) &&
    6021         161 :                          nCount == 16)
    6022             :                 {
    6023         161 :                     m_gt.xorig = padfMatrix[3];
    6024         161 :                     m_gt.xscale = padfMatrix[0];
    6025         161 :                     m_gt.xrot = padfMatrix[1];
    6026         161 :                     m_gt.yorig = padfMatrix[7];
    6027         161 :                     m_gt.yrot = padfMatrix[4];
    6028         161 :                     m_gt.yscale = padfMatrix[5];
    6029             : 
    6030         161 :                     if (bPixelIsPoint && !bPointGeoIgnore)
    6031             :                     {
    6032          10 :                         m_gt.xorig -= m_gt.xscale * 0.5 + m_gt.xrot * 0.5;
    6033          10 :                         m_gt.yorig -= m_gt.yrot * 0.5 + m_gt.yscale * 0.5;
    6034             :                     }
    6035             : 
    6036         161 :                     m_bGeoTransformValid = true;
    6037         161 :                     m_nGeoTransformGeorefSrcIndex = nIndex;
    6038             :                 }
    6039       17078 :                 if (m_bGeoTransformValid)
    6040       11169 :                     break;
    6041             :             }
    6042             : 
    6043             :             /* --------------------------------------------------------------------
    6044             :              */
    6045             :             /*      Otherwise try looking for a .tab, .tfw, .tifw or .wld file.
    6046             :              */
    6047             :             /* --------------------------------------------------------------------
    6048             :              */
    6049       17703 :             if (m_nTABFILEGeorefSrcIndex == nIndex)
    6050             :             {
    6051        5893 :                 char *pszGeorefFilename = nullptr;
    6052             : 
    6053        5893 :                 CSLConstList papszSiblingFiles = GetSiblingFiles();
    6054             : 
    6055             :                 // Begin with .tab since it can also have projection info.
    6056        5893 :                 int nGCPCount = 0;
    6057        5893 :                 GDAL_GCP *pasGCPList = nullptr;
    6058        5893 :                 const int bTabFileOK = GDALReadTabFile2(
    6059             :                     m_osFilename.c_str(), m_gt.data(), &pszTabWKT, &nGCPCount,
    6060             :                     &pasGCPList, papszSiblingFiles, &pszGeorefFilename);
    6061             : 
    6062        5893 :                 if (bTabFileOK)
    6063             :                 {
    6064          14 :                     m_nGeoTransformGeorefSrcIndex = nIndex;
    6065             :                     // if( pszTabWKT )
    6066             :                     // {
    6067             :                     //     m_nProjectionGeorefSrcIndex = nIndex;
    6068             :                     // }
    6069          14 :                     m_aoGCPs = gdal::GCP::fromC(pasGCPList, nGCPCount);
    6070          14 :                     if (m_aoGCPs.empty())
    6071             :                     {
    6072          14 :                         m_bGeoTransformValid = true;
    6073             :                     }
    6074             :                 }
    6075             : 
    6076        5893 :                 if (nGCPCount)
    6077             :                 {
    6078           0 :                     GDALDeinitGCPs(nGCPCount, pasGCPList);
    6079           0 :                     CPLFree(pasGCPList);
    6080             :                 }
    6081             : 
    6082        5893 :                 if (pszGeorefFilename)
    6083             :                 {
    6084          14 :                     CPLFree(m_pszGeorefFilename);
    6085          14 :                     m_pszGeorefFilename = pszGeorefFilename;
    6086          14 :                     pszGeorefFilename = nullptr;
    6087             :                 }
    6088        5893 :                 if (m_bGeoTransformValid)
    6089          14 :                     break;
    6090             :             }
    6091             : 
    6092       17689 :             if (m_nWORLDFILEGeorefSrcIndex == nIndex)
    6093             :             {
    6094        5901 :                 char *pszGeorefFilename = nullptr;
    6095             : 
    6096        5901 :                 CSLConstList papszSiblingFiles = GetSiblingFiles();
    6097             : 
    6098        5901 :                 m_bGeoTransformValid = CPL_TO_BOOL(
    6099        5901 :                     GDALReadWorldFile2(m_osFilename.c_str(), nullptr, m_gt,
    6100             :                                        papszSiblingFiles, &pszGeorefFilename));
    6101             : 
    6102        5901 :                 if (!m_bGeoTransformValid)
    6103             :                 {
    6104        5869 :                     m_bGeoTransformValid = CPL_TO_BOOL(GDALReadWorldFile2(
    6105        5869 :                         m_osFilename.c_str(), "wld", m_gt, papszSiblingFiles,
    6106             :                         &pszGeorefFilename));
    6107             :                 }
    6108        5901 :                 if (m_bGeoTransformValid)
    6109          37 :                     m_nGeoTransformGeorefSrcIndex = nIndex;
    6110             : 
    6111        5901 :                 if (pszGeorefFilename)
    6112             :                 {
    6113          37 :                     CPLFree(m_pszGeorefFilename);
    6114          37 :                     m_pszGeorefFilename = pszGeorefFilename;
    6115          37 :                     pszGeorefFilename = nullptr;
    6116             :                 }
    6117        5901 :                 if (m_bGeoTransformValid)
    6118          37 :                     break;
    6119             :             }
    6120             :         }
    6121             : 
    6122             :         /* --------------------------------------------------------------------
    6123             :          */
    6124             :         /*      Check for GCPs. */
    6125             :         /* --------------------------------------------------------------------
    6126             :          */
    6127       51310 :         if (m_nINTERNALGeorefSrcIndex >= 0 &&
    6128       17086 :             TIFFGetField(m_hTIFF, TIFFTAG_GEOTIEPOINTS, &nCount,
    6129       34198 :                          &padfTiePoints) &&
    6130       11145 :             !m_bGeoTransformValid)
    6131             :         {
    6132         137 :             m_aoGCPs.clear();
    6133         137 :             const int nNewGCPCount = nCount / 6;
    6134         645 :             for (int iGCP = 0; iGCP < nNewGCPCount; ++iGCP)
    6135             :             {
    6136           0 :                 m_aoGCPs.emplace_back(CPLSPrintf("%d", iGCP + 1), "",
    6137         508 :                                       /* pixel = */ padfTiePoints[iGCP * 6 + 0],
    6138         508 :                                       /* line = */ padfTiePoints[iGCP * 6 + 1],
    6139         508 :                                       /* X = */ padfTiePoints[iGCP * 6 + 3],
    6140         508 :                                       /* Y = */ padfTiePoints[iGCP * 6 + 4],
    6141         508 :                                       /* Z = */ padfTiePoints[iGCP * 6 + 5]);
    6142             : 
    6143         508 :                 if (bPixelIsPoint && !bPointGeoIgnore)
    6144             :                 {
    6145          48 :                     m_aoGCPs.back().Pixel() += 0.5;
    6146          48 :                     m_aoGCPs.back().Line() += 0.5;
    6147             :                 }
    6148             :             }
    6149         137 :             m_nGeoTransformGeorefSrcIndex = m_nINTERNALGeorefSrcIndex;
    6150             :         }
    6151             : 
    6152             :         /* --------------------------------------------------------------------
    6153             :          */
    6154             :         /*      Did we find a tab file?  If so we will use its coordinate */
    6155             :         /*      system and give it precedence. */
    6156             :         /* --------------------------------------------------------------------
    6157             :          */
    6158       17112 :         if (pszTabWKT != nullptr && m_oSRS.IsEmpty())
    6159             :         {
    6160          14 :             m_oSRS.importFromWkt(pszTabWKT);
    6161          14 :             m_bLookedForProjection = true;
    6162             :         }
    6163             : 
    6164       17112 :         CPLFree(pszTabWKT);
    6165             :     }
    6166             : 
    6167       17112 :     if (m_bLoadPam && m_nPAMGeorefSrcIndex >= 0)
    6168             :     {
    6169             :         /* --------------------------------------------------------------------
    6170             :          */
    6171             :         /*      Initialize any PAM information. */
    6172             :         /* --------------------------------------------------------------------
    6173             :          */
    6174       14967 :         CPLAssert(!m_bColorProfileMetadataChanged);
    6175       14967 :         CPLAssert(!m_bMetadataChanged);
    6176       14967 :         CPLAssert(!m_bGeoTIFFInfoChanged);
    6177       14967 :         CPLAssert(!m_bNoDataChanged);
    6178             : 
    6179             :         // We must absolutely unset m_bLoadPam now, otherwise calling
    6180             :         // GetFileList() on a .tif with a .aux will result in an (almost)
    6181             :         // endless sequence of calls.
    6182       14967 :         m_bLoadPam = false;
    6183             : 
    6184       14967 :         TryLoadXML(GetSiblingFiles());
    6185       14967 :         ApplyPamInfo();
    6186             : 
    6187       14967 :         m_bColorProfileMetadataChanged = false;
    6188       14967 :         m_bMetadataChanged = false;
    6189       14967 :         m_bGeoTIFFInfoChanged = false;
    6190       14967 :         m_bNoDataChanged = false;
    6191             :     }
    6192       17112 :     m_bLoadPam = false;
    6193             : }
    6194             : 
    6195             : /************************************************************************/
    6196             : /*                           GetSpatialRef()                            */
    6197             : /************************************************************************/
    6198             : 
    6199       21502 : const OGRSpatialReference *GTiffDataset::GetSpatialRef() const
    6200             : 
    6201             : {
    6202       21502 :     const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
    6203       21502 :     if (m_aoGCPs.empty())
    6204             :     {
    6205       20973 :         const_cast<GTiffDataset *>(this)->LookForProjection();
    6206             :     }
    6207             : 
    6208       21502 :     return m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
    6209             : }
    6210             : 
    6211             : /************************************************************************/
    6212             : /*                          GetGeoTransform()                           */
    6213             : /************************************************************************/
    6214             : 
    6215      320521 : CPLErr GTiffDataset::GetGeoTransform(GDALGeoTransform &gt) const
    6216             : 
    6217             : {
    6218      320521 :     const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
    6219             : 
    6220      320521 :     gt = m_gt;
    6221             : 
    6222      320521 :     if (!m_bGeoTransformValid)
    6223      304037 :         return CE_Failure;
    6224             : 
    6225             :     // Same logic as in the .gtx driver, for the benefit of
    6226             :     // GDALOpenVerticalShiftGrid() when used with PROJ-data's US geoids.
    6227       16484 :     if (CPLFetchBool(papszOpenOptions, "SHIFT_ORIGIN_IN_MINUS_180_PLUS_180",
    6228             :                      false))
    6229             :     {
    6230           0 :         if (gt.xorig < -180.0 - gt.xscale)
    6231           0 :             gt.xorig += 360.0;
    6232           0 :         else if (gt.xorig > 180.0)
    6233           0 :             gt.xorig -= 360.0;
    6234             :     }
    6235             : 
    6236       16484 :     return CE_None;
    6237             : }
    6238             : 
    6239             : /************************************************************************/
    6240             : /*                            GetGCPCount()                             */
    6241             : /************************************************************************/
    6242             : 
    6243        7798 : int GTiffDataset::GetGCPCount()
    6244             : 
    6245             : {
    6246        7798 :     LoadGeoreferencingAndPamIfNeeded();
    6247             : 
    6248        7798 :     return static_cast<int>(m_aoGCPs.size());
    6249             : }
    6250             : 
    6251             : /************************************************************************/
    6252             : /*                          GetGCPSpatialRef()                          */
    6253             : /************************************************************************/
    6254             : 
    6255         636 : const OGRSpatialReference *GTiffDataset::GetGCPSpatialRef() const
    6256             : 
    6257             : {
    6258         636 :     const_cast<GTiffDataset *>(this)->LoadGeoreferencingAndPamIfNeeded();
    6259             : 
    6260         636 :     if (!m_aoGCPs.empty())
    6261             :     {
    6262         157 :         const_cast<GTiffDataset *>(this)->LookForProjection();
    6263             :     }
    6264         636 :     return !m_aoGCPs.empty() && !m_oSRS.IsEmpty() ? &m_oSRS : nullptr;
    6265             : }
    6266             : 
    6267             : /************************************************************************/
    6268             : /*                              GetGCPs()                               */
    6269             : /************************************************************************/
    6270             : 
    6271         493 : const GDAL_GCP *GTiffDataset::GetGCPs()
    6272             : 
    6273             : {
    6274         493 :     LoadGeoreferencingAndPamIfNeeded();
    6275             : 
    6276         493 :     return gdal::GCP::c_ptr(m_aoGCPs);
    6277             : }
    6278             : 
    6279             : /************************************************************************/
    6280             : /*                       GetMetadataDomainList()                        */
    6281             : /************************************************************************/
    6282             : 
    6283          33 : char **GTiffDataset::GetMetadataDomainList()
    6284             : {
    6285          33 :     LoadGeoreferencingAndPamIfNeeded();
    6286             : 
    6287          33 :     char **papszDomainList = CSLDuplicate(m_oGTiffMDMD.GetDomainList());
    6288          33 :     char **papszBaseList = GDALDataset::GetMetadataDomainList();
    6289             : 
    6290          33 :     const int nbBaseDomains = CSLCount(papszBaseList);
    6291             : 
    6292          66 :     for (int domainId = 0; domainId < nbBaseDomains; ++domainId)
    6293             :     {
    6294          33 :         if (CSLFindString(papszDomainList, papszBaseList[domainId]) < 0)
    6295             :         {
    6296             :             papszDomainList =
    6297          33 :                 CSLAddString(papszDomainList, papszBaseList[domainId]);
    6298             :         }
    6299             :     }
    6300             : 
    6301          33 :     CSLDestroy(papszBaseList);
    6302             : 
    6303          33 :     return BuildMetadataDomainList(papszDomainList, TRUE, "",
    6304             :                                    "ProxyOverviewRequest", MD_DOMAIN_RPC,
    6305             :                                    MD_DOMAIN_IMD, "SUBDATASETS", "EXIF",
    6306          33 :                                    "xml:XMP", "COLOR_PROFILE", nullptr);
    6307             : }
    6308             : 
    6309             : /************************************************************************/
    6310             : /*                            GetMetadata()                             */
    6311             : /************************************************************************/
    6312             : 
    6313       37078 : CSLConstList GTiffDataset::GetMetadata(const char *pszDomain)
    6314             : 
    6315             : {
    6316       37078 :     if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
    6317             :     {
    6318         141 :         GTiffDataset::GetMetadataItem("COMPRESSION_REVERSIBILITY", pszDomain);
    6319         141 :         GTiffDataset::GetMetadataItem("LAYOUT", pszDomain);
    6320             :     }
    6321             :     else
    6322             :     {
    6323       36937 :         LoadGeoreferencingAndPamIfNeeded();
    6324             :     }
    6325             : 
    6326       37078 :     if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
    6327          33 :         return GDALPamDataset::GetMetadata(pszDomain);
    6328             : 
    6329       37045 :     if (pszDomain != nullptr && EQUAL(pszDomain, "DERIVED_SUBDATASETS"))
    6330             :     {
    6331           6 :         return GDALDataset::GetMetadata(pszDomain);
    6332             :     }
    6333             : 
    6334       37039 :     else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
    6335       23445 :                                       EQUAL(pszDomain, MD_DOMAIN_IMD) ||
    6336       16784 :                                       EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
    6337       19550 :         LoadMetadata();
    6338             : 
    6339       17489 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
    6340        1323 :         ScanDirectories();
    6341             : 
    6342       16166 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
    6343          58 :         LoadEXIFMetadata();
    6344             : 
    6345       16108 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
    6346          48 :         LoadICCProfile();
    6347             : 
    6348       16060 :     else if (pszDomain == nullptr || EQUAL(pszDomain, ""))
    6349        8236 :         LoadMDAreaOrPoint();  // To set GDALMD_AREA_OR_POINT.
    6350             : 
    6351       37039 :     return m_oGTiffMDMD.GetMetadata(pszDomain);
    6352             : }
    6353             : 
    6354             : /************************************************************************/
    6355             : /*                          GetMetadataItem()                           */
    6356             : /************************************************************************/
    6357             : 
    6358      151267 : const char *GTiffDataset::GetMetadataItem(const char *pszName,
    6359             :                                           const char *pszDomain)
    6360             : 
    6361             : {
    6362      151267 :     if (pszDomain != nullptr && EQUAL(pszDomain, "IMAGE_STRUCTURE"))
    6363             :     {
    6364      218742 :         if ((m_nCompression == COMPRESSION_WEBP ||
    6365       71526 :              m_nCompression == COMPRESSION_JXL ||
    6366       71525 :              m_nCompression == COMPRESSION_JXL_DNG_1_7) &&
    6367      145211 :             EQUAL(pszName, "COMPRESSION_REVERSIBILITY") &&
    6368          77 :             m_oGTiffMDMD.GetMetadataItem("COMPRESSION_REVERSIBILITY",
    6369             :                                          "IMAGE_STRUCTURE") == nullptr)
    6370             :         {
    6371          60 :             const char *pszDriverName =
    6372          60 :                 m_nCompression == COMPRESSION_WEBP ? "WEBP" : "JPEGXL";
    6373          60 :             auto poTileDriver = GDALGetDriverByName(pszDriverName);
    6374          60 :             if (poTileDriver)
    6375             :             {
    6376          60 :                 vsi_l_offset nOffset = 0;
    6377          60 :                 vsi_l_offset nSize = 0;
    6378          60 :                 CPL_IGNORE_RET_VAL(
    6379          60 :                     IsBlockAvailable(0, &nOffset, &nSize, nullptr));
    6380          60 :                 if (nSize > 0)
    6381             :                 {
    6382             :                     const std::string osSubfile(
    6383             :                         CPLSPrintf("/vsisubfile/" CPL_FRMT_GUIB "_%d,%s",
    6384             :                                    static_cast<GUIntBig>(nOffset),
    6385          25 :                                    static_cast<int>(std::min(
    6386          50 :                                        static_cast<vsi_l_offset>(1024), nSize)),
    6387          75 :                                    m_osFilename.c_str()));
    6388          25 :                     const char *const apszDrivers[] = {pszDriverName, nullptr};
    6389             :                     auto poWebPDataset =
    6390             :                         std::unique_ptr<GDALDataset>(GDALDataset::Open(
    6391          50 :                             osSubfile.c_str(), GDAL_OF_RASTER, apszDrivers));
    6392          25 :                     if (poWebPDataset)
    6393             :                     {
    6394             :                         const char *pszReversibility =
    6395          25 :                             poWebPDataset->GetMetadataItem(
    6396          25 :                                 "COMPRESSION_REVERSIBILITY", "IMAGE_STRUCTURE");
    6397          25 :                         if (pszReversibility)
    6398          25 :                             m_oGTiffMDMD.SetMetadataItem(
    6399             :                                 "COMPRESSION_REVERSIBILITY", pszReversibility,
    6400             :                                 "IMAGE_STRUCTURE");
    6401             :                     }
    6402             :                 }
    6403             :             }
    6404             :         }
    6405             : 
    6406       73608 :         if (!m_bLayoutChecked && m_poBaseDS == nullptr)
    6407             :         {
    6408        5268 :             m_bLayoutChecked = true;
    6409             :             const char *pszLayout =
    6410        5268 :                 m_oGTiffMDMD.GetMetadataItem("LAYOUT", "IMAGE_STRUCTURE");
    6411        5268 :             if (eAccess == GA_ReadOnly && !pszLayout && CheckCOGLayout())
    6412             :             {
    6413         166 :                 m_oGTiffMDMD.SetMetadataItem("LAYOUT", "COG",
    6414             :                                              "IMAGE_STRUCTURE");
    6415             :             }
    6416       73608 :         }
    6417             :     }
    6418             :     else
    6419             :     {
    6420       77659 :         LoadGeoreferencingAndPamIfNeeded();
    6421             :     }
    6422             : 
    6423      151267 :     if (pszDomain != nullptr && EQUAL(pszDomain, "ProxyOverviewRequest"))
    6424             :     {
    6425           4 :         return GDALPamDataset::GetMetadataItem(pszName, pszDomain);
    6426             :     }
    6427      151263 :     else if (pszDomain != nullptr && (EQUAL(pszDomain, MD_DOMAIN_RPC) ||
    6428      151208 :                                       EQUAL(pszDomain, MD_DOMAIN_IMD) ||
    6429      151206 :                                       EQUAL(pszDomain, MD_DOMAIN_IMAGERY)))
    6430             :     {
    6431          60 :         LoadMetadata();
    6432             :     }
    6433      151203 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "SUBDATASETS"))
    6434             :     {
    6435           1 :         ScanDirectories();
    6436             :     }
    6437      151202 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "EXIF"))
    6438             :     {
    6439           1 :         LoadEXIFMetadata();
    6440             :     }
    6441      151201 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "COLOR_PROFILE"))
    6442             :     {
    6443        5644 :         LoadICCProfile();
    6444             :     }
    6445      145557 :     else if ((pszDomain == nullptr || EQUAL(pszDomain, "")) &&
    6446       65172 :              pszName != nullptr && EQUAL(pszName, GDALMD_AREA_OR_POINT))
    6447             :     {
    6448        8953 :         LoadMDAreaOrPoint();  // To set GDALMD_AREA_OR_POINT.
    6449             :     }
    6450      136604 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "_DEBUG_") &&
    6451          79 :              pszName != nullptr)
    6452             :     {
    6453             : #ifdef DEBUG_REACHED_VIRTUAL_MEM_IO
    6454             :         if (EQUAL(pszName, "UNREACHED_VIRTUALMEMIO_CODE_PATH"))
    6455             :         {
    6456             :             CPLString osMissing;
    6457             :             for (int i = 0;
    6458             :                  i < static_cast<int>(CPL_ARRAYSIZE(anReachedVirtualMemIO));
    6459             :                  ++i)
    6460             :             {
    6461             :                 if (!anReachedVirtualMemIO[i])
    6462             :                 {
    6463             :                     if (!osMissing.empty())
    6464             :                         osMissing += ",";
    6465             :                     osMissing += CPLSPrintf("%d", i);
    6466             :                 }
    6467             :             }
    6468             :             return (osMissing.size()) ? CPLSPrintf("%s", osMissing.c_str())
    6469             :                                       : nullptr;
    6470             :         }
    6471             :         else
    6472             : #endif
    6473          79 :             if (EQUAL(pszName, "TIFFTAG_EXTRASAMPLES"))
    6474             :         {
    6475          18 :             CPLString osRet;
    6476          18 :             uint16_t *v = nullptr;
    6477          18 :             uint16_t count = 0;
    6478             : 
    6479          18 :             if (TIFFGetField(m_hTIFF, TIFFTAG_EXTRASAMPLES, &count, &v))
    6480             :             {
    6481          53 :                 for (int i = 0; i < static_cast<int>(count); ++i)
    6482             :                 {
    6483          37 :                     if (i > 0)
    6484          21 :                         osRet += ",";
    6485          37 :                     osRet += CPLSPrintf("%d", v[i]);
    6486             :                 }
    6487             :             }
    6488          18 :             return (osRet.size()) ? CPLSPrintf("%s", osRet.c_str()) : nullptr;
    6489             :         }
    6490          61 :         else if (EQUAL(pszName, "TIFFTAG_PHOTOMETRIC"))
    6491             :         {
    6492           6 :             return CPLSPrintf("%d", m_nPhotometric);
    6493             :         }
    6494             : 
    6495          55 :         else if (EQUAL(pszName, "TIFFTAG_GDAL_METADATA"))
    6496             :         {
    6497           7 :             char *pszText = nullptr;
    6498           7 :             if (!TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText))
    6499           6 :                 return nullptr;
    6500             : 
    6501           1 :             return pszText;
    6502             :         }
    6503          48 :         else if (EQUAL(pszName, "HAS_USED_READ_ENCODED_API"))
    6504             :         {
    6505           6 :             return m_bHasUsedReadEncodedAPI ? "1" : "0";
    6506             :         }
    6507          42 :         else if (EQUAL(pszName, "WEBP_LOSSLESS"))
    6508             :         {
    6509           6 :             return m_bWebPLossless ? "1" : "0";
    6510             :         }
    6511          36 :         else if (EQUAL(pszName, "WEBP_LEVEL"))
    6512             :         {
    6513           2 :             return CPLSPrintf("%d", m_nWebPLevel);
    6514             :         }
    6515          34 :         else if (EQUAL(pszName, "MAX_Z_ERROR"))
    6516             :         {
    6517          10 :             return CPLSPrintf("%f", m_dfMaxZError);
    6518             :         }
    6519          24 :         else if (EQUAL(pszName, "MAX_Z_ERROR_OVERVIEW"))
    6520             :         {
    6521           6 :             return CPLSPrintf("%f", m_dfMaxZErrorOverview);
    6522             :         }
    6523             : #if HAVE_JXL
    6524          18 :         else if (EQUAL(pszName, "JXL_LOSSLESS"))
    6525             :         {
    6526           9 :             return m_bJXLLossless ? "1" : "0";
    6527             :         }
    6528           9 :         else if (EQUAL(pszName, "JXL_DISTANCE"))
    6529             :         {
    6530           4 :             return CPLSPrintf("%f", static_cast<double>(m_fJXLDistance));
    6531             :         }
    6532           5 :         else if (EQUAL(pszName, "JXL_ALPHA_DISTANCE"))
    6533             :         {
    6534           0 :             return CPLSPrintf("%f", static_cast<double>(m_fJXLAlphaDistance));
    6535             :         }
    6536           5 :         else if (EQUAL(pszName, "JXL_EFFORT"))
    6537             :         {
    6538           4 :             return CPLSPrintf("%u", m_nJXLEffort);
    6539             :         }
    6540             : #endif
    6541           1 :         return nullptr;
    6542             :     }
    6543             : 
    6544      136525 :     else if (pszDomain != nullptr && EQUAL(pszDomain, "TIFF") &&
    6545           7 :              pszName != nullptr)
    6546             :     {
    6547           7 :         if (EQUAL(pszName, "GDAL_STRUCTURAL_METADATA"))
    6548             :         {
    6549           2 :             const auto nOffset = VSIFTellL(m_fpL);
    6550           2 :             VSIFSeekL(m_fpL, 0, SEEK_SET);
    6551             :             GByte abyData[1024];
    6552           2 :             size_t nRead = VSIFReadL(abyData, 1, sizeof(abyData) - 1, m_fpL);
    6553           2 :             abyData[nRead] = 0;
    6554           2 :             VSIFSeekL(m_fpL, nOffset, SEEK_SET);
    6555           2 :             if (nRead > 4)
    6556             :             {
    6557           2 :                 const int nOffsetOfStructuralMetadata =
    6558           2 :                     (abyData[2] == 0x2B || abyData[3] == 0x2B) ? 16 : 8;
    6559           2 :                 const int nSizePatternLen =
    6560             :                     static_cast<int>(strlen("XXXXXX bytes\n"));
    6561           2 :                 if (nRead > nOffsetOfStructuralMetadata +
    6562           2 :                                 strlen("GDAL_STRUCTURAL_METADATA_SIZE=") +
    6563           2 :                                 nSizePatternLen &&
    6564           2 :                     memcmp(abyData + nOffsetOfStructuralMetadata,
    6565             :                            "GDAL_STRUCTURAL_METADATA_SIZE=",
    6566             :                            strlen("GDAL_STRUCTURAL_METADATA_SIZE=")) == 0)
    6567             :                 {
    6568           1 :                     char *pszStructuralMD = reinterpret_cast<char *>(
    6569           1 :                         abyData + nOffsetOfStructuralMetadata);
    6570             :                     const int nLenMD =
    6571           1 :                         atoi(pszStructuralMD +
    6572             :                              strlen("GDAL_STRUCTURAL_METADATA_SIZE="));
    6573           1 :                     if (nOffsetOfStructuralMetadata +
    6574             :                             strlen("GDAL_STRUCTURAL_METADATA_SIZE=") +
    6575           1 :                             nSizePatternLen + nLenMD <=
    6576             :                         nRead)
    6577             :                     {
    6578             :                         pszStructuralMD[strlen(
    6579             :                                             "GDAL_STRUCTURAL_METADATA_SIZE=") +
    6580           1 :                                         nSizePatternLen + nLenMD] = 0;
    6581           1 :                         return CPLSPrintf("%s", pszStructuralMD);
    6582             :                     }
    6583             :                 }
    6584             :             }
    6585           1 :             return nullptr;
    6586           5 :         }
    6587             :     }
    6588             : 
    6589      136518 :     else if (pszName && pszDomain && EQUAL(pszDomain, "json:ISIS3"))
    6590             :     {
    6591           4 :         auto oIter = m_oMapISIS3MetadataItems.find(pszName);
    6592           4 :         if (oIter != m_oMapISIS3MetadataItems.end())
    6593             :         {
    6594           1 :             return oIter->second.c_str();
    6595             :         }
    6596             :         else
    6597             :         {
    6598           3 :             if (!m_oISIS3Metadata.IsValid())
    6599             :             {
    6600           2 :                 CSLConstList papszMD = m_oGTiffMDMD.GetMetadata(pszDomain);
    6601           2 :                 if (papszMD && papszMD[0])
    6602             :                 {
    6603           4 :                     CPLJSONDocument oDoc;
    6604           2 :                     if (oDoc.LoadMemory(papszMD[0]))
    6605             :                     {
    6606           2 :                         m_oISIS3Metadata = oDoc.GetRoot();
    6607             :                     }
    6608             :                 }
    6609             :             }
    6610           9 :             CPLJSONObject obj = m_oISIS3Metadata[pszName];
    6611           3 :             if (obj.IsValid())
    6612             :             {
    6613             :                 return m_oMapISIS3MetadataItems
    6614           2 :                     .insert(std::pair<std::string, std::string>(pszName,
    6615           3 :                                                                 obj.ToString()))
    6616           1 :                     .first->second.c_str();
    6617             :             }
    6618           2 :             return nullptr;
    6619             :         }
    6620             :     }
    6621             : 
    6622      151178 :     return m_oGTiffMDMD.GetMetadataItem(pszName, pszDomain);
    6623             : }
    6624             : 
    6625             : /************************************************************************/
    6626             : /*                          LoadEXIFMetadata()                          */
    6627             : /************************************************************************/
    6628             : 
    6629          59 : void GTiffDataset::LoadEXIFMetadata()
    6630             : {
    6631          59 :     if (m_bEXIFMetadataLoaded)
    6632           7 :         return;
    6633          52 :     m_bEXIFMetadataLoaded = true;
    6634             : 
    6635          52 :     VSILFILE *fp = VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF));
    6636             : 
    6637          52 :     GByte abyHeader[2] = {0};
    6638          52 :     if (VSIFSeekL(fp, 0, SEEK_SET) != 0 || VSIFReadL(abyHeader, 1, 2, fp) != 2)
    6639           0 :         return;
    6640             : 
    6641          52 :     const bool bLittleEndian = abyHeader[0] == 'I' && abyHeader[1] == 'I';
    6642          52 :     const bool bLeastSignificantBit = CPL_IS_LSB != 0;
    6643          52 :     const bool bSwabflag = bLittleEndian != bLeastSignificantBit;  // != is XOR.
    6644             : 
    6645          52 :     char **papszMetadata = nullptr;
    6646          52 :     toff_t nOffset = 0;
    6647             : 
    6648          52 :     if (TIFFGetField(m_hTIFF, TIFFTAG_EXIFIFD, &nOffset))
    6649             :     {
    6650           3 :         uint32_t nExifOffset = static_cast<uint32_t>(nOffset);
    6651           3 :         uint32_t nInterOffset = 0;
    6652           3 :         uint32_t nGPSOffset = 0;
    6653           3 :         EXIFExtractMetadata(papszMetadata, fp, static_cast<uint32_t>(nOffset),
    6654             :                             bSwabflag, 0, nExifOffset, nInterOffset,
    6655             :                             nGPSOffset);
    6656             :     }
    6657             : 
    6658          52 :     if (TIFFGetField(m_hTIFF, TIFFTAG_GPSIFD, &nOffset))
    6659             :     {
    6660           3 :         uint32_t nExifOffset = 0;
    6661           3 :         uint32_t nInterOffset = 0;
    6662           3 :         uint32_t nGPSOffset = static_cast<uint32_t>(nOffset);
    6663           3 :         EXIFExtractMetadata(papszMetadata, fp, static_cast<uint32_t>(nOffset),
    6664             :                             bSwabflag, 0, nExifOffset, nInterOffset,
    6665             :                             nGPSOffset);
    6666             :     }
    6667             : 
    6668          52 :     if (papszMetadata)
    6669             :     {
    6670           3 :         m_oGTiffMDMD.SetMetadata(papszMetadata, "EXIF");
    6671           3 :         CSLDestroy(papszMetadata);
    6672             :     }
    6673             : }
    6674             : 
    6675             : /************************************************************************/
    6676             : /*                            LoadMetadata()                            */
    6677             : /************************************************************************/
    6678       22155 : void GTiffDataset::LoadMetadata()
    6679             : {
    6680       22155 :     if (m_bIMDRPCMetadataLoaded)
    6681       17317 :         return;
    6682        4914 :     m_bIMDRPCMetadataLoaded = true;
    6683             : 
    6684        4914 :     if (EQUAL(CPLGetExtensionSafe(GetDescription()).c_str(), "ovr"))
    6685             :     {
    6686             :         // Do not attempt to retrieve metadata files on .tif.ovr files.
    6687             :         // For example the Pleiades metadata reader might wrongly associate a
    6688             :         // DIM_xxx.XML file that was meant to be associated with the main
    6689             :         // TIFF file. The consequence of that wrong association is that if
    6690             :         // one cleans overviews, then the Delete() method would then delete
    6691             :         // that DIM_xxx.XML file since it would be reported in the GetFileList()
    6692             :         // of the overview dataset.
    6693          76 :         return;
    6694             :     }
    6695             : 
    6696        9676 :     GDALMDReaderManager mdreadermanager;
    6697             :     GDALMDReaderBase *mdreader =
    6698        4838 :         m_poBaseDS == nullptr
    6699        4838 :             ? mdreadermanager.GetReader(m_osFilename.c_str(),
    6700             :                                         oOvManager.GetSiblingFiles(), MDR_ANY)
    6701        4838 :             : nullptr;
    6702             : 
    6703        4838 :     if (nullptr != mdreader)
    6704             :     {
    6705          65 :         mdreader->FillMetadata(&m_oGTiffMDMD);
    6706             : 
    6707          65 :         if (mdreader->GetMetadataDomain(MD_DOMAIN_RPC) == nullptr)
    6708             :         {
    6709          36 :             char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
    6710          36 :             if (papszRPCMD)
    6711             :             {
    6712          12 :                 m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
    6713          12 :                 CSLDestroy(papszRPCMD);
    6714             :             }
    6715             :         }
    6716             : 
    6717          65 :         m_papszMetadataFiles = mdreader->GetMetadataFiles();
    6718             :     }
    6719             :     else
    6720             :     {
    6721        4773 :         char **papszRPCMD = GTiffDatasetReadRPCTag(m_hTIFF);
    6722        4773 :         if (papszRPCMD)
    6723             :         {
    6724          20 :             m_oGTiffMDMD.SetMetadata(papszRPCMD, MD_DOMAIN_RPC);
    6725          20 :             CSLDestroy(papszRPCMD);
    6726             :         }
    6727             :     }
    6728             : }
    6729             : 
    6730             : /************************************************************************/
    6731             : /*                        LoadENVIHdrIfNeeded()                         */
    6732             : /************************************************************************/
    6733             : 
    6734       26757 : void GTiffDataset::LoadENVIHdrIfNeeded()
    6735             : {
    6736       26757 :     if (m_bENVIHdrTried || m_poBaseDS)
    6737       26751 :         return;
    6738        8667 :     m_bENVIHdrTried = true;
    6739             : 
    6740             :     const std::string osHdrFilename =
    6741        8667 :         GetSidecarFilenameWithReplacedExtension("hdr");
    6742        8667 :     if (osHdrFilename.empty())
    6743        7657 :         return;
    6744             : 
    6745        1010 :     auto fp = VSIFilesystemHandler::OpenStatic(osHdrFilename.c_str(), "rb");
    6746        1010 :     if (!fp)
    6747           0 :         return;
    6748             : 
    6749        1010 :     constexpr int MAX_LINE_SIZE = 10000;
    6750             : 
    6751             :     // Check line is "ENVI"
    6752        1010 :     const char *pszFirstLine = CPLReadLine2L(fp.get(), MAX_LINE_SIZE, nullptr);
    6753        1010 :     if (!pszFirstLine || !EQUAL(pszFirstLine, "ENVI"))
    6754           0 :         return;
    6755             : 
    6756        1010 :     VSIRewindL(fp.get());
    6757             : 
    6758        1010 :     const CPLStringList aosHeaders(GDALReadENVIHeader(fp.get()));
    6759             : 
    6760             :     // Basic check to verify the .hdr file is indeed related to the GeoTIFF one
    6761        1010 :     if (atoi(aosHeaders.FetchNameValueDef("samples", "0")) != nRasterXSize ||
    6762        2019 :         atoi(aosHeaders.FetchNameValueDef("lines", "0")) != nRasterYSize ||
    6763        1009 :         !EQUAL(aosHeaders.FetchNameValueDef("file_type", ""), "TIFF"))
    6764             :     {
    6765        1004 :         return;
    6766             :     }
    6767             : 
    6768           6 :     m_bENVIHdrFound = true;
    6769             : 
    6770           6 :     const char *const apszOptions[] = {
    6771             :         "APPLY_DEFAULT_BANDS=NO",        "APPLY_CLASS_LOOKUP=NO",
    6772             :         "APPLY_DATA_IGNORE_VALUE=NO",    "SET_BAND_NAME=NO",
    6773             :         "SET_DATASET_LEVEL_METADATA=NO", nullptr,
    6774             :     };
    6775           6 :     GDALApplyENVIHeaders(this, aosHeaders, apszOptions);
    6776             : }
    6777             : 
    6778             : /************************************************************************/
    6779             : /*                     HasOptimizedReadMultiRange()                     */
    6780             : /************************************************************************/
    6781             : 
    6782     2907720 : bool GTiffDataset::HasOptimizedReadMultiRange()
    6783             : {
    6784     2907720 :     if (m_nHasOptimizedReadMultiRange >= 0)
    6785     2892040 :         return m_nHasOptimizedReadMultiRange != 0;
    6786       15680 :     m_nHasOptimizedReadMultiRange = static_cast<signed char>(
    6787       15680 :         VSIHasOptimizedReadMultiRange(m_osFilename.c_str())
    6788             :         // Config option for debug and testing purposes only
    6789       15680 :         || CPLTestBool(CPLGetConfigOption(
    6790             :                "GTIFF_HAS_OPTIMIZED_READ_MULTI_RANGE", "NO")));
    6791       15680 :     return m_nHasOptimizedReadMultiRange != 0;
    6792             : }
    6793             : 
    6794             : /************************************************************************/
    6795             : /*                          CacheMultiRange()                           */
    6796             : /************************************************************************/
    6797             : 
    6798         256 : static bool CheckTrailer(const GByte *strileData, vsi_l_offset nStrileSize)
    6799             : {
    6800             :     GByte abyTrailer[4];
    6801         256 :     memcpy(abyTrailer, strileData + nStrileSize, 4);
    6802         256 :     GByte abyLastBytes[4] = {};
    6803         256 :     if (nStrileSize >= 4)
    6804         256 :         memcpy(abyLastBytes, strileData + nStrileSize - 4, 4);
    6805             :     else
    6806             :     {
    6807             :         // The last bytes will be zero due to the above {} initialization,
    6808             :         // and that's what should be in abyTrailer too when the trailer is
    6809             :         // correct.
    6810           0 :         memcpy(abyLastBytes, strileData, static_cast<size_t>(nStrileSize));
    6811             :     }
    6812         256 :     return memcmp(abyTrailer, abyLastBytes, 4) == 0;
    6813             : }
    6814             : 
    6815         268 : void *GTiffDataset::CacheMultiRange(int nXOff, int nYOff, int nXSize,
    6816             :                                     int nYSize, int nBufXSize, int nBufYSize,
    6817             :                                     const int *panBandMap, int nBandCount,
    6818             :                                     GDALRasterIOExtraArg *psExtraArg)
    6819             : {
    6820         268 :     void *pBufferedData = nullptr;
    6821             :     // Same logic as in GDALRasterBand::IRasterIO()
    6822         268 :     double dfXOff = nXOff;
    6823         268 :     double dfYOff = nYOff;
    6824         268 :     double dfXSize = nXSize;
    6825         268 :     double dfYSize = nYSize;
    6826         268 :     if (psExtraArg->bFloatingPointWindowValidity)
    6827             :     {
    6828          48 :         dfXOff = psExtraArg->dfXOff;
    6829          48 :         dfYOff = psExtraArg->dfYOff;
    6830          48 :         dfXSize = psExtraArg->dfXSize;
    6831          48 :         dfYSize = psExtraArg->dfYSize;
    6832             :     }
    6833         268 :     const double dfSrcXInc = dfXSize / static_cast<double>(nBufXSize);
    6834         268 :     const double dfSrcYInc = dfYSize / static_cast<double>(nBufYSize);
    6835         268 :     const double EPS = 1e-10;
    6836             :     const int nBlockX1 =
    6837         268 :         static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
    6838         268 :         m_nBlockXSize;
    6839             :     const int nBlockY1 =
    6840         268 :         static_cast<int>(std::max(0.0, (0 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
    6841         268 :         m_nBlockYSize;
    6842             :     const int nBlockX2 =
    6843         268 :         static_cast<int>(
    6844         536 :             std::min(static_cast<double>(nRasterXSize - 1),
    6845         268 :                      (nBufXSize - 1 + 0.5) * dfSrcXInc + dfXOff + EPS)) /
    6846         268 :         m_nBlockXSize;
    6847             :     const int nBlockY2 =
    6848         268 :         static_cast<int>(
    6849         536 :             std::min(static_cast<double>(nRasterYSize - 1),
    6850         268 :                      (nBufYSize - 1 + 0.5) * dfSrcYInc + dfYOff + EPS)) /
    6851         268 :         m_nBlockYSize;
    6852             : 
    6853             :     struct StrileData
    6854             :     {
    6855             :         vsi_l_offset nOffset;
    6856             :         vsi_l_offset nByteCount;
    6857             :         bool bTryMask;
    6858             :     };
    6859             : 
    6860         536 :     std::map<int, StrileData> oMapStrileToOffsetByteCount;
    6861             : 
    6862             :     // Dedicated method to retrieved the offset and size in an efficient way
    6863             :     // when m_bBlockOrderRowMajor and m_bLeaderSizeAsUInt4 conditions are
    6864             :     // met.
    6865             :     // Except for the last block, we just read the offset from the TIFF offset
    6866             :     // array, and retrieve the size in the leader 4 bytes that come before the
    6867             :     // payload.
    6868             :     auto OptimizedRetrievalOfOffsetSize =
    6869         218 :         [&](int nBand, int nBlockId, vsi_l_offset &nOffset, vsi_l_offset &nSize,
    6870             :             size_t nTotalSize, size_t nMaxRawBlockCacheSize)
    6871             :     {
    6872        1224 :         bool bTryMask = m_bMaskInterleavedWithImagery;
    6873         218 :         nOffset = TIFFGetStrileOffset(m_hTIFF, nBlockId);
    6874         218 :         if (nOffset >= 4)
    6875             :         {
    6876         155 :             if ((m_nPlanarConfig == PLANARCONFIG_CONTIG &&
    6877         131 :                  nBlockId == m_nBlocksPerBand - 1) ||
    6878         129 :                 (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
    6879          24 :                  nBlockId == m_nBlocksPerBand * nBands - 1))
    6880             :             {
    6881             :                 // Special case for the last block. As there is no next block
    6882             :                 // from which to retrieve an offset, use the good old method
    6883             :                 // that consists in reading the ByteCount array.
    6884          26 :                 if (m_nPlanarConfig == PLANARCONFIG_CONTIG && bTryMask &&
    6885          54 :                     GetRasterBand(1)->GetMaskBand() && m_poMaskDS)
    6886             :                 {
    6887             :                     auto nMaskOffset =
    6888          23 :                         TIFFGetStrileOffset(m_poMaskDS->m_hTIFF, nBlockId);
    6889          23 :                     if (nMaskOffset)
    6890             :                     {
    6891          23 :                         nSize = nMaskOffset +
    6892          23 :                                 TIFFGetStrileByteCount(m_poMaskDS->m_hTIFF,
    6893          23 :                                                        nBlockId) -
    6894          23 :                                 nOffset;
    6895             :                     }
    6896             :                     else
    6897             :                     {
    6898           0 :                         bTryMask = false;
    6899             :                     }
    6900             :                 }
    6901          28 :                 if (nSize == 0)
    6902             :                 {
    6903           5 :                     nSize = TIFFGetStrileByteCount(m_hTIFF, nBlockId);
    6904             :                 }
    6905          28 :                 if (nSize && m_bTrailerRepeatedLast4BytesRepeated)
    6906             :                 {
    6907          28 :                     nSize += 4;
    6908          28 :                 }
    6909             :             }
    6910             :             else
    6911             :             {
    6912         127 :                 const auto nNextBlockId =
    6913          11 :                     (m_bTileInterleave && nBand < nBands)
    6914         254 :                         ? nBlockId + m_nBlocksPerBand
    6915           3 :                     : (m_bTileInterleave && nBand == nBands)
    6916         122 :                         ? nBlockId - (nBand - 1) * m_nBlocksPerBand + 1
    6917         116 :                         : nBlockId + 1;
    6918         127 :                 auto nOffsetNext = TIFFGetStrileOffset(m_hTIFF, nNextBlockId);
    6919         127 :                 if (nOffsetNext > nOffset)
    6920             :                 {
    6921         119 :                     nSize = nOffsetNext - nOffset;
    6922             :                 }
    6923             :                 else
    6924             :                 {
    6925             :                     // Shouldn't happen for a compliant file
    6926           8 :                     if (nOffsetNext != 0)
    6927             :                     {
    6928           0 :                         CPLDebug("GTiff", "Tile %d is not located after %d",
    6929             :                                  nNextBlockId, nBlockId);
    6930             :                     }
    6931           8 :                     bTryMask = false;
    6932           8 :                     nSize = TIFFGetStrileByteCount(m_hTIFF, nBlockId);
    6933           8 :                     if (m_bTrailerRepeatedLast4BytesRepeated)
    6934           8 :                         nSize += 4;
    6935             :                 }
    6936             :             }
    6937         155 :             if (nSize)
    6938             :             {
    6939         155 :                 nOffset -= 4;
    6940         155 :                 nSize += 4;
    6941         155 :                 if (nTotalSize + nSize < nMaxRawBlockCacheSize)
    6942             :                 {
    6943             :                     StrileData data;
    6944         155 :                     data.nOffset = nOffset;
    6945         155 :                     data.nByteCount = nSize;
    6946         155 :                     data.bTryMask = bTryMask;
    6947         155 :                     oMapStrileToOffsetByteCount[nBlockId] = data;
    6948             :                 }
    6949             :             }
    6950             :         }
    6951             :         else
    6952             :         {
    6953             :             // Sparse tile
    6954             :             StrileData data;
    6955          63 :             data.nOffset = 0;
    6956          63 :             data.nByteCount = 0;
    6957          63 :             data.bTryMask = false;
    6958          63 :             oMapStrileToOffsetByteCount[nBlockId] = data;
    6959             :         }
    6960         218 :     };
    6961             : 
    6962             :     // This lambda fills m_poDS->m_oCacheStrileToOffsetByteCount (and
    6963             :     // m_poDS->m_poMaskDS->m_oCacheStrileToOffsetByteCount, when there is a
    6964             :     // mask) from the temporary oMapStrileToOffsetByteCount.
    6965             :     auto FillCacheStrileToOffsetByteCount =
    6966          37 :         [&](const std::vector<vsi_l_offset> &anOffsets,
    6967             :             const std::vector<size_t> &anSizes,
    6968             :             const std::vector<void *> &apData)
    6969             :     {
    6970          37 :         CPLAssert(m_bLeaderSizeAsUInt4);
    6971          37 :         size_t i = 0;
    6972          37 :         vsi_l_offset nLastOffset = 0;
    6973         215 :         for (const auto &entry : oMapStrileToOffsetByteCount)
    6974             :         {
    6975         178 :             const auto nBlockId = entry.first;
    6976         178 :             const auto nOffset = entry.second.nOffset;
    6977         178 :             const auto nSize = entry.second.nByteCount;
    6978         178 :             if (nOffset == 0)
    6979             :             {
    6980             :                 // Sparse tile
    6981             :                 m_oCacheStrileToOffsetByteCount.insert(nBlockId,
    6982          23 :                                                        std::pair(0, 0));
    6983          77 :                 continue;
    6984             :             }
    6985             : 
    6986         155 :             if (nOffset < nLastOffset)
    6987             :             {
    6988             :                 // shouldn't happen normally if tiles are sorted
    6989           2 :                 i = 0;
    6990             :             }
    6991         155 :             nLastOffset = nOffset;
    6992         318 :             while (i < anOffsets.size() &&
    6993         159 :                    !(nOffset >= anOffsets[i] &&
    6994         159 :                      nOffset + nSize <= anOffsets[i] + anSizes[i]))
    6995             :             {
    6996           4 :                 i++;
    6997             :             }
    6998         155 :             CPLAssert(i < anOffsets.size());
    6999         155 :             CPLAssert(nOffset >= anOffsets[i]);
    7000         155 :             CPLAssert(nOffset + nSize <= anOffsets[i] + anSizes[i]);
    7001             :             GUInt32 nSizeFromLeader;
    7002         155 :             memcpy(&nSizeFromLeader,
    7003             :                    // cppcheck-suppress containerOutOfBounds
    7004         155 :                    static_cast<GByte *>(apData[i]) + nOffset - anOffsets[i],
    7005             :                    sizeof(nSizeFromLeader));
    7006         155 :             CPL_LSBPTR32(&nSizeFromLeader);
    7007         155 :             bool bOK = true;
    7008         155 :             constexpr int nLeaderSize = 4;
    7009         155 :             const int nTrailerSize =
    7010         155 :                 (m_bTrailerRepeatedLast4BytesRepeated ? 4 : 0);
    7011         155 :             if (nSizeFromLeader > nSize - nLeaderSize - nTrailerSize)
    7012             :             {
    7013           0 :                 CPLDebug("GTiff",
    7014             :                          "Inconsistent block size from in leader of block %d",
    7015             :                          nBlockId);
    7016           0 :                 bOK = false;
    7017             :             }
    7018         155 :             else if (m_bTrailerRepeatedLast4BytesRepeated)
    7019             :             {
    7020             :                 // Check trailer consistency
    7021         155 :                 const GByte *strileData = static_cast<GByte *>(apData[i]) +
    7022         155 :                                           nOffset - anOffsets[i] + nLeaderSize;
    7023         155 :                 if (!CheckTrailer(strileData, nSizeFromLeader))
    7024             :                 {
    7025           0 :                     CPLDebug("GTiff", "Inconsistent trailer of block %d",
    7026             :                              nBlockId);
    7027           0 :                     bOK = false;
    7028             :                 }
    7029             :             }
    7030         155 :             if (!bOK)
    7031             :             {
    7032           0 :                 return false;
    7033             :             }
    7034             : 
    7035             :             {
    7036         155 :                 const vsi_l_offset nRealOffset = nOffset + nLeaderSize;
    7037         155 :                 const vsi_l_offset nRealSize = nSizeFromLeader;
    7038             : #ifdef DEBUG_VERBOSE
    7039             :                 CPLDebug("GTiff",
    7040             :                          "Block %d found at offset " CPL_FRMT_GUIB
    7041             :                          " with size " CPL_FRMT_GUIB,
    7042             :                          nBlockId, nRealOffset, nRealSize);
    7043             : #endif
    7044             :                 m_oCacheStrileToOffsetByteCount.insert(
    7045         155 :                     nBlockId, std::pair(nRealOffset, nRealSize));
    7046             :             }
    7047             : 
    7048             :             // Processing of mask
    7049         256 :             if (!(entry.second.bTryMask && m_bMaskInterleavedWithImagery &&
    7050         101 :                   GetRasterBand(1)->GetMaskBand() && m_poMaskDS))
    7051             :             {
    7052          54 :                 continue;
    7053             :             }
    7054             : 
    7055         101 :             bOK = false;
    7056         101 :             const vsi_l_offset nMaskOffsetWithLeader =
    7057         101 :                 nOffset + nLeaderSize + nSizeFromLeader + nTrailerSize;
    7058         202 :             if (nMaskOffsetWithLeader + nLeaderSize <=
    7059         101 :                 anOffsets[i] + anSizes[i])
    7060             :             {
    7061             :                 GUInt32 nMaskSizeFromLeader;
    7062         101 :                 memcpy(&nMaskSizeFromLeader,
    7063         101 :                        static_cast<GByte *>(apData[i]) + nMaskOffsetWithLeader -
    7064         101 :                            anOffsets[i],
    7065             :                        sizeof(nMaskSizeFromLeader));
    7066         101 :                 CPL_LSBPTR32(&nMaskSizeFromLeader);
    7067         202 :                 if (nMaskOffsetWithLeader + nLeaderSize + nMaskSizeFromLeader +
    7068         202 :                         nTrailerSize <=
    7069         101 :                     anOffsets[i] + anSizes[i])
    7070             :                 {
    7071         101 :                     bOK = true;
    7072         101 :                     if (m_bTrailerRepeatedLast4BytesRepeated)
    7073             :                     {
    7074             :                         // Check trailer consistency
    7075             :                         const GByte *strileMaskData =
    7076         101 :                             static_cast<GByte *>(apData[i]) + nOffset -
    7077         202 :                             anOffsets[i] + nLeaderSize + nSizeFromLeader +
    7078         101 :                             nTrailerSize + nLeaderSize;
    7079         101 :                         if (!CheckTrailer(strileMaskData, nMaskSizeFromLeader))
    7080             :                         {
    7081           0 :                             CPLDebug("GTiff",
    7082             :                                      "Inconsistent trailer of mask of block %d",
    7083             :                                      nBlockId);
    7084           0 :                             bOK = false;
    7085             :                         }
    7086             :                     }
    7087             :                 }
    7088         101 :                 if (bOK)
    7089             :                 {
    7090         101 :                     const vsi_l_offset nRealOffset = nOffset + nLeaderSize +
    7091         101 :                                                      nSizeFromLeader +
    7092         101 :                                                      nTrailerSize + nLeaderSize;
    7093         101 :                     const vsi_l_offset nRealSize = nMaskSizeFromLeader;
    7094             : #ifdef DEBUG_VERBOSE
    7095             :                     CPLDebug("GTiff",
    7096             :                              "Mask of block %d found at offset " CPL_FRMT_GUIB
    7097             :                              " with size " CPL_FRMT_GUIB,
    7098             :                              nBlockId, nRealOffset, nRealSize);
    7099             : #endif
    7100             : 
    7101         101 :                     m_poMaskDS->m_oCacheStrileToOffsetByteCount.insert(
    7102         101 :                         nBlockId, std::pair(nRealOffset, nRealSize));
    7103             :                 }
    7104             :             }
    7105         101 :             if (!bOK)
    7106             :             {
    7107           0 :                 CPLDebug("GTiff",
    7108             :                          "Mask for block %d is not properly interleaved with "
    7109             :                          "imagery block",
    7110             :                          nBlockId);
    7111             :             }
    7112             :         }
    7113          37 :         return true;
    7114         268 :     };
    7115             : 
    7116         268 :     thandle_t th = TIFFClientdata(m_hTIFF);
    7117         268 :     if (!VSI_TIFFHasCachedRanges(th))
    7118             :     {
    7119         234 :         std::vector<std::pair<vsi_l_offset, size_t>> aOffsetSize;
    7120         234 :         size_t nTotalSize = 0;
    7121         234 :         const unsigned int nMaxRawBlockCacheSize = atoi(
    7122         234 :             CPLGetConfigOption("GDAL_MAX_RAW_BLOCK_CACHE_SIZE", "10485760"));
    7123         234 :         bool bGoOn = true;
    7124         472 :         for (int iBand = 0; iBand < nBandCount; ++iBand)
    7125             :         {
    7126         238 :             const int nBand = panBandMap[iBand];
    7127             :             GTiffRasterBand *poBand =
    7128         238 :                 cpl::down_cast<GTiffRasterBand *>(papoBands[nBand - 1]);
    7129         557 :             for (int iY = nBlockY1; bGoOn && iY <= nBlockY2; iY++)
    7130             :             {
    7131        1042 :                 for (int iX = nBlockX1; bGoOn && iX <= nBlockX2; iX++)
    7132             :                 {
    7133             :                     GDALRasterBlock *poBlock =
    7134         723 :                         poBand->TryGetLockedBlockRef(iX, iY);
    7135         723 :                     if (poBlock != nullptr)
    7136             :                     {
    7137         299 :                         poBlock->DropLock();
    7138         299 :                         continue;
    7139             :                     }
    7140         424 :                     int nBlockId = iX + iY * m_nBlocksPerRow;
    7141         424 :                     if (m_nPlanarConfig == PLANARCONFIG_SEPARATE)
    7142          24 :                         nBlockId += (nBand - 1) * m_nBlocksPerBand;
    7143         424 :                     vsi_l_offset nOffset = 0;
    7144         424 :                     vsi_l_offset nSize = 0;
    7145             : 
    7146         424 :                     if (!m_bStreamingIn && m_bBlockOrderRowMajor &&
    7147         218 :                         m_bLeaderSizeAsUInt4)
    7148             :                     {
    7149         218 :                         OptimizedRetrievalOfOffsetSize(nBand, nBlockId, nOffset,
    7150             :                                                        nSize, nTotalSize,
    7151             :                                                        nMaxRawBlockCacheSize);
    7152             :                     }
    7153             :                     else
    7154             :                     {
    7155         206 :                         CPL_IGNORE_RET_VAL(IsBlockAvailable(nBlockId, &nOffset,
    7156             :                                                             &nSize, nullptr));
    7157             :                     }
    7158         424 :                     if (nSize)
    7159             :                     {
    7160         166 :                         if (nTotalSize + nSize < nMaxRawBlockCacheSize)
    7161             :                         {
    7162             : #ifdef DEBUG_VERBOSE
    7163             :                             CPLDebug(
    7164             :                                 "GTiff",
    7165             :                                 "Precaching for block (%d, %d), " CPL_FRMT_GUIB
    7166             :                                 "-" CPL_FRMT_GUIB,
    7167             :                                 iX, iY, nOffset,
    7168             :                                 nOffset + static_cast<size_t>(nSize) - 1);
    7169             : #endif
    7170         166 :                             aOffsetSize.push_back(
    7171         166 :                                 std::pair(nOffset, static_cast<size_t>(nSize)));
    7172         166 :                             nTotalSize += static_cast<size_t>(nSize);
    7173             :                         }
    7174             :                         else
    7175             :                         {
    7176           0 :                             bGoOn = false;
    7177             :                         }
    7178             :                     }
    7179             :                 }
    7180             :             }
    7181             :         }
    7182             : 
    7183         234 :         std::sort(aOffsetSize.begin(), aOffsetSize.end());
    7184             : 
    7185         234 :         if (nTotalSize > 0)
    7186             :         {
    7187          42 :             pBufferedData = VSI_MALLOC_VERBOSE(nTotalSize);
    7188          42 :             if (pBufferedData)
    7189             :             {
    7190          42 :                 std::vector<vsi_l_offset> anOffsets;
    7191          42 :                 std::vector<size_t> anSizes;
    7192          42 :                 std::vector<void *> apData;
    7193          42 :                 anOffsets.push_back(aOffsetSize[0].first);
    7194          42 :                 apData.push_back(static_cast<GByte *>(pBufferedData));
    7195          42 :                 size_t nChunkSize = aOffsetSize[0].second;
    7196          42 :                 size_t nAccOffset = 0;
    7197             :                 // Try to merge contiguous or slightly overlapping ranges
    7198         166 :                 for (size_t i = 0; i < aOffsetSize.size() - 1; i++)
    7199             :                 {
    7200         248 :                     if (aOffsetSize[i].first < aOffsetSize[i + 1].first &&
    7201         124 :                         aOffsetSize[i].first + aOffsetSize[i].second >=
    7202         124 :                             aOffsetSize[i + 1].first)
    7203             :                     {
    7204         120 :                         const auto overlap = aOffsetSize[i].first +
    7205         120 :                                              aOffsetSize[i].second -
    7206         120 :                                              aOffsetSize[i + 1].first;
    7207             :                         // That should always be the case for well behaved
    7208             :                         // TIFF files.
    7209         120 :                         if (aOffsetSize[i + 1].second > overlap)
    7210             :                         {
    7211         120 :                             nChunkSize += static_cast<size_t>(
    7212         120 :                                 aOffsetSize[i + 1].second - overlap);
    7213             :                         }
    7214             :                     }
    7215             :                     else
    7216             :                     {
    7217             :                         // terminate current block
    7218           4 :                         anSizes.push_back(nChunkSize);
    7219             : #ifdef DEBUG_VERBOSE
    7220             :                         CPLDebug("GTiff",
    7221             :                                  "Requesting range [" CPL_FRMT_GUIB
    7222             :                                  "-" CPL_FRMT_GUIB "]",
    7223             :                                  anOffsets.back(),
    7224             :                                  anOffsets.back() + anSizes.back() - 1);
    7225             : #endif
    7226           4 :                         nAccOffset += nChunkSize;
    7227             :                         // start a new range
    7228           4 :                         anOffsets.push_back(aOffsetSize[i + 1].first);
    7229           4 :                         apData.push_back(static_cast<GByte *>(pBufferedData) +
    7230             :                                          nAccOffset);
    7231           4 :                         nChunkSize = aOffsetSize[i + 1].second;
    7232             :                     }
    7233             :                 }
    7234             :                 // terminate last block
    7235          42 :                 anSizes.push_back(nChunkSize);
    7236             : #ifdef DEBUG_VERBOSE
    7237             :                 CPLDebug(
    7238             :                     "GTiff",
    7239             :                     "Requesting range [" CPL_FRMT_GUIB "-" CPL_FRMT_GUIB "]",
    7240             :                     anOffsets.back(), anOffsets.back() + anSizes.back() - 1);
    7241             : #endif
    7242             : 
    7243          42 :                 VSILFILE *fp = VSI_TIFFGetVSILFile(th);
    7244             : 
    7245             :                 // An error in VSIFReadMultiRangeL() will not be critical,
    7246             :                 // as this method is an optimization, and if it fails,
    7247             :                 // tile-by-tile data acquisition will be done, so we can
    7248             :                 // temporary turn failures into warnings.
    7249             :                 bool ok;
    7250             :                 {
    7251             :                     CPLTurnFailureIntoWarningBackuper
    7252          42 :                         oFailureToWarningBackuper{};
    7253          42 :                     ok = VSIFReadMultiRangeL(static_cast<int>(anSizes.size()),
    7254          42 :                                              &apData[0], &anOffsets[0],
    7255          42 :                                              &anSizes[0], fp) == 0;
    7256             :                 }
    7257             : 
    7258          42 :                 if (ok)
    7259             :                 {
    7260          79 :                     if (!oMapStrileToOffsetByteCount.empty() &&
    7261          37 :                         !FillCacheStrileToOffsetByteCount(anOffsets, anSizes,
    7262             :                                                           apData))
    7263             :                     {
    7264             :                         // Retry without optimization
    7265           0 :                         CPLFree(pBufferedData);
    7266           0 :                         m_bLeaderSizeAsUInt4 = false;
    7267           0 :                         void *pRet = CacheMultiRange(
    7268             :                             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
    7269             :                             panBandMap, nBandCount, psExtraArg);
    7270           0 :                         m_bLeaderSizeAsUInt4 = true;
    7271           0 :                         return pRet;
    7272             :                     }
    7273             : 
    7274          42 :                     VSI_TIFFSetCachedRanges(
    7275          42 :                         th, static_cast<int>(anSizes.size()), &apData[0],
    7276          42 :                         &anOffsets[0], &anSizes[0]);
    7277             :                 }
    7278             :                 else
    7279             :                 {
    7280           0 :                     CPLFree(pBufferedData);
    7281           0 :                     pBufferedData = nullptr;
    7282             :                 }
    7283             :             }
    7284             :         }
    7285             :     }
    7286         268 :     return pBufferedData;
    7287             : }
    7288             : 
    7289             : /************************************************************************/
    7290             : /*                           CheckCOGLayout()                           */
    7291             : /************************************************************************/
    7292             : 
    7293        2947 : bool GTiffDataset::CheckCOGLayout()
    7294             : {
    7295        2947 :     bool bRet = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
    7296        2947 :     const bool bNeedsOverviews = (nRasterXSize > 512 || nRasterYSize > 512);
    7297        2947 :     if (bNeedsOverviews)
    7298         356 :         ScanDirectories();
    7299        2947 :     bRet = bRet && !(m_apoOverviewDS.empty() && bNeedsOverviews);
    7300             : #ifdef TIFFLIB_MAJOR_VERSION
    7301             :     // TIFFIsBigTIFF() added in libtiff 4.4
    7302        2947 :     const uint64_t nExpectedDirOffset = TIFFIsBigTIFF(m_hTIFF) ? 16 : 8;
    7303             : #else
    7304             :     GByte abyData[4] = {0, 0, 0, 0};
    7305             :     {
    7306             :         const auto nCurFPOffset = VSIFTellL(m_fpL);
    7307             :         VSIFSeekL(m_fpL, 0, SEEK_SET);
    7308             :         CPL_IGNORE_RET_VAL(VSIFReadL(abyData, 1, sizeof(abyData), m_fpL));
    7309             :         VSIFSeekL(m_fpL, nCurFPOffset, SEEK_SET);
    7310             :     }
    7311             :     const uint64_t nExpectedDirOffset =
    7312             :         (abyData[2] == 0x2B || abyData[3] == 0x2B) ? 16 : 8;
    7313             : #endif
    7314        2947 :     bRet = bRet && (m_nDirOffset == nExpectedDirOffset);
    7315        2947 :     uint64_t nLastIFDOffset = nExpectedDirOffset;
    7316        2947 :     int nLastXSize = nRasterXSize;
    7317        2947 :     int nLastYSize = nRasterYSize;
    7318        3006 :     for (const auto &poOvrDS : m_apoOverviewDS)
    7319             :     {
    7320          59 :         bRet = bRet && poOvrDS->m_nDirOffset > nLastIFDOffset;
    7321          59 :         bRet = bRet && poOvrDS->nRasterXSize <= nLastXSize;
    7322          59 :         bRet = bRet && poOvrDS->nRasterYSize <= nLastYSize;
    7323          59 :         bRet = bRet && CPL_TO_BOOL(TIFFIsTiled(poOvrDS->m_hTIFF));
    7324          59 :         nLastXSize = poOvrDS->nRasterXSize;
    7325          59 :         nLastYSize = poOvrDS->nRasterYSize;
    7326          59 :         nLastIFDOffset = poOvrDS->m_nDirOffset;
    7327             :     }
    7328        2947 :     uint64_t nDataOffset = nLastIFDOffset;
    7329        2971 :     for (auto iter = m_apoOverviewDS.rbegin();
    7330        2995 :          bRet && iter != m_apoOverviewDS.rend(); ++iter)
    7331             :     {
    7332          24 :         bRet = CPL_TO_BOOL(TIFFIsTiled((*iter)->m_hTIFF));
    7333          24 :         vsi_l_offset nOffset = 0;
    7334          24 :         vsi_l_offset nSize = 0;
    7335          24 :         if ((*iter)->IsBlockAvailable(0, &nOffset, &nSize, nullptr))
    7336             :         {
    7337          21 :             bRet = bRet && nOffset > nDataOffset;
    7338          21 :             nDataOffset = nOffset;
    7339             :         }
    7340             :     }
    7341        2947 :     if (!m_apoOverviewDS.empty())
    7342             :     {
    7343          38 :         vsi_l_offset nOffset = 0;
    7344          38 :         vsi_l_offset nSize = 0;
    7345          38 :         if (IsBlockAvailable(0, &nOffset, &nSize, nullptr))
    7346             :         {
    7347          31 :             bRet = bRet && nOffset > nDataOffset;
    7348             :         }
    7349             :     }
    7350        2947 :     return bRet;
    7351             : }

Generated by: LCOV version 1.14