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

Generated by: LCOV version 1.14