LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset_read.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 3241 3550 91.3 %
Date: 2025-11-26 00:27:10 Functions: 56 56 100.0 %

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

Generated by: LCOV version 1.14