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

Generated by: LCOV version 1.14