LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 2962 3262 90.8 %
Date: 2024-05-18 15:15:27 Functions: 50 51 98.0 %

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

Generated by: LCOV version 1.14