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

Generated by: LCOV version 1.14