LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 690 732 94.3 %
Date: 2025-12-24 19:12:58 Functions: 24 25 96.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GeoTIFF Driver
       4             :  * Purpose:  GDAL GeoTIFF support.
       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             : 
      18             : #include <cassert>
      19             : 
      20             : #include <algorithm>
      21             : #include <limits>
      22             : #include <memory>
      23             : #include <set>
      24             : #include <string>
      25             : #include <tuple>
      26             : #include <utility>
      27             : 
      28             : #include "cpl_error.h"
      29             : #include "cpl_vsi.h"
      30             : #include "cpl_vsi_virtual.h"
      31             : #include "cpl_worker_thread_pool.h"
      32             : #include "gdal_priv.h"
      33             : #include "ogr_proj_p.h"  // OSRGetProjTLSContext()
      34             : #include "tif_jxl.h"
      35             : #include "tifvsi.h"
      36             : #include "xtiffio.h"
      37             : 
      38             : static const GTIFFTag asTIFFTags[] = {
      39             :     {"TIFFTAG_DOCUMENTNAME", TIFFTAG_DOCUMENTNAME, GTIFFTAGTYPE_STRING},
      40             :     {"TIFFTAG_IMAGEDESCRIPTION", TIFFTAG_IMAGEDESCRIPTION, GTIFFTAGTYPE_STRING},
      41             :     {"TIFFTAG_SOFTWARE", TIFFTAG_SOFTWARE, GTIFFTAGTYPE_STRING},
      42             :     {"TIFFTAG_DATETIME", TIFFTAG_DATETIME, GTIFFTAGTYPE_STRING},
      43             :     {"TIFFTAG_ARTIST", TIFFTAG_ARTIST, GTIFFTAGTYPE_STRING},
      44             :     {"TIFFTAG_HOSTCOMPUTER", TIFFTAG_HOSTCOMPUTER, GTIFFTAGTYPE_STRING},
      45             :     {"TIFFTAG_COPYRIGHT", TIFFTAG_COPYRIGHT, GTIFFTAGTYPE_STRING},
      46             :     {"TIFFTAG_XRESOLUTION", TIFFTAG_XRESOLUTION, GTIFFTAGTYPE_FLOAT},
      47             :     {"TIFFTAG_YRESOLUTION", TIFFTAG_YRESOLUTION, GTIFFTAGTYPE_FLOAT},
      48             :     // Dealt as special case.
      49             :     {"TIFFTAG_RESOLUTIONUNIT", TIFFTAG_RESOLUTIONUNIT, GTIFFTAGTYPE_SHORT},
      50             :     {"TIFFTAG_MINSAMPLEVALUE", TIFFTAG_MINSAMPLEVALUE, GTIFFTAGTYPE_SHORT},
      51             :     {"TIFFTAG_MAXSAMPLEVALUE", TIFFTAG_MAXSAMPLEVALUE, GTIFFTAGTYPE_SHORT},
      52             : 
      53             :     // GeoTIFF DGIWG tags
      54             :     {"GEO_METADATA", TIFFTAG_GEO_METADATA, GTIFFTAGTYPE_BYTE_STRING},
      55             :     {"TIFF_RSID", TIFFTAG_TIFF_RSID, GTIFFTAGTYPE_STRING},
      56             :     {nullptr, 0, GTIFFTAGTYPE_STRING},
      57             : };
      58             : 
      59             : /************************************************************************/
      60             : /*                            GetTIFFTags()                             */
      61             : /************************************************************************/
      62             : 
      63       29912 : const GTIFFTag *GTiffDataset::GetTIFFTags()
      64             : {
      65       29912 :     return asTIFFTags;
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                            GTiffDataset()                            */
      70             : /************************************************************************/
      71             : 
      72       33331 : GTiffDataset::GTiffDataset()
      73             :     : m_bStreamingIn(false), m_bStreamingOut(false), m_bScanDeferred(true),
      74             :       m_bSingleIFDOpened(false), m_bLoadedBlockDirty(false),
      75             :       m_bWriteError(false), m_bLookedForProjection(false),
      76             :       m_bLookedForMDAreaOrPoint(false), m_bGeoTransformValid(false),
      77             :       m_bCrystalized(true), m_bGeoTIFFInfoChanged(false),
      78             :       m_bForceUnsetGTOrGCPs(false), m_bForceUnsetProjection(false),
      79             :       m_bNoDataChanged(false), m_bNoDataSet(false), m_bNoDataSetAsInt64(false),
      80             :       m_bNoDataSetAsUInt64(false), m_bMetadataChanged(false),
      81             :       m_bColorProfileMetadataChanged(false), m_bForceUnsetRPC(false),
      82             :       m_bNeedsRewrite(false), m_bLoadingOtherBands(false), m_bIsOverview(false),
      83             :       m_bWriteEmptyTiles(true), m_bFillEmptyTilesAtClosing(false),
      84             :       m_bTreatAsSplit(false), m_bTreatAsSplitBitmap(false), m_bClipWarn(false),
      85             :       m_bIMDRPCMetadataLoaded(false), m_bEXIFMetadataLoaded(false),
      86             :       m_bICCMetadataLoaded(false),
      87             :       m_bHasWarnedDisableAggressiveBandCaching(false),
      88             :       m_bDontReloadFirstBlock(false), m_bWebPLossless(false),
      89             :       m_bPromoteTo8Bits(false),
      90             :       m_bDebugDontWriteBlocks(
      91       33331 :           CPLTestBool(CPLGetConfigOption("GTIFF_DONT_WRITE_BLOCKS", "NO"))),
      92             :       m_bIsFinalized(false),
      93             :       m_bIgnoreReadErrors(
      94       33331 :           CPLTestBool(CPLGetConfigOption("GTIFF_IGNORE_READ_ERRORS", "NO"))),
      95       33331 :       m_bDirectIO(CPLTestBool(CPLGetConfigOption("GTIFF_DIRECT_IO", "NO"))),
      96             :       m_bReadGeoTransform(false), m_bLoadPam(false), m_bENVIHdrTried(false),
      97             :       m_bENVIHdrFound(false), m_bHasGotSiblingFiles(false),
      98             :       m_bHasIdentifiedAuthorizedGeoreferencingSources(false),
      99             :       m_bLayoutIFDSBeforeData(false), m_bBlockOrderRowMajor(false),
     100             :       m_bLeaderSizeAsUInt4(false), m_bTrailerRepeatedLast4BytesRepeated(false),
     101             :       m_bMaskInterleavedWithImagery(false), m_bKnownIncompatibleEdition(false),
     102             :       m_bWriteKnownIncompatibleEdition(false), m_bHasUsedReadEncodedAPI(false),
     103             :       m_bWriteCOGLayout(false), m_bTileInterleave(false),
     104       99993 :       m_bLayoutChecked(false)
     105             : {
     106             :     // CPLDebug("GDAL", "sizeof(GTiffDataset) = %d bytes", static_cast<int>(
     107             :     //     sizeof(GTiffDataset)));
     108             : 
     109             :     const char *pszVirtualMemIO =
     110       33331 :         CPLGetConfigOption("GTIFF_VIRTUAL_MEM_IO", "NO");
     111       33331 :     if (EQUAL(pszVirtualMemIO, "IF_ENOUGH_RAM"))
     112           0 :         m_eVirtualMemIOUsage = VirtualMemIOEnum::IF_ENOUGH_RAM;
     113       33331 :     else if (CPLTestBool(pszVirtualMemIO))
     114          41 :         m_eVirtualMemIOUsage = VirtualMemIOEnum::YES;
     115             : 
     116       33331 :     m_oSRS.SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     117       33331 : }
     118             : 
     119             : /************************************************************************/
     120             : /*                           ~GTiffDataset()                            */
     121             : /************************************************************************/
     122             : 
     123       64888 : GTiffDataset::~GTiffDataset()
     124             : 
     125             : {
     126       33330 :     GTiffDataset::Close();
     127       64888 : }
     128             : 
     129             : /************************************************************************/
     130             : /*                              Close()                                 */
     131             : /************************************************************************/
     132             : 
     133       59842 : CPLErr GTiffDataset::Close(GDALProgressFunc, void *)
     134             : {
     135       59842 :     if (nOpenFlags != OPEN_FLAGS_CLOSED)
     136             :     {
     137       33330 :         auto [eErr, bDroppedRef] = Finalize();
     138             : 
     139       33330 :         if (m_pszTmpFilename)
     140             :         {
     141           4 :             VSIUnlink(m_pszTmpFilename);
     142           4 :             CPLFree(m_pszTmpFilename);
     143             :         }
     144             : 
     145       33330 :         if (GDALPamDataset::Close() != CE_None)
     146           0 :             eErr = CE_Failure;
     147       33330 :         return eErr;
     148             :     }
     149       26512 :     return CE_None;
     150             : }
     151             : 
     152             : /************************************************************************/
     153             : /*                             Finalize()                               */
     154             : /************************************************************************/
     155             : 
     156             : // Return a tuple (CPLErr, bool) to indicate respectively if an I/O error has
     157             : // occurred and if a reference to an auxiliary dataset has been dropped.
     158       33392 : std::tuple<CPLErr, bool> GTiffDataset::Finalize()
     159             : {
     160       33392 :     bool bDroppedRef = false;
     161       33392 :     if (m_bIsFinalized)
     162         124 :         return std::tuple(CE_None, bDroppedRef);
     163             : 
     164       33330 :     CPLErr eErr = CE_None;
     165       33330 :     Crystalize();
     166             : 
     167       33330 :     if (m_bColorProfileMetadataChanged)
     168             :     {
     169           2 :         SaveICCProfile(this, nullptr, nullptr, 0);
     170           2 :         m_bColorProfileMetadataChanged = false;
     171             :     }
     172             : 
     173             :     /* -------------------------------------------------------------------- */
     174             :     /*      Handle forcing xml:ESRI data to be written to PAM.              */
     175             :     /* -------------------------------------------------------------------- */
     176       33330 :     if (CPLTestBool(CPLGetConfigOption("ESRI_XML_PAM", "NO")))
     177             :     {
     178           7 :         char **papszESRIMD = GTiffDataset::GetMetadata("xml:ESRI");
     179           7 :         if (papszESRIMD)
     180             :         {
     181           5 :             GDALPamDataset::SetMetadata(papszESRIMD, "xml:ESRI");
     182             :         }
     183             :     }
     184             : 
     185       33330 :     if (m_psVirtualMemIOMapping)
     186          11 :         CPLVirtualMemFree(m_psVirtualMemIOMapping);
     187       33330 :     m_psVirtualMemIOMapping = nullptr;
     188             : 
     189             :     /* -------------------------------------------------------------------- */
     190             :     /*      Fill in missing blocks with empty data.                         */
     191             :     /* -------------------------------------------------------------------- */
     192       33330 :     if (m_bFillEmptyTilesAtClosing)
     193             :     {
     194             :         /* --------------------------------------------------------------------
     195             :          */
     196             :         /*  Ensure any blocks write cached by GDAL gets pushed through libtiff.
     197             :          */
     198             :         /* --------------------------------------------------------------------
     199             :          */
     200        7986 :         if (FlushCacheInternal(true, /* at closing */
     201        7986 :                                false /* do not call FlushDirectory */) !=
     202             :             CE_None)
     203             :         {
     204           0 :             eErr = CE_Failure;
     205             :         }
     206             : 
     207        7986 :         if (FillEmptyTiles() != CE_None)
     208             :         {
     209           9 :             eErr = CE_Failure;
     210             :         }
     211        7986 :         m_bFillEmptyTilesAtClosing = false;
     212             :     }
     213             : 
     214             :     /* -------------------------------------------------------------------- */
     215             :     /*      Force a complete flush, including either rewriting(moving)      */
     216             :     /*      of writing in place the current directory.                      */
     217             :     /* -------------------------------------------------------------------- */
     218       33330 :     if (FlushCacheInternal(true /* at closing */, true) != CE_None)
     219             :     {
     220           7 :         eErr = CE_Failure;
     221             :     }
     222             : 
     223             :     // Destroy compression queue
     224       33330 :     if (m_poCompressQueue)
     225             :     {
     226          58 :         m_poCompressQueue->WaitCompletion();
     227             : 
     228         280 :         for (int i = 0; i < static_cast<int>(m_asCompressionJobs.size()); ++i)
     229             :         {
     230         222 :             CPLFree(m_asCompressionJobs[i].pabyBuffer);
     231         222 :             if (m_asCompressionJobs[i].pszTmpFilename)
     232             :             {
     233         222 :                 VSIUnlink(m_asCompressionJobs[i].pszTmpFilename);
     234         222 :                 CPLFree(m_asCompressionJobs[i].pszTmpFilename);
     235             :             }
     236             :         }
     237          58 :         m_poCompressQueue.reset();
     238             :     }
     239             : 
     240             :     /* -------------------------------------------------------------------- */
     241             :     /*      If there is still changed metadata, then presumably we want     */
     242             :     /*      to push it into PAM.                                            */
     243             :     /* -------------------------------------------------------------------- */
     244       33330 :     if (m_bMetadataChanged)
     245             :     {
     246           6 :         PushMetadataToPam();
     247           6 :         m_bMetadataChanged = false;
     248           6 :         GDALPamDataset::FlushCache(false);
     249             :     }
     250             : 
     251             :     /* -------------------------------------------------------------------- */
     252             :     /*      Cleanup overviews.                                              */
     253             :     /* -------------------------------------------------------------------- */
     254       33330 :     if (!m_poBaseDS)
     255             :     {
     256       31558 :         if (!m_apoOverviewDS.empty())
     257         903 :             bDroppedRef = true;
     258             :         // Move m_apoOverviewDS to a temporary variable, otherwise
     259             :         // GTiffDataset::FlushDirectory() might try to access an overview
     260             :         // that is being deleted (#5580)
     261       63116 :         auto apoTmpDS = std::move(m_apoOverviewDS);
     262       31558 :         apoTmpDS.clear();
     263             : 
     264       31558 :         if (!m_apoJPEGOverviewDS.empty())
     265          21 :             bDroppedRef = true;
     266       31558 :         m_apoJPEGOverviewDS.clear();
     267             :     }
     268             :     else
     269             :     {
     270        1772 :         m_apoOverviewDS.clear();
     271             :     }
     272             : 
     273       33330 :     if (m_poMaskDS)
     274             :     {
     275             :         // Move m_poMaskDS to a temporary variable, otherwise
     276             :         // GTiffDataset::FlushDirectory() might try to access it while being
     277             :         // deleted. (#5580)
     278         354 :         auto poTmpDS = std::move(m_poMaskDS);
     279         354 :         poTmpDS.reset();
     280         354 :         bDroppedRef = true;
     281             :     }
     282             : 
     283       33330 :     m_poColorTable.reset();
     284             : 
     285       33330 :     if (m_hTIFF)
     286             :     {
     287       33325 :         XTIFFClose(m_hTIFF);
     288       33325 :         m_hTIFF = nullptr;
     289             :     }
     290             : 
     291       33330 :     if (!m_poBaseDS)
     292             :     {
     293       31558 :         if (m_fpL != nullptr)
     294             :         {
     295       31558 :             if (m_bWriteKnownIncompatibleEdition)
     296             :             {
     297             :                 GByte abyHeader[4096];
     298          11 :                 VSIFSeekL(m_fpL, 0, SEEK_SET);
     299          11 :                 VSIFReadL(abyHeader, 1, sizeof(abyHeader), m_fpL);
     300          11 :                 const char *szKeyToLook =
     301             :                     "KNOWN_INCOMPATIBLE_EDITION=NO\n ";  // trailing space
     302             :                                                          // intended
     303        1771 :                 for (size_t i = 0; i < sizeof(abyHeader) - strlen(szKeyToLook);
     304             :                      i++)
     305             :                 {
     306        1771 :                     if (memcmp(abyHeader + i, szKeyToLook,
     307             :                                strlen(szKeyToLook)) == 0)
     308             :                     {
     309          11 :                         const char *szNewKey =
     310             :                             "KNOWN_INCOMPATIBLE_EDITION=YES\n";
     311          11 :                         CPLAssert(strlen(szKeyToLook) == strlen(szNewKey));
     312          11 :                         memcpy(abyHeader + i, szNewKey, strlen(szNewKey));
     313          11 :                         VSIFSeekL(m_fpL, 0, SEEK_SET);
     314          11 :                         VSIFWriteL(abyHeader, 1, sizeof(abyHeader), m_fpL);
     315          11 :                         break;
     316             :                     }
     317             :                 }
     318             :             }
     319             : 
     320       31558 :             if (IsMarkedSuppressOnClose())
     321         493 :                 m_fpL->CancelCreation();
     322             : 
     323       31558 :             if (VSIFCloseL(m_fpL) != 0)
     324             :             {
     325           0 :                 eErr = CE_Failure;
     326           0 :                 ReportError(CE_Failure, CPLE_FileIO, "I/O error");
     327             :             }
     328       31558 :             m_fpL = nullptr;
     329             :         }
     330             :     }
     331             : 
     332       33330 :     if (m_fpToWrite != nullptr)
     333             :     {
     334           7 :         if (VSIFCloseL(m_fpToWrite) != 0)
     335             :         {
     336           0 :             eErr = CE_Failure;
     337           0 :             ReportError(CE_Failure, CPLE_FileIO, "I/O error");
     338             :         }
     339           7 :         m_fpToWrite = nullptr;
     340             :     }
     341             : 
     342       33330 :     m_aoGCPs.clear();
     343             : 
     344       33330 :     CSLDestroy(m_papszCreationOptions);
     345       33330 :     m_papszCreationOptions = nullptr;
     346             : 
     347       33330 :     CPLFree(m_pabyTempWriteBuffer);
     348       33330 :     m_pabyTempWriteBuffer = nullptr;
     349             : 
     350       33330 :     m_bIMDRPCMetadataLoaded = false;
     351       33330 :     CSLDestroy(m_papszMetadataFiles);
     352       33330 :     m_papszMetadataFiles = nullptr;
     353             : 
     354       33330 :     VSIFree(m_pTempBufferForCommonDirectIO);
     355       33330 :     m_pTempBufferForCommonDirectIO = nullptr;
     356             : 
     357       33330 :     CPLFree(m_panMaskOffsetLsb);
     358       33330 :     m_panMaskOffsetLsb = nullptr;
     359             : 
     360       33330 :     CPLFree(m_pszVertUnit);
     361       33330 :     m_pszVertUnit = nullptr;
     362             : 
     363       33330 :     m_osFilename.clear();
     364             : 
     365       33330 :     CPLFree(m_pszGeorefFilename);
     366       33330 :     m_pszGeorefFilename = nullptr;
     367             : 
     368       33330 :     CPLFree(m_pszXMLFilename);
     369       33330 :     m_pszXMLFilename = nullptr;
     370             : 
     371       33330 :     m_bIsFinalized = true;
     372             : 
     373       33330 :     return std::tuple(eErr, bDroppedRef);
     374             : }
     375             : 
     376             : /************************************************************************/
     377             : /*                        CloseDependentDatasets()                      */
     378             : /************************************************************************/
     379             : 
     380          62 : int GTiffDataset::CloseDependentDatasets()
     381             : {
     382          62 :     if (m_poBaseDS)
     383           0 :         return FALSE;
     384             : 
     385          62 :     int bHasDroppedRef = GDALPamDataset::CloseDependentDatasets();
     386             : 
     387             :     // We ignore eErr as it is not relevant for CloseDependentDatasets(),
     388             :     // which is called in a "garbage collection" context.
     389          62 :     auto [eErr, bHasDroppedRefInFinalize] = Finalize();
     390          62 :     if (bHasDroppedRefInFinalize)
     391           1 :         bHasDroppedRef = true;
     392             : 
     393          62 :     return bHasDroppedRef;
     394             : }
     395             : 
     396             : /************************************************************************/
     397             : /*                        IsWholeBlock()                                */
     398             : /************************************************************************/
     399             : 
     400          31 : bool GTiffDataset::IsWholeBlock(int nXOff, int nYOff, int nXSize,
     401             :                                 int nYSize) const
     402             : {
     403          31 :     if ((nXOff % m_nBlockXSize) != 0 || (nYOff % m_nBlockYSize) != 0)
     404             :     {
     405           0 :         return false;
     406             :     }
     407          31 :     if (TIFFIsTiled(m_hTIFF))
     408             :     {
     409           3 :         return nXSize == m_nBlockXSize && nYSize == m_nBlockYSize;
     410             :     }
     411             :     else
     412             :     {
     413          54 :         return nXSize == m_nBlockXSize &&
     414          54 :                (nYSize == m_nBlockYSize || nYOff + nYSize == nRasterYSize);
     415             :     }
     416             : }
     417             : 
     418             : /************************************************************************/
     419             : /*                            IRasterIO()                               */
     420             : /************************************************************************/
     421             : 
     422      437164 : CPLErr GTiffDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
     423             :                                int nXSize, int nYSize, void *pData,
     424             :                                int nBufXSize, int nBufYSize,
     425             :                                GDALDataType eBufType, int nBandCount,
     426             :                                BANDMAP_TYPE panBandMap, GSpacing nPixelSpace,
     427             :                                GSpacing nLineSpace, GSpacing nBandSpace,
     428             :                                GDALRasterIOExtraArg *psExtraArg)
     429             : 
     430             : {
     431             :     // Try to pass the request to the most appropriate overview dataset.
     432      437164 :     if (nBufXSize < nXSize && nBufYSize < nYSize)
     433             :     {
     434      157850 :         int bTried = FALSE;
     435      157850 :         if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     436      157698 :             ++m_nJPEGOverviewVisibilityCounter;
     437      157850 :         const CPLErr eErr = TryOverviewRasterIO(
     438             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     439             :             eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
     440             :             nBandSpace, psExtraArg, &bTried);
     441      157850 :         if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     442      157698 :             --m_nJPEGOverviewVisibilityCounter;
     443      157850 :         if (bTried)
     444          22 :             return eErr;
     445             :     }
     446             : 
     447      437142 :     if (m_eVirtualMemIOUsage != VirtualMemIOEnum::NO)
     448             :     {
     449             :         const int nErr =
     450         649 :             VirtualMemIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
     451             :                          nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap,
     452             :                          nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
     453         649 :         if (nErr >= 0)
     454         608 :             return static_cast<CPLErr>(nErr);
     455             :     }
     456      436534 :     if (m_bDirectIO)
     457             :     {
     458             :         const int nErr =
     459         471 :             DirectIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize,
     460             :                      nBufYSize, eBufType, nBandCount, panBandMap, nPixelSpace,
     461             :                      nLineSpace, nBandSpace, psExtraArg);
     462         471 :         if (nErr >= 0)
     463         414 :             return static_cast<CPLErr>(nErr);
     464             :     }
     465             : 
     466      436120 :     bool bCanUseMultiThreadedRead = false;
     467      436120 :     if (m_nDisableMultiThreadedRead == 0 && m_poThreadPool &&
     468      872388 :         eRWFlag == GF_Read && nBufXSize == nXSize && nBufYSize == nYSize &&
     469         148 :         IsMultiThreadedReadCompatible())
     470             :     {
     471         148 :         const int nBlockX1 = nXOff / m_nBlockXSize;
     472         148 :         const int nBlockY1 = nYOff / m_nBlockYSize;
     473         148 :         const int nBlockX2 = (nXOff + nXSize - 1) / m_nBlockXSize;
     474         148 :         const int nBlockY2 = (nYOff + nYSize - 1) / m_nBlockYSize;
     475         148 :         const int nXBlocks = nBlockX2 - nBlockX1 + 1;
     476         148 :         const int nYBlocks = nBlockY2 - nBlockY1 + 1;
     477         148 :         const size_t nBlocks =
     478         148 :             static_cast<size_t>(nXBlocks) * nYBlocks *
     479         148 :             (m_nPlanarConfig == PLANARCONFIG_CONTIG ? 1 : nBandCount);
     480         148 :         if (nBlocks > 1)
     481             :         {
     482         145 :             bCanUseMultiThreadedRead = true;
     483             :         }
     484             :     }
     485             : 
     486      436120 :     void *pBufferedData = nullptr;
     487      436120 :     const auto poFirstBand = cpl::down_cast<GTiffRasterBand *>(papoBands[0]);
     488      436120 :     const auto eDataType = poFirstBand->GetRasterDataType();
     489             : 
     490       37796 :     if (eAccess == GA_ReadOnly && eRWFlag == GF_Read &&
     491      473934 :         HasOptimizedReadMultiRange() &&
     492          18 :         !(bCanUseMultiThreadedRead &&
     493           4 :           VSI_TIFFGetVSILFile(TIFFClientdata(m_hTIFF))->HasPRead()))
     494             :     {
     495          14 :         if (nBands == 1 || m_nPlanarConfig == PLANARCONFIG_CONTIG)
     496             :         {
     497          12 :             const int nBandOne = 1;
     498             :             pBufferedData =
     499          12 :                 CacheMultiRange(nXOff, nYOff, nXSize, nYSize, nBufXSize,
     500          12 :                                 nBufYSize, &nBandOne, 1, psExtraArg);
     501             :         }
     502             :         else
     503             :         {
     504             :             pBufferedData =
     505           2 :                 CacheMultiRange(nXOff, nYOff, nXSize, nYSize, nBufXSize,
     506             :                                 nBufYSize, panBandMap, nBandCount, psExtraArg);
     507             :         }
     508             :     }
     509      436106 :     else if (bCanUseMultiThreadedRead)
     510             :     {
     511         145 :         return MultiThreadedRead(nXOff, nYOff, nXSize, nYSize, pData, eBufType,
     512             :                                  nBandCount, panBandMap, nPixelSpace,
     513         145 :                                  nLineSpace, nBandSpace);
     514             :     }
     515             : 
     516             :     // Write optimization when writing whole blocks, by-passing the block cache.
     517             :     // We require the block cache to be non instantiated to simplify things
     518             :     // (otherwise we might need to evict corresponding existing blocks from the
     519             :     // block cache).
     520      204808 :     else if (eRWFlag == GF_Write && nBands > 1 &&
     521       30585 :              m_nPlanarConfig == PLANARCONFIG_CONTIG &&
     522             :              // Could be extended to "odd bit" case, but more work
     523       27485 :              m_nBitsPerSample == GDALGetDataTypeSizeBits(eDataType) &&
     524       27474 :              nXSize == nBufXSize && nYSize == nBufYSize &&
     525       27472 :              nBandCount == nBands && !m_bLoadedBlockDirty &&
     526       27450 :              (nXOff % m_nBlockXSize) == 0 && (nYOff % m_nBlockYSize) == 0 &&
     527        1707 :              (nXOff + nXSize == nRasterXSize ||
     528      640809 :               (nXSize % m_nBlockXSize) == 0) &&
     529        1704 :              (nYOff + nYSize == nRasterYSize || (nYSize % m_nBlockYSize) == 0))
     530             :     {
     531        1582 :         bool bOptimOK = true;
     532        1582 :         bool bOrderedBands = true;
     533        6581 :         for (int i = 0; i < nBands; ++i)
     534             :         {
     535        5033 :             if (panBandMap[i] != i + 1)
     536             :             {
     537          26 :                 bOrderedBands = false;
     538             :             }
     539       10066 :             if (cpl::down_cast<GTiffRasterBand *>(papoBands[panBandMap[i] - 1])
     540        5033 :                     ->HasBlockCache())
     541             :             {
     542          34 :                 bOptimOK = false;
     543          34 :                 break;
     544             :             }
     545             :         }
     546        1582 :         if (bOptimOK)
     547             :         {
     548        1548 :             Crystalize();
     549             : 
     550        1548 :             if (m_bDebugDontWriteBlocks)
     551           0 :                 return CE_None;
     552             : 
     553        1548 :             const int nDTSize = GDALGetDataTypeSizeBytes(eDataType);
     554        1548 :             if (bOrderedBands && nXSize == m_nBlockXSize &&
     555        1346 :                 nYSize == m_nBlockYSize && eBufType == eDataType &&
     556        1169 :                 nBandSpace == nDTSize &&
     557          15 :                 nPixelSpace == static_cast<GSpacing>(nDTSize) * nBands &&
     558           5 :                 nLineSpace == nPixelSpace * m_nBlockXSize)
     559             :             {
     560             :                 // If writing one single block with the right data type and
     561             :                 // layout (interleaved per pixel), we don't need a temporary
     562             :                 // buffer
     563          10 :                 const int nBlockId = poFirstBand->ComputeBlockId(
     564           5 :                     nXOff / m_nBlockXSize, nYOff / m_nBlockYSize);
     565           5 :                 return WriteEncodedTileOrStrip(nBlockId, pData,
     566           5 :                                                /* bPreserveDataBuffer= */ true);
     567             :             }
     568             : 
     569             :             // Make sure m_poGDS->m_pabyBlockBuf is allocated.
     570             :             // We could actually use any temporary buffer
     571        1543 :             if (LoadBlockBuf(/* nBlockId = */ -1,
     572        1543 :                              /* bReadFromDisk = */ false) != CE_None)
     573             :             {
     574           0 :                 return CE_Failure;
     575             :             }
     576             : 
     577             :             // Iterate over all blocks defined by
     578             :             // [nXOff, nXOff+nXSize[ * [nYOff, nYOff+nYSize[
     579             :             // and write their content as a nBlockXSize x nBlockYSize strile
     580             :             // in a temporary buffer, before calling WriteEncodedTileOrStrip()
     581             :             // on it
     582        1543 :             const int nYBlockStart = nYOff / m_nBlockYSize;
     583        1543 :             const int nYBlockEnd = 1 + (nYOff + nYSize - 1) / m_nBlockYSize;
     584        1543 :             const int nXBlockStart = nXOff / m_nBlockXSize;
     585        1543 :             const int nXBlockEnd = 1 + (nXOff + nXSize - 1) / m_nBlockXSize;
     586       17770 :             for (int nYBlock = nYBlockStart; nYBlock < nYBlockEnd; ++nYBlock)
     587             :             {
     588             :                 const int nValidY = std::min(
     589       16231 :                     m_nBlockYSize, nRasterYSize - nYBlock * m_nBlockYSize);
     590       34739 :                 for (int nXBlock = nXBlockStart; nXBlock < nXBlockEnd;
     591             :                      ++nXBlock)
     592             :                 {
     593             :                     const int nValidX = std::min(
     594       18512 :                         m_nBlockXSize, nRasterXSize - nXBlock * m_nBlockXSize);
     595       18512 :                     if (nValidY < m_nBlockYSize || nValidX < m_nBlockXSize)
     596             :                     {
     597             :                         // Make sure padding bytes at the right/bottom of the
     598             :                         // tile are initialized to zero.
     599         334 :                         memset(m_pabyBlockBuf, 0,
     600         334 :                                static_cast<size_t>(m_nBlockXSize) *
     601         334 :                                    m_nBlockYSize * nBands * nDTSize);
     602             :                     }
     603       18512 :                     const auto nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
     604       18512 :                     const GByte *pabySrcData =
     605             :                         static_cast<const GByte *>(pData) +
     606       18512 :                         static_cast<size_t>(nYBlock - nYBlockStart) *
     607       18512 :                             m_nBlockYSize * nLineSpace +
     608       18512 :                         static_cast<size_t>(nXBlock - nXBlockStart) *
     609       18512 :                             m_nBlockXSize * nPixelSpace;
     610       18512 :                     if (bOrderedBands && nBandSpace == nBufDTSize &&
     611          16 :                         nPixelSpace == nBands * nBandSpace)
     612             :                     {
     613             :                         // Input buffer is pixel interleaved
     614          17 :                         for (int iY = 0; iY < nValidY; ++iY)
     615             :                         {
     616          16 :                             GDALCopyWords64(
     617          16 :                                 pabySrcData +
     618          16 :                                     static_cast<size_t>(iY) * nLineSpace,
     619             :                                 eBufType, nBufDTSize,
     620          16 :                                 m_pabyBlockBuf + static_cast<size_t>(iY) *
     621          16 :                                                      m_nBlockXSize * nBands *
     622          16 :                                                      nDTSize,
     623             :                                 eDataType, nDTSize,
     624          16 :                                 static_cast<GPtrDiff_t>(nValidX) * nBands);
     625           1 :                         }
     626             :                     }
     627             :                     else
     628             :                     {
     629             :                         // "Random" spacing for input buffer
     630       75912 :                         for (int iBand = 0; iBand < nBands; ++iBand)
     631             :                         {
     632     1751570 :                             for (int iY = 0; iY < nValidY; ++iY)
     633             :                             {
     634     1694160 :                                 GDALCopyWords64(
     635     1694160 :                                     pabySrcData +
     636     1694160 :                                         static_cast<size_t>(iY) * nLineSpace,
     637             :                                     eBufType, static_cast<int>(nPixelSpace),
     638     1694160 :                                     m_pabyBlockBuf +
     639     1694160 :                                         (panBandMap[iBand] - 1 +
     640     1694160 :                                          static_cast<size_t>(iY) *
     641     1694160 :                                              m_nBlockXSize * nBands) *
     642     1694160 :                                             nDTSize,
     643     1694160 :                                     eDataType, nDTSize * nBands, nValidX);
     644             :                             }
     645       57401 :                             pabySrcData += nBandSpace;
     646             :                         }
     647             :                     }
     648             : 
     649             :                     const int nBlockId =
     650       18512 :                         poFirstBand->ComputeBlockId(nXBlock, nYBlock);
     651       37024 :                     if (WriteEncodedTileOrStrip(
     652       18512 :                             nBlockId, m_pabyBlockBuf,
     653       18512 :                             /* bPreserveDataBuffer= */ false) != CE_None)
     654             :                     {
     655           4 :                         return CE_Failure;
     656             :                     }
     657             :                 }
     658             :             }
     659        1539 :             return CE_None;
     660             :         }
     661             :     }
     662             : 
     663      434427 :     if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     664      434267 :         ++m_nJPEGOverviewVisibilityCounter;
     665      434427 :     const CPLErr eErr = GDALPamDataset::IRasterIO(
     666             :         eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
     667             :         eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace, nBandSpace,
     668             :         psExtraArg);
     669      434427 :     if (psExtraArg->eResampleAlg == GRIORA_NearestNeighbour)
     670      434267 :         m_nJPEGOverviewVisibilityCounter--;
     671             : 
     672      434427 :     if (pBufferedData)
     673             :     {
     674           8 :         VSIFree(pBufferedData);
     675           8 :         VSI_TIFFSetCachedRanges(TIFFClientdata(m_hTIFF), 0, nullptr, nullptr,
     676             :                                 nullptr);
     677             :     }
     678             : 
     679      434427 :     return eErr;
     680             : }
     681             : 
     682             : /************************************************************************/
     683             : /*                       GetGTIFFKeysFlavor()                           */
     684             : /************************************************************************/
     685             : 
     686       33170 : GTIFFKeysFlavorEnum GetGTIFFKeysFlavor(CSLConstList papszOptions)
     687             : {
     688             :     const char *pszGeoTIFFKeysFlavor =
     689       33170 :         CSLFetchNameValueDef(papszOptions, "GEOTIFF_KEYS_FLAVOR", "STANDARD");
     690       33170 :     if (EQUAL(pszGeoTIFFKeysFlavor, "ESRI_PE"))
     691           1 :         return GEOTIFF_KEYS_ESRI_PE;
     692       33169 :     return GEOTIFF_KEYS_STANDARD;
     693             : }
     694             : 
     695             : /************************************************************************/
     696             : /*                       GetGeoTIFFVersion()                            */
     697             : /************************************************************************/
     698             : 
     699       33170 : GeoTIFFVersionEnum GetGeoTIFFVersion(CSLConstList papszOptions)
     700             : {
     701             :     const char *pszVersion =
     702       33170 :         CSLFetchNameValueDef(papszOptions, "GEOTIFF_VERSION", "AUTO");
     703       33170 :     if (EQUAL(pszVersion, "1.0"))
     704           3 :         return GEOTIFF_VERSION_1_0;
     705       33167 :     if (EQUAL(pszVersion, "1.1"))
     706           5 :         return GEOTIFF_VERSION_1_1;
     707       33162 :     return GEOTIFF_VERSION_AUTO;
     708             : }
     709             : 
     710             : /************************************************************************/
     711             : /*                      InitCreationOrOpenOptions()                     */
     712             : /************************************************************************/
     713             : 
     714       31524 : void GTiffDataset::InitCreationOrOpenOptions(bool bUpdateMode,
     715             :                                              CSLConstList papszOptions)
     716             : {
     717       31524 :     InitCompressionThreads(bUpdateMode, papszOptions);
     718             : 
     719       31524 :     m_eGeoTIFFKeysFlavor = GetGTIFFKeysFlavor(papszOptions);
     720       31524 :     m_eGeoTIFFVersion = GetGeoTIFFVersion(papszOptions);
     721       31524 : }
     722             : 
     723             : /************************************************************************/
     724             : /*                          IsBlockAvailable()                          */
     725             : /*                                                                      */
     726             : /*      Return true if the indicated strip/tile is available.  We       */
     727             : /*      establish this by testing if the stripbytecount is zero.  If    */
     728             : /*      zero then the block has never been committed to disk.           */
     729             : /************************************************************************/
     730             : 
     731     2317900 : bool GTiffDataset::IsBlockAvailable(int nBlockId, vsi_l_offset *pnOffset,
     732             :                                     vsi_l_offset *pnSize, bool *pbErrOccurred)
     733             : 
     734             : {
     735     2317900 :     if (pbErrOccurred)
     736     2259210 :         *pbErrOccurred = false;
     737             : 
     738     2317900 :     std::pair<vsi_l_offset, vsi_l_offset> oPair;
     739     2317900 :     if (m_oCacheStrileToOffsetByteCount.tryGet(nBlockId, oPair))
     740             :     {
     741         449 :         if (pnOffset)
     742         110 :             *pnOffset = oPair.first;
     743         449 :         if (pnSize)
     744           0 :             *pnSize = oPair.second;
     745         449 :         return oPair.first != 0;
     746             :     }
     747             : 
     748     2317460 :     WaitCompletionForBlock(nBlockId);
     749             : 
     750             :     // Optimization to avoid fetching the whole Strip/TileCounts and
     751             :     // Strip/TileOffsets arrays.
     752     2317460 :     if (eAccess == GA_ReadOnly && !m_bStreamingIn)
     753             :     {
     754     2184130 :         int nErrOccurred = 0;
     755             :         auto bytecount =
     756     2184130 :             TIFFGetStrileByteCountWithErr(m_hTIFF, nBlockId, &nErrOccurred);
     757     2184130 :         if (nErrOccurred && pbErrOccurred)
     758           1 :             *pbErrOccurred = true;
     759     2184130 :         if (pnOffset)
     760             :         {
     761     2140440 :             *pnOffset =
     762     2140440 :                 TIFFGetStrileOffsetWithErr(m_hTIFF, nBlockId, &nErrOccurred);
     763     2140440 :             if (nErrOccurred && pbErrOccurred)
     764           3 :                 *pbErrOccurred = true;
     765             :         }
     766     2184130 :         if (pnSize)
     767       12156 :             *pnSize = bytecount;
     768     2184130 :         return bytecount != 0;
     769             :     }
     770             : 
     771      133329 :     if (!m_bCrystalized)
     772             :     {
     773             :         // If this is a fresh new file not yet crystalized, do not try to
     774             :         // read the [Strip|Tile][ByteCounts|Offsets] tags as they do not yet
     775             :         // exist. Trying would set *pbErrOccurred=true, which is not desirable.
     776           2 :         if (pnOffset)
     777           2 :             *pnOffset = 0;
     778           2 :         if (pnSize)
     779           2 :             *pnSize = 0;
     780           2 :         return false;
     781             :     }
     782             : 
     783      133327 :     toff_t *panByteCounts = nullptr;
     784      133327 :     toff_t *panOffsets = nullptr;
     785      133327 :     const bool bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
     786             : 
     787      167351 :     if ((bIsTiled &&
     788       34024 :          TIFFGetField(m_hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts) &&
     789       25873 :          (pnOffset == nullptr ||
     790      266654 :           TIFFGetField(m_hTIFF, TIFFTAG_TILEOFFSETS, &panOffsets))) ||
     791       99303 :         (!bIsTiled &&
     792       99303 :          TIFFGetField(m_hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts) &&
     793       49831 :          (pnOffset == nullptr ||
     794       49831 :           TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panOffsets))))
     795             :     {
     796      133327 :         if (panByteCounts == nullptr ||
     797       75704 :             (pnOffset != nullptr && panOffsets == nullptr))
     798             :         {
     799           0 :             if (pbErrOccurred)
     800           0 :                 *pbErrOccurred = true;
     801           0 :             return false;
     802             :         }
     803             :         const int nBlockCount =
     804      133327 :             bIsTiled ? TIFFNumberOfTiles(m_hTIFF) : TIFFNumberOfStrips(m_hTIFF);
     805      133327 :         if (nBlockId >= nBlockCount)
     806             :         {
     807           0 :             if (pbErrOccurred)
     808           0 :                 *pbErrOccurred = true;
     809           0 :             return false;
     810             :         }
     811             : 
     812      133327 :         if (pnOffset)
     813       75704 :             *pnOffset = panOffsets[nBlockId];
     814      133327 :         if (pnSize)
     815       15650 :             *pnSize = panByteCounts[nBlockId];
     816      133327 :         return panByteCounts[nBlockId] != 0;
     817             :     }
     818             :     else
     819             :     {
     820           0 :         if (pbErrOccurred)
     821           0 :             *pbErrOccurred = true;
     822             :     }
     823             : 
     824           0 :     return false;
     825             : }
     826             : 
     827             : /************************************************************************/
     828             : /*                           ReloadDirectory()                          */
     829             : /************************************************************************/
     830             : 
     831        8033 : void GTiffDataset::ReloadDirectory(bool bReopenHandle)
     832             : {
     833        8033 :     bool bNeedSetInvalidDir = true;
     834        8033 :     if (bReopenHandle)
     835             :     {
     836             :         // When issuing a TIFFRewriteDirectory() or when a TIFFFlush() has
     837             :         // caused a move of the directory, we would need to invalidate the
     838             :         // tif_lastdiroff member, but it is not possible to do so without
     839             :         // re-opening the TIFF handle.
     840          10 :         auto hTIFFNew = VSI_TIFFReOpen(m_hTIFF);
     841          10 :         if (hTIFFNew != nullptr)
     842             :         {
     843          10 :             m_hTIFF = hTIFFNew;
     844          10 :             bNeedSetInvalidDir = false;  // we could do it, but not needed
     845             :         }
     846             :         else
     847             :         {
     848           0 :             CPLError(CE_Failure, CPLE_AppDefined,
     849             :                      "Cannot re-open TIFF handle for file %s. "
     850             :                      "Directory chaining may be corrupted !",
     851             :                      m_osFilename.c_str());
     852             :         }
     853             :     }
     854        8033 :     if (bNeedSetInvalidDir)
     855             :     {
     856        8023 :         TIFFSetSubDirectory(m_hTIFF, 0);
     857             :     }
     858        8033 :     CPL_IGNORE_RET_VAL(SetDirectory());
     859        8033 : }
     860             : 
     861             : /************************************************************************/
     862             : /*                            SetDirectory()                            */
     863             : /************************************************************************/
     864             : 
     865       57185 : bool GTiffDataset::SetDirectory()
     866             : 
     867             : {
     868       57185 :     Crystalize();
     869             : 
     870       57185 :     if (TIFFCurrentDirOffset(m_hTIFF) == m_nDirOffset)
     871             :     {
     872       47378 :         return true;
     873             :     }
     874             : 
     875        9807 :     const int nSetDirResult = TIFFSetSubDirectory(m_hTIFF, m_nDirOffset);
     876        9807 :     if (!nSetDirResult)
     877           0 :         return false;
     878             : 
     879        9807 :     RestoreVolatileParameters(m_hTIFF);
     880             : 
     881        9807 :     return true;
     882             : }
     883             : 
     884             : /************************************************************************/
     885             : /*                     GTiffSetDeflateSubCodec()                        */
     886             : /************************************************************************/
     887             : 
     888        6478 : void GTiffSetDeflateSubCodec(TIFF *hTIFF)
     889             : {
     890             :     (void)hTIFF;
     891             : 
     892             : #if defined(TIFFTAG_DEFLATE_SUBCODEC) && defined(LIBDEFLATE_SUPPORT)
     893             :     // Mostly for strict reproducibility purposes
     894        6478 :     if (EQUAL(CPLGetConfigOption("GDAL_TIFF_DEFLATE_SUBCODEC", ""), "ZLIB"))
     895             :     {
     896        4097 :         TIFFSetField(hTIFF, TIFFTAG_DEFLATE_SUBCODEC, DEFLATE_SUBCODEC_ZLIB);
     897             :     }
     898             : #endif
     899        6478 : }
     900             : 
     901             : /************************************************************************/
     902             : /*                     RestoreVolatileParameters()                      */
     903             : /************************************************************************/
     904             : 
     905       45088 : void GTiffDataset::RestoreVolatileParameters(TIFF *hTIFF)
     906             : {
     907             : 
     908             :     /* -------------------------------------------------------------------- */
     909             :     /*      YCbCr JPEG compressed images should be translated on the fly    */
     910             :     /*      to RGB by libtiff/libjpeg unless specifically requested         */
     911             :     /*      otherwise.                                                      */
     912             :     /* -------------------------------------------------------------------- */
     913       90599 :     if (m_nCompression == COMPRESSION_JPEG &&
     914       45367 :         m_nPhotometric == PHOTOMETRIC_YCBCR &&
     915         279 :         CPLTestBool(CPLGetConfigOption("CONVERT_YCBCR_TO_RGB", "YES")))
     916             :     {
     917         279 :         int nColorMode = JPEGCOLORMODE_RAW;  // Initialize to 0;
     918             : 
     919         279 :         TIFFGetField(hTIFF, TIFFTAG_JPEGCOLORMODE, &nColorMode);
     920         279 :         if (nColorMode != JPEGCOLORMODE_RGB)
     921             :         {
     922         249 :             TIFFSetField(hTIFF, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
     923             :         }
     924             :     }
     925             : 
     926       45088 :     if (m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
     927       39226 :         m_nCompression == COMPRESSION_LERC)
     928             :     {
     929        6099 :         GTiffSetDeflateSubCodec(hTIFF);
     930             :     }
     931             : 
     932             :     /* -------------------------------------------------------------------- */
     933             :     /*      Propagate any quality settings.                                 */
     934             :     /* -------------------------------------------------------------------- */
     935       45088 :     if (eAccess == GA_Update)
     936             :     {
     937             :         // Now, reset zip and jpeg quality.
     938       37859 :         if (m_nJpegQuality > 0 && m_nCompression == COMPRESSION_JPEG)
     939             :         {
     940             : #ifdef DEBUG_VERBOSE
     941             :             CPLDebug("GTiff", "Propagate JPEG_QUALITY(%d) in SetDirectory()",
     942             :                      m_nJpegQuality);
     943             : #endif
     944         179 :             TIFFSetField(hTIFF, TIFFTAG_JPEGQUALITY, m_nJpegQuality);
     945             :         }
     946       37859 :         if (m_nJpegTablesMode >= 0 && m_nCompression == COMPRESSION_JPEG)
     947         320 :             TIFFSetField(hTIFF, TIFFTAG_JPEGTABLESMODE, m_nJpegTablesMode);
     948       37859 :         if (m_nZLevel > 0 && (m_nCompression == COMPRESSION_ADOBE_DEFLATE ||
     949          12 :                               m_nCompression == COMPRESSION_LERC))
     950          26 :             TIFFSetField(hTIFF, TIFFTAG_ZIPQUALITY, m_nZLevel);
     951       37859 :         if (m_nLZMAPreset > 0 && m_nCompression == COMPRESSION_LZMA)
     952           8 :             TIFFSetField(hTIFF, TIFFTAG_LZMAPRESET, m_nLZMAPreset);
     953       37859 :         if (m_nZSTDLevel > 0 && (m_nCompression == COMPRESSION_ZSTD ||
     954          12 :                                  m_nCompression == COMPRESSION_LERC))
     955          18 :             TIFFSetField(hTIFF, TIFFTAG_ZSTD_LEVEL, m_nZSTDLevel);
     956       37859 :         if (m_nCompression == COMPRESSION_LERC)
     957             :         {
     958         185 :             TIFFSetField(hTIFF, TIFFTAG_LERC_MAXZERROR, m_dfMaxZError);
     959             :         }
     960       37859 :         if (m_nWebPLevel > 0 && m_nCompression == COMPRESSION_WEBP)
     961         124 :             TIFFSetField(hTIFF, TIFFTAG_WEBP_LEVEL, m_nWebPLevel);
     962       37859 :         if (m_bWebPLossless && m_nCompression == COMPRESSION_WEBP)
     963          50 :             TIFFSetField(hTIFF, TIFFTAG_WEBP_LOSSLESS, 1);
     964             : #ifdef HAVE_JXL
     965       37859 :         if (m_nCompression == COMPRESSION_JXL ||
     966       37859 :             m_nCompression == COMPRESSION_JXL_DNG_1_7)
     967             :         {
     968          76 :             TIFFSetField(hTIFF, TIFFTAG_JXL_LOSSYNESS,
     969          76 :                          m_bJXLLossless ? JXL_LOSSLESS : JXL_LOSSY);
     970          76 :             TIFFSetField(hTIFF, TIFFTAG_JXL_EFFORT, m_nJXLEffort);
     971          76 :             TIFFSetField(hTIFF, TIFFTAG_JXL_DISTANCE,
     972          76 :                          static_cast<double>(m_fJXLDistance));
     973          76 :             TIFFSetField(hTIFF, TIFFTAG_JXL_ALPHA_DISTANCE,
     974          76 :                          static_cast<double>(m_fJXLAlphaDistance));
     975             :         }
     976             : #endif
     977             :     }
     978       45088 : }
     979             : 
     980             : /************************************************************************/
     981             : /*                     ComputeBlocksPerColRowAndBand()                  */
     982             : /************************************************************************/
     983             : 
     984       33319 : bool GTiffDataset::ComputeBlocksPerColRowAndBand(int l_nBands)
     985             : {
     986       33319 :     m_nBlocksPerColumn = DIV_ROUND_UP(nRasterYSize, m_nBlockYSize);
     987       33319 :     m_nBlocksPerRow = DIV_ROUND_UP(nRasterXSize, m_nBlockXSize);
     988       33319 :     if (m_nBlocksPerColumn > INT_MAX / m_nBlocksPerRow)
     989             :     {
     990           1 :         ReportError(CE_Failure, CPLE_AppDefined, "Too many blocks: %d x %d",
     991             :                     m_nBlocksPerRow, m_nBlocksPerColumn);
     992           1 :         return false;
     993             :     }
     994             : 
     995             :     // Note: we could potentially go up to UINT_MAX blocks, but currently
     996             :     // we use a int nBlockId
     997       33318 :     m_nBlocksPerBand = m_nBlocksPerColumn * m_nBlocksPerRow;
     998       33318 :     if (m_nPlanarConfig == PLANARCONFIG_SEPARATE &&
     999        4175 :         m_nBlocksPerBand > INT_MAX / l_nBands)
    1000             :     {
    1001           1 :         ReportError(CE_Failure, CPLE_AppDefined,
    1002             :                     "Too many blocks: %d x %d x %d bands", m_nBlocksPerRow,
    1003             :                     m_nBlocksPerColumn, l_nBands);
    1004           1 :         return false;
    1005             :     }
    1006       33317 :     return true;
    1007             : }
    1008             : 
    1009             : /************************************************************************/
    1010             : /*                   SetStructuralMDFromParent()                        */
    1011             : /************************************************************************/
    1012             : 
    1013        1121 : void GTiffDataset::SetStructuralMDFromParent(GTiffDataset *poParentDS)
    1014             : {
    1015        1121 :     m_bBlockOrderRowMajor = poParentDS->m_bBlockOrderRowMajor;
    1016        1121 :     m_bLeaderSizeAsUInt4 = poParentDS->m_bLeaderSizeAsUInt4;
    1017        1121 :     m_bTrailerRepeatedLast4BytesRepeated =
    1018        1121 :         poParentDS->m_bTrailerRepeatedLast4BytesRepeated;
    1019        1121 :     m_bMaskInterleavedWithImagery = poParentDS->m_bMaskInterleavedWithImagery;
    1020        1121 :     m_bWriteEmptyTiles = poParentDS->m_bWriteEmptyTiles;
    1021        1121 :     m_bTileInterleave = poParentDS->m_bTileInterleave;
    1022        1121 : }
    1023             : 
    1024             : /************************************************************************/
    1025             : /*                          ScanDirectories()                           */
    1026             : /*                                                                      */
    1027             : /*      Scan through all the directories finding overviews, masks       */
    1028             : /*      and subdatasets.                                                */
    1029             : /************************************************************************/
    1030             : 
    1031     1536960 : void GTiffDataset::ScanDirectories()
    1032             : 
    1033             : {
    1034             :     /* -------------------------------------------------------------------- */
    1035             :     /*      We only scan once.  We do not scan for non-base datasets.       */
    1036             :     /* -------------------------------------------------------------------- */
    1037     1536960 :     if (!m_bScanDeferred)
    1038     1529620 :         return;
    1039             : 
    1040        7666 :     m_bScanDeferred = false;
    1041             : 
    1042        7666 :     if (m_poBaseDS)
    1043         323 :         return;
    1044             : 
    1045        7343 :     Crystalize();
    1046             : 
    1047        7343 :     CPLDebug("GTiff", "ScanDirectories()");
    1048             : 
    1049             :     /* ==================================================================== */
    1050             :     /*      Scan all directories.                                           */
    1051             :     /* ==================================================================== */
    1052       14686 :     CPLStringList aosSubdatasets;
    1053        7343 :     int iDirIndex = 0;
    1054             : 
    1055        7343 :     FlushDirectory();
    1056             : 
    1057        1109 :     do
    1058             :     {
    1059        8452 :         toff_t nTopDir = TIFFCurrentDirOffset(m_hTIFF);
    1060        8452 :         uint32_t nSubType = 0;
    1061             : 
    1062        8452 :         ++iDirIndex;
    1063             : 
    1064        8452 :         toff_t *tmpSubIFDOffsets = nullptr;
    1065        8452 :         toff_t *subIFDOffsets = nullptr;
    1066        8452 :         uint16_t nSubIFDs = 0;
    1067        8452 :         if (TIFFGetField(m_hTIFF, TIFFTAG_SUBIFD, &nSubIFDs,
    1068        8452 :                          &tmpSubIFDOffsets) &&
    1069             :             iDirIndex == 1)
    1070             :         {
    1071             :             subIFDOffsets =
    1072          14 :                 static_cast<toff_t *>(CPLMalloc(nSubIFDs * sizeof(toff_t)));
    1073          72 :             for (uint16_t iSubIFD = 0; iSubIFD < nSubIFDs; iSubIFD++)
    1074             :             {
    1075          58 :                 subIFDOffsets[iSubIFD] = tmpSubIFDOffsets[iSubIFD];
    1076             :             }
    1077             :         }
    1078             : 
    1079             :         // early break for backwards compatibility: if the first directory read
    1080             :         // is also the last, and there are no subIFDs, no use continuing
    1081        8452 :         if (iDirIndex == 1 && nSubIFDs == 0 && TIFFLastDirectory(m_hTIFF))
    1082             :         {
    1083        6683 :             CPLFree(subIFDOffsets);
    1084        6683 :             break;
    1085             :         }
    1086             : 
    1087        3570 :         for (uint16_t iSubIFD = 0; iSubIFD <= nSubIFDs; iSubIFD++)
    1088             :         {
    1089        1810 :             toff_t nThisDir = nTopDir;
    1090        1810 :             if (iSubIFD > 0 && iDirIndex > 1)  // don't read subIFDs if we are
    1091             :                                                // not in the original directory
    1092           8 :                 break;
    1093        1802 :             if (iSubIFD > 0)
    1094             :             {
    1095             :                 // make static analyzer happy. subIFDOffsets cannot be null if
    1096             :                 // iSubIFD>0
    1097          33 :                 assert(subIFDOffsets != nullptr);
    1098          33 :                 nThisDir = subIFDOffsets[iSubIFD - 1];
    1099             :                 // CPLDebug("GTiff", "Opened subIFD %d/%d at offset %llu.",
    1100             :                 // iSubIFD, nSubIFDs, nThisDir);
    1101          33 :                 if (!TIFFSetSubDirectory(m_hTIFF, nThisDir))
    1102           1 :                     break;
    1103             :             }
    1104             : 
    1105        1801 :             if (!TIFFGetField(m_hTIFF, TIFFTAG_SUBFILETYPE, &nSubType))
    1106         434 :                 nSubType = 0;
    1107             : 
    1108             :             /* Embedded overview of the main image */
    1109        4856 :             if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
    1110        1254 :                 (nSubType & FILETYPE_MASK) == 0 &&
    1111        3964 :                 ((nSubIFDs == 0 && iDirIndex != 1) || iSubIFD > 0) &&
    1112         909 :                 m_apoOverviewDS.size() < 30 /* to avoid DoS */)
    1113             :             {
    1114        1818 :                 auto poODS = std::make_shared<GTiffDataset>();
    1115         909 :                 poODS->ShareLockWithParentDataset(this);
    1116         909 :                 poODS->SetStructuralMDFromParent(this);
    1117         909 :                 if (m_bHasGotSiblingFiles)
    1118         161 :                     poODS->oOvManager.TransferSiblingFiles(
    1119             :                         CSLDuplicate(GetSiblingFiles()));
    1120         909 :                 poODS->m_osFilename = m_osFilename;
    1121         909 :                 poODS->m_nColorTableMultiplier = m_nColorTableMultiplier;
    1122         909 :                 if (poODS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nThisDir,
    1123        1818 :                                       eAccess) == CE_None &&
    1124         909 :                     poODS->GetRasterCount() == GetRasterCount())
    1125             :                 {
    1126        1818 :                     CPLDebug("GTiff", "Opened %dx%d overview.",
    1127        1818 :                              poODS->GetRasterXSize(), poODS->GetRasterYSize());
    1128         909 :                     m_apoOverviewDS.push_back(poODS);
    1129         909 :                     poODS->m_poBaseDS = this;
    1130         909 :                     poODS->m_bIsOverview = true;
    1131             : 
    1132             :                     // Propagate a few compression related settings that are
    1133             :                     // no preserved at the TIFF tag level, but may be set in
    1134             :                     // the GDAL_METADATA tag in the IMAGE_STRUCTURE domain
    1135             :                     // Note: this might not be totally reflecting the reality
    1136             :                     // if users have created overviews with different settings
    1137             :                     // but this is probably better than the default ones
    1138         909 :                     poODS->m_nWebPLevel = m_nWebPLevel;
    1139             :                     // below is not a copy & paste error: we transfer the
    1140             :                     // m_dfMaxZErrorOverview overview of the parent to
    1141             :                     // m_dfMaxZError of the overview
    1142         909 :                     poODS->m_dfMaxZError = m_dfMaxZErrorOverview;
    1143         909 :                     poODS->m_dfMaxZErrorOverview = m_dfMaxZErrorOverview;
    1144             : #if HAVE_JXL
    1145         909 :                     poODS->m_bJXLLossless = m_bJXLLossless;
    1146         909 :                     poODS->m_fJXLDistance = m_fJXLDistance;
    1147         909 :                     poODS->m_fJXLAlphaDistance = m_fJXLAlphaDistance;
    1148         909 :                     poODS->m_nJXLEffort = m_nJXLEffort;
    1149             : #endif
    1150             :                     // Those ones are not serialized currently..
    1151             :                     // poODS->m_nZLevel = m_nZLevel;
    1152             :                     // poODS->m_nLZMAPreset = m_nLZMAPreset;
    1153             :                     // poODS->m_nZSTDLevel = m_nZSTDLevel;
    1154             : 
    1155         909 :                     if (const char *pszOverviewResampling =
    1156         909 :                             m_oGTiffMDMD.GetMetadataItem("OVERVIEW_RESAMPLING",
    1157             :                                                          "IMAGE_STRUCTURE"))
    1158             :                     {
    1159         279 :                         for (int iBand = 1; iBand <= poODS->GetRasterCount();
    1160             :                              ++iBand)
    1161             :                         {
    1162         193 :                             auto poOBand = cpl::down_cast<GTiffRasterBand *>(
    1163         193 :                                 poODS->GetRasterBand(iBand));
    1164         193 :                             if (poOBand->GetMetadataItem("RESAMPLING") ==
    1165             :                                 nullptr)
    1166             :                             {
    1167         189 :                                 poOBand->m_oGTiffMDMD.SetMetadataItem(
    1168             :                                     "RESAMPLING", pszOverviewResampling);
    1169             :                             }
    1170             :                         }
    1171             :                     }
    1172             :                 }
    1173             :             }
    1174             :             // Embedded mask of the main image.
    1175        1996 :             else if ((nSubType & FILETYPE_MASK) != 0 &&
    1176         212 :                      (nSubType & FILETYPE_REDUCEDIMAGE) == 0 &&
    1177        1217 :                      ((nSubIFDs == 0 && iDirIndex != 1) || iSubIFD > 0) &&
    1178         113 :                      m_poMaskDS == nullptr)
    1179             :             {
    1180         113 :                 m_poMaskDS = std::make_shared<GTiffDataset>();
    1181         113 :                 m_poMaskDS->ShareLockWithParentDataset(this);
    1182         113 :                 m_poMaskDS->SetStructuralMDFromParent(this);
    1183         113 :                 m_poMaskDS->m_osFilename = m_osFilename;
    1184             : 
    1185             :                 // The TIFF6 specification - page 37 - only allows 1
    1186             :                 // SamplesPerPixel and 1 BitsPerSample Here we support either 1
    1187             :                 // or 8 bit per sample and we support either 1 sample per pixel
    1188             :                 // or as many samples as in the main image We don't check the
    1189             :                 // value of the PhotometricInterpretation tag, which should be
    1190             :                 // set to "Transparency mask" (4) according to the specification
    1191             :                 // (page 36).  However, the TIFF6 specification allows image
    1192             :                 // masks to have a higher resolution than the main image, what
    1193             :                 // we don't support here.
    1194             : 
    1195         113 :                 if (m_poMaskDS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nThisDir,
    1196         113 :                                            eAccess) != CE_None ||
    1197         113 :                     m_poMaskDS->GetRasterCount() == 0 ||
    1198         113 :                     !(m_poMaskDS->GetRasterCount() == 1 ||
    1199           3 :                       m_poMaskDS->GetRasterCount() == GetRasterCount()) ||
    1200         113 :                     m_poMaskDS->GetRasterXSize() != GetRasterXSize() ||
    1201         339 :                     m_poMaskDS->GetRasterYSize() != GetRasterYSize() ||
    1202         113 :                     m_poMaskDS->GetRasterBand(1)->GetRasterDataType() !=
    1203             :                         GDT_UInt8)
    1204             :                 {
    1205           0 :                     m_poMaskDS.reset();
    1206             :                 }
    1207             :                 else
    1208             :                 {
    1209         113 :                     CPLDebug("GTiff", "Opened band mask.");
    1210         113 :                     m_poMaskDS->m_poBaseDS = this;
    1211         113 :                     m_poMaskDS->m_poImageryDS = this;
    1212             : 
    1213         113 :                     m_poMaskDS->m_bPromoteTo8Bits =
    1214         113 :                         CPLTestBool(CPLGetConfigOption(
    1215             :                             "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
    1216             :                 }
    1217             :             }
    1218             : 
    1219             :             // Embedded mask of an overview.  The TIFF6 specification allows the
    1220             :             // combination of the FILETYPE_xxxx masks.
    1221         779 :             else if ((nSubType & FILETYPE_REDUCEDIMAGE) != 0 &&
    1222         345 :                      (nSubType & FILETYPE_MASK) != 0 &&
    1223          99 :                      ((nSubIFDs == 0 && iDirIndex != 1) || iSubIFD > 0))
    1224             :             {
    1225         198 :                 auto poDS = std::make_shared<GTiffDataset>();
    1226          99 :                 poDS->ShareLockWithParentDataset(this);
    1227          99 :                 poDS->SetStructuralMDFromParent(this);
    1228          99 :                 poDS->m_osFilename = m_osFilename;
    1229          99 :                 if (poDS->OpenOffset(VSI_TIFFOpenChild(m_hTIFF), nThisDir,
    1230          99 :                                      eAccess) == CE_None &&
    1231         198 :                     poDS->GetRasterCount() != 0 &&
    1232          99 :                     poDS->GetRasterBand(1)->GetRasterDataType() == GDT_UInt8)
    1233             :                 {
    1234         143 :                     for (auto &poOvrDS : m_apoOverviewDS)
    1235             :                     {
    1236         143 :                         if (poOvrDS->m_poMaskDS == nullptr &&
    1237          99 :                             poDS->GetRasterXSize() ==
    1238          99 :                                 poOvrDS->GetRasterXSize() &&
    1239          99 :                             poDS->GetRasterYSize() ==
    1240         341 :                                 poOvrDS->GetRasterYSize() &&
    1241          99 :                             (poDS->GetRasterCount() == 1 ||
    1242           0 :                              poDS->GetRasterCount() == GetRasterCount()))
    1243             :                         {
    1244         198 :                             CPLDebug(
    1245             :                                 "GTiff", "Opened band mask for %dx%d overview.",
    1246         198 :                                 poDS->GetRasterXSize(), poDS->GetRasterYSize());
    1247          99 :                             poDS->m_poImageryDS = poOvrDS.get();
    1248         198 :                             poDS->m_bPromoteTo8Bits =
    1249          99 :                                 CPLTestBool(CPLGetConfigOption(
    1250             :                                     "GDAL_TIFF_INTERNAL_MASK_TO_8BIT", "YES"));
    1251          99 :                             poDS->m_poBaseDS = this;
    1252          99 :                             poOvrDS->m_poMaskDS = std::move(poDS);
    1253          99 :                             break;
    1254             :                         }
    1255             :                     }
    1256          99 :                 }
    1257             :             }
    1258         680 :             else if (!m_bSingleIFDOpened &&
    1259         674 :                      (nSubType == 0 || nSubType == FILETYPE_PAGE))
    1260             :             {
    1261         429 :                 uint32_t nXSize = 0;
    1262         429 :                 uint32_t nYSize = 0;
    1263             : 
    1264         429 :                 TIFFGetField(m_hTIFF, TIFFTAG_IMAGEWIDTH, &nXSize);
    1265         429 :                 TIFFGetField(m_hTIFF, TIFFTAG_IMAGELENGTH, &nYSize);
    1266             : 
    1267             :                 // For Geodetic TIFF grids (GTG)
    1268             :                 // (https://proj.org/specifications/geodetictiffgrids.html)
    1269             :                 // extract the grid_name to put it in the description
    1270         858 :                 std::string osFriendlyName;
    1271         429 :                 char *pszText = nullptr;
    1272         524 :                 if (TIFFGetField(m_hTIFF, TIFFTAG_GDAL_METADATA, &pszText) &&
    1273          95 :                     strstr(pszText, "grid_name") != nullptr)
    1274             :                 {
    1275           4 :                     CPLXMLNode *psRoot = CPLParseXMLString(pszText);
    1276             :                     const CPLXMLNode *psItem =
    1277           4 :                         psRoot ? CPLGetXMLNode(psRoot, "=GDALMetadata")
    1278           4 :                                : nullptr;
    1279           4 :                     if (psItem)
    1280           4 :                         psItem = psItem->psChild;
    1281           4 :                     for (; psItem != nullptr; psItem = psItem->psNext)
    1282             :                     {
    1283             : 
    1284           4 :                         if (psItem->eType != CXT_Element ||
    1285           4 :                             !EQUAL(psItem->pszValue, "Item"))
    1286           0 :                             continue;
    1287             : 
    1288             :                         const char *pszKey =
    1289           4 :                             CPLGetXMLValue(psItem, "name", nullptr);
    1290             :                         const char *pszValue =
    1291           4 :                             CPLGetXMLValue(psItem, nullptr, nullptr);
    1292             :                         int nBand =
    1293           4 :                             atoi(CPLGetXMLValue(psItem, "sample", "-1"));
    1294           4 :                         if (pszKey && pszValue && nBand <= 0 &&
    1295           4 :                             EQUAL(pszKey, "grid_name"))
    1296             :                         {
    1297           4 :                             osFriendlyName = ": ";
    1298           4 :                             osFriendlyName += pszValue;
    1299           4 :                             break;
    1300             :                         }
    1301             :                     }
    1302             : 
    1303           4 :                     CPLDestroyXMLNode(psRoot);
    1304             :                 }
    1305             : 
    1306         429 :                 if (nXSize > INT_MAX || nYSize > INT_MAX)
    1307             :                 {
    1308           1 :                     CPLDebug("GTiff",
    1309             :                              "Skipping directory with too large image: %u x %u",
    1310             :                              nXSize, nYSize);
    1311             :                 }
    1312             :                 else
    1313             :                 {
    1314         428 :                     uint16_t nSPP = 0;
    1315         428 :                     if (!TIFFGetField(m_hTIFF, TIFFTAG_SAMPLESPERPIXEL, &nSPP))
    1316           7 :                         nSPP = 1;
    1317             : 
    1318         856 :                     CPLString osName, osDesc;
    1319             :                     osName.Printf("SUBDATASET_%d_NAME=GTIFF_DIR:%d:%s",
    1320         428 :                                   iDirIndex, iDirIndex, m_osFilename.c_str());
    1321             :                     osDesc.Printf(
    1322             :                         "SUBDATASET_%d_DESC=Page %d (%dP x %dL x %dB)",
    1323             :                         iDirIndex, iDirIndex, static_cast<int>(nXSize),
    1324         428 :                         static_cast<int>(nYSize), nSPP);
    1325         428 :                     osDesc += osFriendlyName;
    1326             : 
    1327         428 :                     aosSubdatasets.AddString(osName);
    1328         428 :                     aosSubdatasets.AddString(osDesc);
    1329             :                 }
    1330             :             }
    1331             :         }
    1332        1769 :         CPLFree(subIFDOffsets);
    1333             : 
    1334             :         // Make sure we are stepping from the expected directory regardless
    1335             :         // of churn done processing the above.
    1336        1769 :         if (TIFFCurrentDirOffset(m_hTIFF) != nTopDir)
    1337          14 :             TIFFSetSubDirectory(m_hTIFF, nTopDir);
    1338        2878 :     } while (!m_bSingleIFDOpened && !TIFFLastDirectory(m_hTIFF) &&
    1339        1109 :              TIFFReadDirectory(m_hTIFF) != 0);
    1340             : 
    1341        7343 :     ReloadDirectory();
    1342             : 
    1343             :     // If we have a mask for the main image, loop over the overviews, and if
    1344             :     // they have a mask, let's set this mask as an overview of the main mask.
    1345        7343 :     if (m_poMaskDS)
    1346             :     {
    1347         212 :         for (auto &poOvrDS : m_apoOverviewDS)
    1348             :         {
    1349          99 :             if (poOvrDS->m_poMaskDS)
    1350             :             {
    1351          99 :                 m_poMaskDS->m_apoOverviewDS.push_back(poOvrDS->m_poMaskDS);
    1352             :             }
    1353             :         }
    1354             :     }
    1355             : 
    1356             :     // Assign color interpretation from main dataset
    1357        7343 :     const int l_nBands = GetRasterCount();
    1358        8252 :     for (auto &poOvrDS : m_apoOverviewDS)
    1359             :     {
    1360       68054 :         for (int i = 1; i <= l_nBands; i++)
    1361             :         {
    1362             :             auto poBand =
    1363       67145 :                 dynamic_cast<GTiffRasterBand *>(poOvrDS->GetRasterBand(i));
    1364       67145 :             if (poBand)
    1365       67145 :                 poBand->m_eBandInterp =
    1366       67145 :                     GetRasterBand(i)->GetColorInterpretation();
    1367             :         }
    1368             :     }
    1369             : 
    1370             :     /* -------------------------------------------------------------------- */
    1371             :     /*      Only keep track of subdatasets if we have more than one         */
    1372             :     /*      subdataset (pair).                                              */
    1373             :     /* -------------------------------------------------------------------- */
    1374        7343 :     if (aosSubdatasets.size() > 2)
    1375             :     {
    1376          12 :         m_oGTiffMDMD.SetMetadata(aosSubdatasets.List(), "SUBDATASETS");
    1377             :     }
    1378             : }
    1379             : 
    1380             : /************************************************************************/
    1381             : /*                         GetInternalHandle()                          */
    1382             : /************************************************************************/
    1383             : 
    1384        2492 : void *GTiffDataset::GetInternalHandle(const char *pszHandleName)
    1385             : 
    1386             : {
    1387        2492 :     if (pszHandleName && EQUAL(pszHandleName, "TIFF_HANDLE"))
    1388        2319 :         return m_hTIFF;
    1389         173 :     return nullptr;
    1390             : }
    1391             : 
    1392             : /************************************************************************/
    1393             : /*                            GetFileList()                             */
    1394             : /************************************************************************/
    1395             : 
    1396        2512 : char **GTiffDataset::GetFileList()
    1397             : 
    1398             : {
    1399        2512 :     if (m_poBaseDS != nullptr)
    1400           0 :         return nullptr;
    1401             : 
    1402        2512 :     LoadGeoreferencingAndPamIfNeeded();
    1403             : 
    1404        5024 :     CPLStringList aosFiles(GDALPamDataset::GetFileList());
    1405             : 
    1406        2512 :     LoadMetadata();
    1407        2512 :     if (nullptr != m_papszMetadataFiles)
    1408             :     {
    1409          77 :         for (int i = 0; m_papszMetadataFiles[i] != nullptr; ++i)
    1410             :         {
    1411          44 :             if (aosFiles.FindString(m_papszMetadataFiles[i]) < 0)
    1412             :             {
    1413          44 :                 aosFiles.AddString(m_papszMetadataFiles[i]);
    1414             :             }
    1415             :         }
    1416             :     }
    1417             : 
    1418        2512 :     if (m_pszGeorefFilename && aosFiles.FindString(m_pszGeorefFilename) == -1)
    1419             :     {
    1420           6 :         aosFiles.AddString(m_pszGeorefFilename);
    1421             :     }
    1422             : 
    1423        2512 :     if (m_nXMLGeorefSrcIndex >= 0)
    1424        2512 :         LookForProjection();
    1425             : 
    1426        2512 :     if (m_pszXMLFilename && aosFiles.FindString(m_pszXMLFilename) == -1)
    1427             :     {
    1428           1 :         aosFiles.AddString(m_pszXMLFilename);
    1429             :     }
    1430             : 
    1431        5024 :     const std::string osVATDBF = m_osFilename + ".vat.dbf";
    1432             :     VSIStatBufL sStat;
    1433        2512 :     if (VSIStatL(osVATDBF.c_str(), &sStat) == 0)
    1434             :     {
    1435           2 :         aosFiles.AddString(osVATDBF.c_str());
    1436             :     }
    1437             : 
    1438        2512 :     LoadENVIHdrIfNeeded();
    1439        2512 :     if (m_bENVIHdrFound)
    1440             :     {
    1441             :         aosFiles.AddString(
    1442           1 :             GetSidecarFilenameWithReplacedExtension("hdr").c_str());
    1443             :     }
    1444             : 
    1445        2512 :     return aosFiles.StealList();
    1446             : }
    1447             : 
    1448             : /************************************************************************/
    1449             : /*                        GetRawBinaryLayout()                          */
    1450             : /************************************************************************/
    1451             : 
    1452           9 : bool GTiffDataset::GetRawBinaryLayout(GDALDataset::RawBinaryLayout &sLayout)
    1453             : {
    1454           9 :     if (eAccess == GA_Update)
    1455             :     {
    1456           3 :         FlushCache(false);
    1457           3 :         Crystalize();
    1458             :     }
    1459             : 
    1460           9 :     if (m_nCompression != COMPRESSION_NONE)
    1461           1 :         return false;
    1462           8 :     if (!CPLIsPowerOfTwo(m_nBitsPerSample) || m_nBitsPerSample < 8)
    1463           0 :         return false;
    1464           8 :     const auto eDT = GetRasterBand(1)->GetRasterDataType();
    1465           8 :     if (GDALDataTypeIsComplex(eDT))
    1466           0 :         return false;
    1467             : 
    1468           8 :     toff_t *panByteCounts = nullptr;
    1469           8 :     toff_t *panOffsets = nullptr;
    1470           8 :     const bool bIsTiled = CPL_TO_BOOL(TIFFIsTiled(m_hTIFF));
    1471             : 
    1472          16 :     if (!((bIsTiled &&
    1473           3 :            TIFFGetField(m_hTIFF, TIFFTAG_TILEBYTECOUNTS, &panByteCounts) &&
    1474           3 :            TIFFGetField(m_hTIFF, TIFFTAG_TILEOFFSETS, &panOffsets)) ||
    1475           5 :           (!bIsTiled &&
    1476           5 :            TIFFGetField(m_hTIFF, TIFFTAG_STRIPBYTECOUNTS, &panByteCounts) &&
    1477           5 :            TIFFGetField(m_hTIFF, TIFFTAG_STRIPOFFSETS, &panOffsets))))
    1478             :     {
    1479           0 :         return false;
    1480             :     }
    1481             : 
    1482           8 :     const int nDTSize = GDALGetDataTypeSizeBytes(eDT);
    1483           8 :     vsi_l_offset nImgOffset = panOffsets[0];
    1484          16 :     GIntBig nPixelOffset = (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    1485           8 :                                ? static_cast<GIntBig>(nDTSize) * nBands
    1486             :                                : nDTSize;
    1487           8 :     GIntBig nLineOffset = nPixelOffset * nRasterXSize;
    1488           8 :     GIntBig nBandOffset =
    1489           8 :         (m_nPlanarConfig == PLANARCONFIG_CONTIG && nBands > 1) ? nDTSize : 0;
    1490           8 :     RawBinaryLayout::Interleaving eInterleaving =
    1491          12 :         (nBands == 1) ? RawBinaryLayout::Interleaving::UNKNOWN
    1492           4 :         : (m_nPlanarConfig == PLANARCONFIG_CONTIG)
    1493           4 :             ? RawBinaryLayout::Interleaving::BIP
    1494             :             : RawBinaryLayout::Interleaving::BSQ;
    1495           8 :     if (bIsTiled)
    1496             :     {
    1497             :         // Only a single block tiled file with same dimension as the raster
    1498             :         // might be acceptable
    1499           3 :         if (m_nBlockXSize != nRasterXSize || m_nBlockYSize != nRasterYSize)
    1500           1 :             return false;
    1501           2 :         if (nBands > 1 && m_nPlanarConfig != PLANARCONFIG_CONTIG)
    1502             :         {
    1503           1 :             nBandOffset = static_cast<GIntBig>(panOffsets[1]) -
    1504           1 :                           static_cast<GIntBig>(panOffsets[0]);
    1505           2 :             for (int i = 2; i < nBands; i++)
    1506             :             {
    1507           1 :                 if (static_cast<GIntBig>(panOffsets[i]) -
    1508           1 :                         static_cast<GIntBig>(panOffsets[i - 1]) !=
    1509             :                     nBandOffset)
    1510           0 :                     return false;
    1511             :             }
    1512             :         }
    1513             :     }
    1514             :     else
    1515             :     {
    1516           5 :         const int nStrips = DIV_ROUND_UP(nRasterYSize, m_nRowsPerStrip);
    1517           5 :         if (nBands == 1 || m_nPlanarConfig == PLANARCONFIG_CONTIG)
    1518             :         {
    1519           4 :             vsi_l_offset nLastStripEnd = panOffsets[0] + panByteCounts[0];
    1520          16 :             for (int iStrip = 1; iStrip < nStrips; iStrip++)
    1521             :             {
    1522          12 :                 if (nLastStripEnd != panOffsets[iStrip])
    1523           0 :                     return false;
    1524          12 :                 nLastStripEnd = panOffsets[iStrip] + panByteCounts[iStrip];
    1525           4 :             }
    1526             :         }
    1527             :         else
    1528             :         {
    1529             :             // Note: we could potentially have BIL order with m_nRowsPerStrip ==
    1530             :             // 1 and if strips are ordered strip_line_1_band_1, ...,
    1531             :             // strip_line_1_band_N, strip_line2_band1, ... strip_line2_band_N,
    1532             :             // etc.... but that'd be faily exotic ! So only detect BSQ layout
    1533             :             // here
    1534           1 :             nBandOffset = static_cast<GIntBig>(panOffsets[nStrips]) -
    1535           1 :                           static_cast<GIntBig>(panOffsets[0]);
    1536           4 :             for (int i = 0; i < nBands; i++)
    1537             :             {
    1538           3 :                 uint32_t iStripOffset = nStrips * i;
    1539           3 :                 vsi_l_offset nLastStripEnd =
    1540           3 :                     panOffsets[iStripOffset] + panByteCounts[iStripOffset];
    1541           3 :                 for (int iStrip = 1; iStrip < nStrips; iStrip++)
    1542             :                 {
    1543           0 :                     if (nLastStripEnd != panOffsets[iStripOffset + iStrip])
    1544           0 :                         return false;
    1545           0 :                     nLastStripEnd = panOffsets[iStripOffset + iStrip] +
    1546           0 :                                     panByteCounts[iStripOffset + iStrip];
    1547             :                 }
    1548           3 :                 if (i >= 2 && static_cast<GIntBig>(panOffsets[iStripOffset]) -
    1549           1 :                                       static_cast<GIntBig>(
    1550           1 :                                           panOffsets[iStripOffset - nStrips]) !=
    1551             :                                   nBandOffset)
    1552             :                 {
    1553           0 :                     return false;
    1554             :                 }
    1555             :             }
    1556             :         }
    1557             :     }
    1558             : 
    1559           7 :     sLayout.osRawFilename = m_osFilename;
    1560           7 :     sLayout.eInterleaving = eInterleaving;
    1561           7 :     sLayout.eDataType = eDT;
    1562             : #ifdef CPL_LSB
    1563           7 :     sLayout.bLittleEndianOrder = !TIFFIsByteSwapped(m_hTIFF);
    1564             : #else
    1565             :     sLayout.bLittleEndianOrder = TIFFIsByteSwapped(m_hTIFF);
    1566             : #endif
    1567           7 :     sLayout.nImageOffset = nImgOffset;
    1568           7 :     sLayout.nPixelOffset = nPixelOffset;
    1569           7 :     sLayout.nLineOffset = nLineOffset;
    1570           7 :     sLayout.nBandOffset = nBandOffset;
    1571             : 
    1572           7 :     return true;
    1573             : }
    1574             : 
    1575             : /************************************************************************/
    1576             : /*               GTiffDatasetLibGeotiffErrorCallback()                  */
    1577             : /************************************************************************/
    1578             : 
    1579           0 : static void GTiffDatasetLibGeotiffErrorCallback(GTIF *, int level,
    1580             :                                                 const char *pszMsg, ...)
    1581             : {
    1582             :     va_list ap;
    1583           0 :     va_start(ap, pszMsg);
    1584           0 :     CPLErrorV((level == LIBGEOTIFF_WARNING) ? CE_Warning : CE_Failure,
    1585             :               CPLE_AppDefined, pszMsg, ap);
    1586           0 :     va_end(ap);
    1587           0 : }
    1588             : 
    1589             : /************************************************************************/
    1590             : /*                           GTIFNew()                                  */
    1591             : /************************************************************************/
    1592             : 
    1593       34151 : /* static */ GTIF *GTiffDataset::GTIFNew(TIFF *hTIFF)
    1594             : {
    1595       34151 :     GTIF *gtif = GTIFNewEx(hTIFF, GTiffDatasetLibGeotiffErrorCallback, nullptr);
    1596       34151 :     if (gtif)
    1597             :     {
    1598       34151 :         GTIFAttachPROJContext(gtif, OSRGetProjTLSContext());
    1599             :     }
    1600       34151 :     return gtif;
    1601             : }

Generated by: LCOV version 1.14