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

Generated by: LCOV version 1.14