LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3214 3520 91.3 %
Date: 2025-05-06 02:01:45 Functions: 54 54 100.0 %

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

Generated by: LCOV version 1.14