LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 713 756 94.3 %
Date: 2026-06-26 10:54:19 Functions: 26 27 96.3 %

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

Generated by: LCOV version 1.14