LCOV - code coverage report
Current view: top level - frmts/gtiff - gtiffdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 709 758 93.5 %
Date: 2025-10-01 17:07:58 Functions: 24 25 96.0 %

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

Generated by: LCOV version 1.14