LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3212 3527 91.1 %
Date: 2025-02-20 10:14:44 Functions: 54 55 98.2 %

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

Generated by: LCOV version 1.14