LCOV - code coverage report
Current view: top level - frmts/vrt - vrtdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1330 1465 90.8 %
Date: 2025-05-31 00:00:17 Functions: 58 61 95.1 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Virtual GDAL Datasets
       4             :  * Purpose:  Implementation of VRTDataset
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "vrtdataset.h"
      15             : 
      16             : #include "cpl_error_internal.h"
      17             : #include "cpl_minixml.h"
      18             : #include "cpl_string.h"
      19             : #include "gdal_frmts.h"
      20             : #include "ogr_spatialref.h"
      21             : #include "gdal_thread_pool.h"
      22             : #include "gdal_utils.h"
      23             : 
      24             : #include <algorithm>
      25             : #include <cassert>
      26             : #include <cmath>
      27             : #include <set>
      28             : #include <typeinfo>
      29             : #include "gdal_proxy.h"
      30             : 
      31             : /*! @cond Doxygen_Suppress */
      32             : 
      33             : #define VRT_PROTOCOL_PREFIX "vrt://"
      34             : 
      35             : constexpr int DEFAULT_BLOCK_SIZE = 128;
      36             : 
      37             : /************************************************************************/
      38             : /*                            VRTDataset()                              */
      39             : /************************************************************************/
      40             : 
      41        5630 : VRTDataset::VRTDataset(int nXSize, int nYSize, int nBlockXSize, int nBlockYSize)
      42             : {
      43        5630 :     nRasterXSize = nXSize;
      44        5630 :     nRasterYSize = nYSize;
      45             : 
      46        5630 :     m_adfGeoTransform[0] = 0.0;
      47        5630 :     m_adfGeoTransform[1] = 1.0;
      48        5630 :     m_adfGeoTransform[2] = 0.0;
      49        5630 :     m_adfGeoTransform[3] = 0.0;
      50        5630 :     m_adfGeoTransform[4] = 0.0;
      51        5630 :     m_adfGeoTransform[5] = 1.0;
      52        5630 :     m_bBlockSizeSpecified = nBlockXSize > 0 && nBlockYSize > 0;
      53        5630 :     m_nBlockXSize =
      54        5630 :         nBlockXSize > 0 ? nBlockXSize : std::min(DEFAULT_BLOCK_SIZE, nXSize);
      55        5630 :     m_nBlockYSize =
      56        5630 :         nBlockYSize > 0 ? nBlockYSize : std::min(DEFAULT_BLOCK_SIZE, nYSize);
      57             : 
      58        5630 :     GDALRegister_VRT();
      59             : 
      60        5630 :     poDriver = static_cast<GDALDriver *>(GDALGetDriverByName("VRT"));
      61        5630 : }
      62             : 
      63             : /************************************************************************/
      64             : /*                          IsDefaultBlockSize()                        */
      65             : /************************************************************************/
      66             : 
      67        1460 : /* static */ bool VRTDataset::IsDefaultBlockSize(int nBlockSize, int nDimension)
      68             : {
      69        2338 :     return nBlockSize == DEFAULT_BLOCK_SIZE ||
      70        2338 :            (nBlockSize < DEFAULT_BLOCK_SIZE && nBlockSize == nDimension);
      71             : }
      72             : 
      73             : /*! @endcond */
      74             : 
      75             : /************************************************************************/
      76             : /*                              VRTCreate()                             */
      77             : /************************************************************************/
      78             : 
      79             : /**
      80             :  * @see VRTDataset::VRTDataset()
      81             :  */
      82             : 
      83        2020 : VRTDatasetH CPL_STDCALL VRTCreate(int nXSize, int nYSize)
      84             : 
      85             : {
      86        2020 :     auto poDS = new VRTDataset(nXSize, nYSize);
      87        2020 :     poDS->eAccess = GA_Update;
      88        2020 :     return poDS;
      89             : }
      90             : 
      91             : /*! @cond Doxygen_Suppress */
      92             : 
      93             : /************************************************************************/
      94             : /*                            ~VRTDataset()                            */
      95             : /************************************************************************/
      96             : 
      97       10594 : VRTDataset::~VRTDataset()
      98             : 
      99             : {
     100        5630 :     VRTDataset::FlushCache(true);
     101        5630 :     CPLFree(m_pszVRTPath);
     102             : 
     103        5630 :     delete m_poMaskBand;
     104             : 
     105        5685 :     for (size_t i = 0; i < m_apoOverviews.size(); i++)
     106          55 :         delete m_apoOverviews[i];
     107        5637 :     for (size_t i = 0; i < m_apoOverviewsBak.size(); i++)
     108           7 :         delete m_apoOverviewsBak[i];
     109        5630 :     CSLDestroy(m_papszXMLVRTMetadata);
     110       10594 : }
     111             : 
     112             : /************************************************************************/
     113             : /*                             FlushCache()                             */
     114             : /************************************************************************/
     115             : 
     116        5980 : CPLErr VRTDataset::FlushCache(bool bAtClosing)
     117             : 
     118             : {
     119        5980 :     if (m_poRootGroup)
     120         338 :         return m_poRootGroup->Serialize() ? CE_None : CE_Failure;
     121             :     else
     122        5642 :         return VRTFlushCacheStruct<VRTDataset>::FlushCache(*this, bAtClosing);
     123             : }
     124             : 
     125             : /************************************************************************/
     126             : /*                             FlushCache()                             */
     127             : /************************************************************************/
     128             : 
     129         755 : CPLErr VRTWarpedDataset::FlushCache(bool bAtClosing)
     130             : 
     131             : {
     132         755 :     return VRTFlushCacheStruct<VRTWarpedDataset>::FlushCache(*this, bAtClosing);
     133             : }
     134             : 
     135             : /************************************************************************/
     136             : /*                             FlushCache()                             */
     137             : /************************************************************************/
     138             : 
     139         190 : CPLErr VRTPansharpenedDataset::FlushCache(bool bAtClosing)
     140             : 
     141             : {
     142         190 :     return VRTFlushCacheStruct<VRTPansharpenedDataset>::FlushCache(*this,
     143         190 :                                                                    bAtClosing);
     144             : }
     145             : 
     146             : /************************************************************************/
     147             : /*                             FlushCache()                             */
     148             : /************************************************************************/
     149             : 
     150         198 : CPLErr VRTProcessedDataset::FlushCache(bool bAtClosing)
     151             : 
     152             : {
     153         198 :     return VRTFlushCacheStruct<VRTProcessedDataset>::FlushCache(*this,
     154         198 :                                                                 bAtClosing);
     155             : }
     156             : 
     157             : /************************************************************************/
     158             : /*                             FlushCache()                             */
     159             : /************************************************************************/
     160             : 
     161             : template <class T>
     162        6785 : CPLErr VRTFlushCacheStruct<T>::FlushCache(T &obj, bool bAtClosing)
     163             : {
     164        6785 :     CPLErr eErr = obj.GDALDataset::FlushCache(bAtClosing);
     165             : 
     166        6785 :     if (!obj.m_bNeedsFlush || !obj.m_bWritable)
     167        3505 :         return eErr;
     168             : 
     169             :     // We don't write to disk if there is no filename.  This is a
     170             :     // memory only dataset.
     171        3695 :     if (strlen(obj.GetDescription()) == 0 ||
     172         415 :         STARTS_WITH_CI(obj.GetDescription(), "<VRTDataset"))
     173        2882 :         return eErr;
     174             : 
     175         398 :     obj.m_bNeedsFlush = false;
     176             : 
     177             :     // Serialize XML representation to disk
     178         398 :     const std::string osVRTPath(CPLGetPathSafe(obj.GetDescription()));
     179         398 :     CPLXMLNode *psDSTree = obj.T::SerializeToXML(osVRTPath.c_str());
     180         398 :     if (!CPLSerializeXMLTreeToFile(psDSTree, obj.GetDescription()))
     181          13 :         eErr = CE_Failure;
     182         398 :     CPLDestroyXMLNode(psDSTree);
     183         398 :     return eErr;
     184             : }
     185             : 
     186             : /************************************************************************/
     187             : /*                            GetMetadata()                             */
     188             : /************************************************************************/
     189             : 
     190       16666 : char **VRTDataset::GetMetadata(const char *pszDomain)
     191             : {
     192       16666 :     if (pszDomain != nullptr && EQUAL(pszDomain, "xml:VRT"))
     193             :     {
     194             :         /* ------------------------------------------------------------------ */
     195             :         /*      Convert tree to a single block of XML text.                   */
     196             :         /* ------------------------------------------------------------------ */
     197          50 :         const char *pszDescription = GetDescription();
     198          50 :         char *l_pszVRTPath = CPLStrdup(
     199          50 :             pszDescription[0] && !STARTS_WITH(pszDescription, "<VRTDataset")
     200          70 :                 ? CPLGetPathSafe(pszDescription).c_str()
     201             :                 : "");
     202          50 :         CPLXMLNode *psDSTree = SerializeToXML(l_pszVRTPath);
     203          50 :         char *pszXML = CPLSerializeXMLTree(psDSTree);
     204             : 
     205          50 :         CPLDestroyXMLNode(psDSTree);
     206             : 
     207          50 :         CPLFree(l_pszVRTPath);
     208             : 
     209          50 :         CSLDestroy(m_papszXMLVRTMetadata);
     210          50 :         m_papszXMLVRTMetadata =
     211          50 :             static_cast<char **>(CPLMalloc(2 * sizeof(char *)));
     212          50 :         m_papszXMLVRTMetadata[0] = pszXML;
     213          50 :         m_papszXMLVRTMetadata[1] = nullptr;
     214          50 :         return m_papszXMLVRTMetadata;
     215             :     }
     216             : 
     217       16616 :     return GDALDataset::GetMetadata(pszDomain);
     218             : }
     219             : 
     220             : /************************************************************************/
     221             : /*                          GetMetadataItem()                           */
     222             : /************************************************************************/
     223             : 
     224       25335 : const char *VRTDataset::GetMetadataItem(const char *pszName,
     225             :                                         const char *pszDomain)
     226             : 
     227             : {
     228       25335 :     if (pszName && pszDomain && EQUAL(pszDomain, "__DEBUG__"))
     229             :     {
     230          10 :         if (EQUAL(pszName, "MULTI_THREADED_RASTERIO_LAST_USED"))
     231           9 :             return m_bMultiThreadedRasterIOLastUsed ? "1" : "0";
     232           1 :         else if (EQUAL(pszName, "CheckCompatibleForDatasetIO()"))
     233           1 :             return CheckCompatibleForDatasetIO() ? "1" : "0";
     234             :     }
     235       25325 :     return GDALDataset::GetMetadataItem(pszName, pszDomain);
     236             : }
     237             : 
     238             : /*! @endcond */
     239             : 
     240             : /************************************************************************/
     241             : /*                            VRTFlushCache(bool bAtClosing) */
     242             : /************************************************************************/
     243             : 
     244             : /**
     245             :  * @see VRTDataset::FlushCache(bool bAtClosing)
     246             :  */
     247             : 
     248           0 : void CPL_STDCALL VRTFlushCache(VRTDatasetH hDataset)
     249             : {
     250           0 :     VALIDATE_POINTER0(hDataset, "VRTFlushCache");
     251             : 
     252           0 :     static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))
     253           0 :         ->FlushCache(false);
     254             : }
     255             : 
     256             : /*! @cond Doxygen_Suppress */
     257             : 
     258             : /************************************************************************/
     259             : /*                           SerializeToXML()                           */
     260             : /************************************************************************/
     261             : 
     262         590 : CPLXMLNode *VRTDataset::SerializeToXML(const char *pszVRTPathIn)
     263             : 
     264             : {
     265         590 :     if (m_poRootGroup)
     266          77 :         return m_poRootGroup->SerializeToXML(pszVRTPathIn);
     267             : 
     268             :     /* -------------------------------------------------------------------- */
     269             :     /*      Setup root node and attributes.                                 */
     270             :     /* -------------------------------------------------------------------- */
     271         513 :     CPLXMLNode *psDSTree = CPLCreateXMLNode(nullptr, CXT_Element, "VRTDataset");
     272             : 
     273         513 :     char szNumber[128] = {'\0'};
     274         513 :     snprintf(szNumber, sizeof(szNumber), "%d", GetRasterXSize());
     275         513 :     CPLSetXMLValue(psDSTree, "#rasterXSize", szNumber);
     276             : 
     277         513 :     snprintf(szNumber, sizeof(szNumber), "%d", GetRasterYSize());
     278         513 :     CPLSetXMLValue(psDSTree, "#rasterYSize", szNumber);
     279             : 
     280             :     /* -------------------------------------------------------------------- */
     281             :     /*      SRS                                                             */
     282             :     /* -------------------------------------------------------------------- */
     283         513 :     if (m_poSRS && !m_poSRS->IsEmpty())
     284             :     {
     285         374 :         char *pszWKT = nullptr;
     286         374 :         m_poSRS->exportToWkt(&pszWKT);
     287             :         CPLXMLNode *psSRSNode =
     288         374 :             CPLCreateXMLElementAndValue(psDSTree, "SRS", pszWKT);
     289         374 :         CPLFree(pszWKT);
     290         374 :         const auto &mapping = m_poSRS->GetDataAxisToSRSAxisMapping();
     291         748 :         CPLString osMapping;
     292        1124 :         for (size_t i = 0; i < mapping.size(); ++i)
     293             :         {
     294         750 :             if (!osMapping.empty())
     295         376 :                 osMapping += ",";
     296         750 :             osMapping += CPLSPrintf("%d", mapping[i]);
     297             :         }
     298         374 :         CPLAddXMLAttributeAndValue(psSRSNode, "dataAxisToSRSAxisMapping",
     299             :                                    osMapping.c_str());
     300         374 :         const double dfCoordinateEpoch = m_poSRS->GetCoordinateEpoch();
     301         374 :         if (dfCoordinateEpoch > 0)
     302             :         {
     303           2 :             std::string osCoordinateEpoch = CPLSPrintf("%f", dfCoordinateEpoch);
     304           1 :             if (osCoordinateEpoch.find('.') != std::string::npos)
     305             :             {
     306           6 :                 while (osCoordinateEpoch.back() == '0')
     307           5 :                     osCoordinateEpoch.pop_back();
     308             :             }
     309           1 :             CPLAddXMLAttributeAndValue(psSRSNode, "coordinateEpoch",
     310             :                                        osCoordinateEpoch.c_str());
     311             :         }
     312             :     }
     313             : 
     314             :     /* -------------------------------------------------------------------- */
     315             :     /*      Geotransform.                                                   */
     316             :     /* -------------------------------------------------------------------- */
     317         513 :     if (m_bGeoTransformSet)
     318             :     {
     319         445 :         CPLSetXMLValue(
     320             :             psDSTree, "GeoTransform",
     321             :             CPLSPrintf("%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
     322             :                        m_adfGeoTransform[0], m_adfGeoTransform[1],
     323             :                        m_adfGeoTransform[2], m_adfGeoTransform[3],
     324             :                        m_adfGeoTransform[4], m_adfGeoTransform[5]));
     325             :     }
     326             : 
     327             :     /* -------------------------------------------------------------------- */
     328             :     /*      Metadata                                                        */
     329             :     /* -------------------------------------------------------------------- */
     330         513 :     CPLXMLNode *psMD = oMDMD.Serialize();
     331         513 :     if (psMD != nullptr)
     332             :     {
     333         301 :         CPLAddXMLChild(psDSTree, psMD);
     334             :     }
     335             : 
     336             :     /* -------------------------------------------------------------------- */
     337             :     /*      GCPs                                                            */
     338             :     /* -------------------------------------------------------------------- */
     339         513 :     if (!m_asGCPs.empty())
     340             :     {
     341           4 :         GDALSerializeGCPListToXML(psDSTree, m_asGCPs, m_poGCP_SRS.get());
     342             :     }
     343             : 
     344             :     /* -------------------------------------------------------------------- */
     345             :     /*      Serialize bands.                                                */
     346             :     /* -------------------------------------------------------------------- */
     347         513 :     CPLXMLNode *psLastChild = psDSTree->psChild;
     348        2338 :     for (; psLastChild != nullptr && psLastChild->psNext;
     349        1825 :          psLastChild = psLastChild->psNext)
     350             :     {
     351             :     }
     352         513 :     CPLAssert(psLastChild);  // we have at least rasterXSize
     353         513 :     bool bHasWarnedAboutRAMUsage = false;
     354         513 :     size_t nAccRAMUsage = 0;
     355        1348 :     for (int iBand = 0; iBand < nBands; iBand++)
     356             :     {
     357             :         CPLXMLNode *psBandTree =
     358         835 :             static_cast<VRTRasterBand *>(papoBands[iBand])
     359        1670 :                 ->SerializeToXML(pszVRTPathIn, bHasWarnedAboutRAMUsage,
     360         835 :                                  nAccRAMUsage);
     361             : 
     362         835 :         if (psBandTree != nullptr)
     363             :         {
     364         835 :             psLastChild->psNext = psBandTree;
     365         835 :             psLastChild = psBandTree;
     366             :         }
     367             :     }
     368             : 
     369             :     /* -------------------------------------------------------------------- */
     370             :     /*      Serialize dataset mask band.                                    */
     371             :     /* -------------------------------------------------------------------- */
     372         513 :     if (m_poMaskBand)
     373             :     {
     374          38 :         CPLXMLNode *psBandTree = m_poMaskBand->SerializeToXML(
     375          19 :             pszVRTPathIn, bHasWarnedAboutRAMUsage, nAccRAMUsage);
     376             : 
     377          19 :         if (psBandTree != nullptr)
     378             :         {
     379             :             CPLXMLNode *psMaskBandElement =
     380          19 :                 CPLCreateXMLNode(psDSTree, CXT_Element, "MaskBand");
     381          19 :             CPLAddXMLChild(psMaskBandElement, psBandTree);
     382             :         }
     383             :     }
     384             : 
     385             :     /* -------------------------------------------------------------------- */
     386             :     /*      Overview factors.                                               */
     387             :     /* -------------------------------------------------------------------- */
     388         513 :     if (!m_anOverviewFactors.empty())
     389             :     {
     390          10 :         CPLString osOverviewList;
     391          16 :         for (int nOvFactor : m_anOverviewFactors)
     392             :         {
     393          11 :             if (!osOverviewList.empty())
     394           6 :                 osOverviewList += " ";
     395          11 :             osOverviewList += CPLSPrintf("%d", nOvFactor);
     396             :         }
     397           5 :         CPLXMLNode *psOverviewList = CPLCreateXMLElementAndValue(
     398             :             psDSTree, "OverviewList", osOverviewList);
     399           5 :         if (!m_osOverviewResampling.empty())
     400             :         {
     401           5 :             CPLAddXMLAttributeAndValue(psOverviewList, "resampling",
     402             :                                        m_osOverviewResampling);
     403             :         }
     404             :     }
     405             : 
     406         513 :     return psDSTree;
     407             : }
     408             : 
     409             : /*! @endcond */
     410             : /************************************************************************/
     411             : /*                          VRTSerializeToXML()                         */
     412             : /************************************************************************/
     413             : 
     414             : /**
     415             :  * @see VRTDataset::SerializeToXML()
     416             :  */
     417             : 
     418           0 : CPLXMLNode *CPL_STDCALL VRTSerializeToXML(VRTDatasetH hDataset,
     419             :                                           const char *pszVRTPath)
     420             : {
     421           0 :     VALIDATE_POINTER1(hDataset, "VRTSerializeToXML", nullptr);
     422             : 
     423           0 :     return static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))
     424           0 :         ->SerializeToXML(pszVRTPath);
     425             : }
     426             : 
     427             : /*! @cond Doxygen_Suppress */
     428             : 
     429             : /************************************************************************/
     430             : /*                             InitBand()                               */
     431             : /************************************************************************/
     432             : 
     433        2959 : VRTRasterBand *VRTDataset::InitBand(const char *pszSubclass, int nBand,
     434             :                                     bool bAllowPansharpenedOrProcessed)
     435             : {
     436        2959 :     VRTRasterBand *poBand = nullptr;
     437        2959 :     if (auto poProcessedDS = dynamic_cast<VRTProcessedDataset *>(this))
     438             :     {
     439          36 :         if (bAllowPansharpenedOrProcessed &&
     440          36 :             EQUAL(pszSubclass, "VRTProcessedRasterBand"))
     441             :         {
     442          36 :             poBand = new VRTProcessedRasterBand(poProcessedDS, nBand);
     443             :         }
     444             :     }
     445        2923 :     else if (EQUAL(pszSubclass, "VRTSourcedRasterBand"))
     446        1099 :         poBand = new VRTSourcedRasterBand(this, nBand);
     447        1824 :     else if (EQUAL(pszSubclass, "VRTDerivedRasterBand"))
     448        1273 :         poBand = new VRTDerivedRasterBand(this, nBand);
     449         551 :     else if (EQUAL(pszSubclass, "VRTRawRasterBand"))
     450          22 :         poBand = new VRTRawRasterBand(this, nBand);
     451         980 :     else if (EQUAL(pszSubclass, "VRTWarpedRasterBand") &&
     452         451 :              dynamic_cast<VRTWarpedDataset *>(this) != nullptr)
     453         451 :         poBand = new VRTWarpedRasterBand(this, nBand);
     454          78 :     else if (bAllowPansharpenedOrProcessed &&
     455         155 :              EQUAL(pszSubclass, "VRTPansharpenedRasterBand") &&
     456          77 :              dynamic_cast<VRTPansharpenedDataset *>(this) != nullptr)
     457          77 :         poBand = new VRTPansharpenedRasterBand(this, nBand);
     458             : 
     459        2959 :     if (!poBand)
     460             :     {
     461           1 :         CPLError(CE_Failure, CPLE_AppDefined,
     462             :                  "VRTRasterBand of unrecognized subclass '%s'.", pszSubclass);
     463             :     }
     464             : 
     465        2959 :     return poBand;
     466             : }
     467             : 
     468             : /************************************************************************/
     469             : /*                              XMLInit()                               */
     470             : /************************************************************************/
     471             : 
     472        2593 : CPLErr VRTDataset::XMLInit(const CPLXMLNode *psTree, const char *pszVRTPathIn)
     473             : 
     474             : {
     475        2593 :     if (pszVRTPathIn != nullptr)
     476        1120 :         m_pszVRTPath = CPLStrdup(pszVRTPathIn);
     477             : 
     478             :     /* -------------------------------------------------------------------- */
     479             :     /*      Check for an SRS node.                                          */
     480             :     /* -------------------------------------------------------------------- */
     481        2593 :     const CPLXMLNode *psSRSNode = CPLGetXMLNode(psTree, "SRS");
     482        2593 :     if (psSRSNode)
     483             :     {
     484         596 :         m_poSRS.reset(new OGRSpatialReference());
     485         596 :         m_poSRS->SetFromUserInput(
     486             :             CPLGetXMLValue(psSRSNode, nullptr, ""),
     487             :             OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
     488             :         const char *pszMapping =
     489         596 :             CPLGetXMLValue(psSRSNode, "dataAxisToSRSAxisMapping", nullptr);
     490         596 :         if (pszMapping)
     491             :         {
     492             :             char **papszTokens =
     493         361 :                 CSLTokenizeStringComplex(pszMapping, ",", FALSE, FALSE);
     494         722 :             std::vector<int> anMapping;
     495        1086 :             for (int i = 0; papszTokens && papszTokens[i]; i++)
     496             :             {
     497         725 :                 anMapping.push_back(atoi(papszTokens[i]));
     498             :             }
     499         361 :             CSLDestroy(papszTokens);
     500         361 :             m_poSRS->SetDataAxisToSRSAxisMapping(anMapping);
     501             :         }
     502             :         else
     503             :         {
     504         235 :             m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
     505             :         }
     506             : 
     507             :         const char *pszCoordinateEpoch =
     508         596 :             CPLGetXMLValue(psSRSNode, "coordinateEpoch", nullptr);
     509         596 :         if (pszCoordinateEpoch)
     510           1 :             m_poSRS->SetCoordinateEpoch(CPLAtof(pszCoordinateEpoch));
     511             :     }
     512             : 
     513             :     /* -------------------------------------------------------------------- */
     514             :     /*      Check for a GeoTransform node.                                  */
     515             :     /* -------------------------------------------------------------------- */
     516        2593 :     const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
     517        2593 :     if (strlen(pszGT) > 0)
     518             :     {
     519             :         const CPLStringList aosTokens(
     520        1366 :             CSLTokenizeStringComplex(pszGT, ",", FALSE, FALSE));
     521         683 :         if (aosTokens.size() != 6)
     522             :         {
     523           0 :             CPLError(CE_Warning, CPLE_AppDefined,
     524             :                      "GeoTransform node does not have expected six values.");
     525             :         }
     526             :         else
     527             :         {
     528        4781 :             for (int iTA = 0; iTA < 6; iTA++)
     529        4098 :                 m_adfGeoTransform[iTA] = CPLAtof(aosTokens[iTA]);
     530         683 :             m_bGeoTransformSet = TRUE;
     531             :         }
     532             :     }
     533             : 
     534             :     /* -------------------------------------------------------------------- */
     535             :     /*      Check for GCPs.                                                 */
     536             :     /* -------------------------------------------------------------------- */
     537        2593 :     if (const CPLXMLNode *psGCPList = CPLGetXMLNode(psTree, "GCPList"))
     538             :     {
     539          48 :         OGRSpatialReference *poSRS = nullptr;
     540          48 :         GDALDeserializeGCPListFromXML(psGCPList, m_asGCPs, &poSRS);
     541          48 :         m_poGCP_SRS.reset(poSRS);
     542             :     }
     543             : 
     544             :     /* -------------------------------------------------------------------- */
     545             :     /*      Apply any dataset level metadata.                               */
     546             :     /* -------------------------------------------------------------------- */
     547        2593 :     oMDMD.XMLInit(psTree, TRUE);
     548             : 
     549             :     /* -------------------------------------------------------------------- */
     550             :     /*      Create dataset mask band.                                       */
     551             :     /* -------------------------------------------------------------------- */
     552             : 
     553             :     /* Parse dataset mask band first */
     554        2593 :     const CPLXMLNode *psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
     555             : 
     556        2593 :     const CPLXMLNode *psChild = nullptr;
     557        2593 :     if (psMaskBandNode)
     558          23 :         psChild = psMaskBandNode->psChild;
     559             :     else
     560        2570 :         psChild = nullptr;
     561             : 
     562        2593 :     for (; psChild != nullptr; psChild = psChild->psNext)
     563             :     {
     564          23 :         if (psChild->eType == CXT_Element &&
     565          23 :             EQUAL(psChild->pszValue, "VRTRasterBand"))
     566             :         {
     567             :             const char *pszSubclass =
     568          23 :                 CPLGetXMLValue(psChild, "subclass", "VRTSourcedRasterBand");
     569             : 
     570          23 :             VRTRasterBand *poBand = InitBand(pszSubclass, 0, false);
     571          46 :             if (poBand != nullptr &&
     572          23 :                 poBand->XMLInit(psChild, pszVRTPathIn, m_oMapSharedSources) ==
     573             :                     CE_None)
     574             :             {
     575          23 :                 SetMaskBand(poBand);
     576          23 :                 break;
     577             :             }
     578             :             else
     579             :             {
     580           0 :                 delete poBand;
     581           0 :                 return CE_Failure;
     582             :             }
     583             :         }
     584             :     }
     585             : 
     586             :     /* -------------------------------------------------------------------- */
     587             :     /*      Create band information objects.                                */
     588             :     /* -------------------------------------------------------------------- */
     589        2593 :     int l_nBands = 0;
     590       13194 :     for (psChild = psTree->psChild; psChild != nullptr;
     591       10601 :          psChild = psChild->psNext)
     592             :     {
     593       10633 :         if (psChild->eType == CXT_Element &&
     594        5955 :             EQUAL(psChild->pszValue, "VRTRasterBand"))
     595             :         {
     596             :             const char *pszSubclass =
     597        2937 :                 CPLGetXMLValue(psChild, "subclass", "VRTSourcedRasterBand");
     598        2937 :             if (dynamic_cast<VRTProcessedDataset *>(this) &&
     599          36 :                 !EQUAL(pszSubclass, "VRTProcessedRasterBand"))
     600             :             {
     601           0 :                 CPLError(CE_Failure, CPLE_NotSupported,
     602             :                          "Only subClass=VRTProcessedRasterBand supported");
     603           0 :                 return CE_Failure;
     604             :             }
     605             : 
     606        4210 :             if (CPLGetXMLNode(psChild, "PixelFunctionType") != nullptr &&
     607        1273 :                 !EQUAL(pszSubclass, "VRTDerivedRasterBand"))
     608             :             {
     609           1 :                 CPLError(CE_Failure, CPLE_NotSupported,
     610             :                          "Pixel functions may only be used with "
     611             :                          "subClass=VRTDerivedRasterBand");
     612           1 :                 return CE_Failure;
     613             :             }
     614             : 
     615        2936 :             VRTRasterBand *poBand = InitBand(pszSubclass, l_nBands + 1, true);
     616        5871 :             if (poBand != nullptr &&
     617        2935 :                 poBand->XMLInit(psChild, pszVRTPathIn, m_oMapSharedSources) ==
     618             :                     CE_None)
     619             :             {
     620        2905 :                 l_nBands++;
     621        2905 :                 SetBand(l_nBands, poBand);
     622             :             }
     623             :             else
     624             :             {
     625          31 :                 delete poBand;
     626          31 :                 return CE_Failure;
     627             :             }
     628             :         }
     629             :     }
     630             : 
     631        2561 :     if (const CPLXMLNode *psGroup = CPLGetXMLNode(psTree, "Group"))
     632             :     {
     633         233 :         const char *pszName = CPLGetXMLValue(psGroup, "name", nullptr);
     634         233 :         if (pszName == nullptr || !EQUAL(pszName, "/"))
     635             :         {
     636           2 :             CPLError(CE_Failure, CPLE_AppDefined,
     637             :                      "Missing name or not equal to '/'");
     638           2 :             return CE_Failure;
     639             :         }
     640             : 
     641         231 :         m_poRootGroup = VRTGroup::Create(std::string(), "/");
     642         231 :         m_poRootGroup->SetIsRootGroup();
     643         231 :         if (!m_poRootGroup->XMLInit(m_poRootGroup, m_poRootGroup, psGroup,
     644             :                                     pszVRTPathIn))
     645             :         {
     646          21 :             return CE_Failure;
     647             :         }
     648             :     }
     649             : 
     650             :     /* -------------------------------------------------------------------- */
     651             :     /*      Create virtual overviews.                                       */
     652             :     /* -------------------------------------------------------------------- */
     653        2538 :     const char *pszSubClass = CPLGetXMLValue(psTree, "subClass", "");
     654        2538 :     if (EQUAL(pszSubClass, ""))
     655             :     {
     656             :         m_aosOverviewList =
     657        2170 :             CSLTokenizeString(CPLGetXMLValue(psTree, "OverviewList", ""));
     658             :         m_osOverviewResampling =
     659        2170 :             CPLGetXMLValue(psTree, "OverviewList.resampling", "");
     660             :     }
     661             : 
     662        2538 :     return CE_None;
     663             : }
     664             : 
     665             : /************************************************************************/
     666             : /*                            GetGCPCount()                             */
     667             : /************************************************************************/
     668             : 
     669        2172 : int VRTDataset::GetGCPCount()
     670             : 
     671             : {
     672        2172 :     return static_cast<int>(m_asGCPs.size());
     673             : }
     674             : 
     675             : /************************************************************************/
     676             : /*                               GetGCPs()                              */
     677             : /************************************************************************/
     678             : 
     679          75 : const GDAL_GCP *VRTDataset::GetGCPs()
     680             : 
     681             : {
     682          75 :     return gdal::GCP::c_ptr(m_asGCPs);
     683             : }
     684             : 
     685             : /************************************************************************/
     686             : /*                              SetGCPs()                               */
     687             : /************************************************************************/
     688             : 
     689          33 : CPLErr VRTDataset::SetGCPs(int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
     690             :                            const OGRSpatialReference *poGCP_SRS)
     691             : 
     692             : {
     693          33 :     m_poGCP_SRS.reset(poGCP_SRS ? poGCP_SRS->Clone() : nullptr);
     694          33 :     m_asGCPs = gdal::GCP::fromC(pasGCPListIn, nGCPCountIn);
     695             : 
     696          33 :     SetNeedsFlush();
     697             : 
     698          33 :     return CE_None;
     699             : }
     700             : 
     701             : /************************************************************************/
     702             : /*                           SetSpatialRef()                            */
     703             : /************************************************************************/
     704             : 
     705        2243 : CPLErr VRTDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
     706             : 
     707             : {
     708        2243 :     m_poSRS.reset(poSRS ? poSRS->Clone() : nullptr);
     709             : 
     710        2243 :     SetNeedsFlush();
     711             : 
     712        2243 :     return CE_None;
     713             : }
     714             : 
     715             : /************************************************************************/
     716             : /*                          SetGeoTransform()                           */
     717             : /************************************************************************/
     718             : 
     719        2378 : CPLErr VRTDataset::SetGeoTransform(double *padfGeoTransformIn)
     720             : 
     721             : {
     722        2378 :     memcpy(m_adfGeoTransform, padfGeoTransformIn, sizeof(double) * 6);
     723        2378 :     m_bGeoTransformSet = TRUE;
     724             : 
     725        2378 :     SetNeedsFlush();
     726             : 
     727        2378 :     return CE_None;
     728             : }
     729             : 
     730             : /************************************************************************/
     731             : /*                          GetGeoTransform()                           */
     732             : /************************************************************************/
     733             : 
     734        7522 : CPLErr VRTDataset::GetGeoTransform(double *padfGeoTransform)
     735             : 
     736             : {
     737        7522 :     memcpy(padfGeoTransform, m_adfGeoTransform, sizeof(double) * 6);
     738             : 
     739        7522 :     return m_bGeoTransformSet ? CE_None : CE_Failure;
     740             : }
     741             : 
     742             : /************************************************************************/
     743             : /*                            SetMetadata()                             */
     744             : /************************************************************************/
     745             : 
     746        2108 : CPLErr VRTDataset::SetMetadata(char **papszMetadata, const char *pszDomain)
     747             : 
     748             : {
     749        2108 :     SetNeedsFlush();
     750             : 
     751        2108 :     return GDALDataset::SetMetadata(papszMetadata, pszDomain);
     752             : }
     753             : 
     754             : /************************************************************************/
     755             : /*                          SetMetadataItem()                           */
     756             : /************************************************************************/
     757             : 
     758        2204 : CPLErr VRTDataset::SetMetadataItem(const char *pszName, const char *pszValue,
     759             :                                    const char *pszDomain)
     760             : 
     761             : {
     762        2204 :     SetNeedsFlush();
     763             : 
     764        2204 :     return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
     765             : }
     766             : 
     767             : /************************************************************************/
     768             : /*                              Identify()                              */
     769             : /************************************************************************/
     770             : 
     771       91345 : int VRTDataset::Identify(GDALOpenInfo *poOpenInfo)
     772             : 
     773             : {
     774       91345 :     if (poOpenInfo->nHeaderBytes > 20 &&
     775       32249 :         strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
     776             :                "<VRTDataset") != nullptr)
     777        2138 :         return TRUE;
     778             : 
     779       89207 :     if (strstr(poOpenInfo->pszFilename, "<VRTDataset") != nullptr)
     780        2961 :         return TRUE;
     781             : 
     782       86246 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, VRT_PROTOCOL_PREFIX))
     783         146 :         return TRUE;
     784             : 
     785       86100 :     return FALSE;
     786             : }
     787             : 
     788             : /************************************************************************/
     789             : /*                                Open()                                */
     790             : /************************************************************************/
     791             : 
     792        2606 : GDALDataset *VRTDataset::Open(GDALOpenInfo *poOpenInfo)
     793             : 
     794             : {
     795             :     /* -------------------------------------------------------------------- */
     796             :     /*      Does this appear to be a virtual dataset definition XML         */
     797             :     /*      file?                                                           */
     798             :     /* -------------------------------------------------------------------- */
     799        2606 :     if (!Identify(poOpenInfo))
     800           0 :         return nullptr;
     801             : 
     802        2606 :     if (STARTS_WITH_CI(poOpenInfo->pszFilename, VRT_PROTOCOL_PREFIX))
     803          73 :         return OpenVRTProtocol(poOpenInfo->pszFilename);
     804             : 
     805             :     /* -------------------------------------------------------------------- */
     806             :     /*      Try to read the whole file into memory.                         */
     807             :     /* -------------------------------------------------------------------- */
     808        2533 :     char *pszXML = nullptr;
     809        2533 :     VSILFILE *fp = poOpenInfo->fpL;
     810             : 
     811        2533 :     char *pszVRTPath = nullptr;
     812        2533 :     if (fp != nullptr)
     813             :     {
     814        1053 :         poOpenInfo->fpL = nullptr;
     815             : 
     816        1053 :         GByte *pabyOut = nullptr;
     817        1053 :         if (!VSIIngestFile(fp, poOpenInfo->pszFilename, &pabyOut, nullptr,
     818             :                            INT_MAX - 1))
     819             :         {
     820           0 :             CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     821           0 :             return nullptr;
     822             :         }
     823        1053 :         pszXML = reinterpret_cast<char *>(pabyOut);
     824             : 
     825        1053 :         char *pszCurDir = CPLGetCurrentDir();
     826             :         std::string currentVrtFilename =
     827        1053 :             CPLProjectRelativeFilenameSafe(pszCurDir, poOpenInfo->pszFilename);
     828        1053 :         CPLString osInitialCurrentVrtFilename(currentVrtFilename);
     829        1053 :         CPLFree(pszCurDir);
     830             : 
     831             : #if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
     832             :         char filenameBuffer[2048];
     833             : 
     834             :         while (true)
     835             :         {
     836             :             VSIStatBuf statBuffer;
     837        1057 :             int lstatCode = lstat(currentVrtFilename.c_str(), &statBuffer);
     838        1057 :             if (lstatCode == -1)
     839             :             {
     840         261 :                 if (errno == ENOENT)
     841             :                 {
     842             :                     // File could be a virtual file, let later checks handle it.
     843         261 :                     break;
     844             :                 }
     845             :                 else
     846             :                 {
     847           0 :                     CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     848           0 :                     CPLFree(pszXML);
     849           0 :                     CPLError(CE_Failure, CPLE_FileIO, "Failed to lstat %s: %s",
     850           0 :                              currentVrtFilename.c_str(), VSIStrerror(errno));
     851           0 :                     return nullptr;
     852             :                 }
     853             :             }
     854             : 
     855         796 :             if (!VSI_ISLNK(statBuffer.st_mode))
     856             :             {
     857         792 :                 break;
     858             :             }
     859             : 
     860             :             const int bufferSize = static_cast<int>(
     861           4 :                 readlink(currentVrtFilename.c_str(), filenameBuffer,
     862           4 :                          sizeof(filenameBuffer)));
     863           4 :             if (bufferSize != -1)
     864             :             {
     865           4 :                 filenameBuffer[std::min(
     866           4 :                     bufferSize, static_cast<int>(sizeof(filenameBuffer)) - 1)] =
     867             :                     0;
     868             :                 // The filename in filenameBuffer might be a relative path
     869             :                 // from the linkfile resolve it before looping
     870           8 :                 currentVrtFilename = CPLProjectRelativeFilenameSafe(
     871           8 :                     CPLGetDirnameSafe(currentVrtFilename.c_str()).c_str(),
     872           4 :                     filenameBuffer);
     873             :             }
     874             :             else
     875             :             {
     876           0 :                 CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     877           0 :                 CPLFree(pszXML);
     878           0 :                 CPLError(CE_Failure, CPLE_FileIO,
     879             :                          "Failed to read filename from symlink %s: %s",
     880           0 :                          currentVrtFilename.c_str(), VSIStrerror(errno));
     881           0 :                 return nullptr;
     882             :             }
     883           4 :         }
     884             : #endif  // HAVE_READLINK && HAVE_LSTAT
     885             : 
     886        1053 :         if (osInitialCurrentVrtFilename == currentVrtFilename)
     887             :             pszVRTPath =
     888        1050 :                 CPLStrdup(CPLGetPathSafe(poOpenInfo->pszFilename).c_str());
     889             :         else
     890             :             pszVRTPath =
     891           3 :                 CPLStrdup(CPLGetPathSafe(currentVrtFilename.c_str()).c_str());
     892             : 
     893        1053 :         CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
     894             :     }
     895             :     /* -------------------------------------------------------------------- */
     896             :     /*      Or use the filename as the XML input.                           */
     897             :     /* -------------------------------------------------------------------- */
     898             :     else
     899             :     {
     900        1480 :         pszXML = CPLStrdup(poOpenInfo->pszFilename);
     901             :     }
     902             : 
     903        2533 :     if (CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH") != nullptr)
     904             :     {
     905           5 :         CPLFree(pszVRTPath);
     906           5 :         pszVRTPath = CPLStrdup(
     907           5 :             CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH"));
     908             :     }
     909             : 
     910             :     /* -------------------------------------------------------------------- */
     911             :     /*      Turn the XML representation into a VRTDataset.                  */
     912             :     /* -------------------------------------------------------------------- */
     913        5066 :     auto poDS = OpenXML(pszXML, pszVRTPath, poOpenInfo->eAccess);
     914             : 
     915        2533 :     if (poDS != nullptr)
     916        2413 :         poDS->m_bNeedsFlush = false;
     917             : 
     918        2533 :     if (poDS != nullptr)
     919             :     {
     920        2413 :         if (poDS->GetRasterCount() == 0 &&
     921        2414 :             (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) == 0 &&
     922           1 :             strstr(pszXML, "VRTPansharpenedDataset") == nullptr)
     923             :         {
     924           0 :             poDS.reset();
     925             :         }
     926        4826 :         else if (poDS->GetRootGroup() == nullptr &&
     927        4826 :                  (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
     928           0 :                  (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
     929             :         {
     930           0 :             poDS.reset();
     931             :         }
     932             :     }
     933             : 
     934        2533 :     CPLFree(pszXML);
     935        2533 :     CPLFree(pszVRTPath);
     936             : 
     937             :     /* -------------------------------------------------------------------- */
     938             :     /*      Initialize info for later overview discovery.                   */
     939             :     /* -------------------------------------------------------------------- */
     940             : 
     941        2533 :     if (poDS != nullptr)
     942             :     {
     943        2413 :         if (fp != nullptr)
     944             :         {
     945        1045 :             poDS->oOvManager.Initialize(poDS.get(), poOpenInfo->pszFilename);
     946        1045 :             if (poOpenInfo->AreSiblingFilesLoaded())
     947           2 :                 poDS->oOvManager.TransferSiblingFiles(
     948             :                     poOpenInfo->StealSiblingFiles());
     949             :         }
     950             : 
     951             :         // Creating virtual overviews, but only if there is no higher priority
     952             :         // overview source, ie. a Overview element at VRT band level,
     953             :         // or external .vrt.ovr
     954        2413 :         if (!poDS->m_aosOverviewList.empty())
     955             :         {
     956           7 :             if (poDS->nBands > 0)
     957             :             {
     958           7 :                 auto poBand = dynamic_cast<VRTRasterBand *>(poDS->papoBands[0]);
     959           7 :                 if (poBand && !poBand->m_aoOverviewInfos.empty())
     960             :                 {
     961           0 :                     poDS->m_aosOverviewList.Clear();
     962           0 :                     CPLDebug("VRT",
     963             :                              "Ignoring virtual overviews of OverviewList "
     964             :                              "because Overview element is present on VRT band");
     965             :                 }
     966          14 :                 else if (poBand &&
     967           7 :                          poBand->GDALRasterBand::GetOverviewCount() > 0)
     968             :                 {
     969           1 :                     poDS->m_aosOverviewList.Clear();
     970           1 :                     CPLDebug("VRT",
     971             :                              "Ignoring virtual overviews of OverviewList "
     972             :                              "because external .vrt.ovr is available");
     973             :                 }
     974             :             }
     975          19 :             for (int iOverview = 0; iOverview < poDS->m_aosOverviewList.size();
     976             :                  iOverview++)
     977             :             {
     978          12 :                 const int nOvFactor = atoi(poDS->m_aosOverviewList[iOverview]);
     979          12 :                 if (nOvFactor <= 1)
     980             :                 {
     981           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
     982             :                              "Invalid overview factor");
     983           0 :                     return nullptr;
     984             :                 }
     985             : 
     986          36 :                 poDS->AddVirtualOverview(
     987          12 :                     nOvFactor, poDS->m_osOverviewResampling.empty()
     988             :                                    ? "nearest"
     989          12 :                                    : poDS->m_osOverviewResampling.c_str());
     990             :             }
     991           7 :             poDS->m_aosOverviewList.Clear();
     992             :         }
     993             : 
     994        2491 :         if (poDS->eAccess == GA_Update && poDS->m_poRootGroup &&
     995          78 :             !STARTS_WITH_CI(poOpenInfo->pszFilename, "<VRT"))
     996             :         {
     997          78 :             poDS->m_poRootGroup->SetFilename(poOpenInfo->pszFilename);
     998             :         }
     999             :     }
    1000             : 
    1001        2533 :     return poDS.release();
    1002             : }
    1003             : 
    1004             : /************************************************************************/
    1005             : /*                         OpenVRTProtocol()                            */
    1006             : /*                                                                      */
    1007             : /*      Create an open VRTDataset from a vrt:// string.                 */
    1008             : /************************************************************************/
    1009             : 
    1010          73 : GDALDataset *VRTDataset::OpenVRTProtocol(const char *pszSpec)
    1011             : 
    1012             : {
    1013          73 :     CPLAssert(STARTS_WITH_CI(pszSpec, VRT_PROTOCOL_PREFIX));
    1014         146 :     CPLString osFilename(pszSpec + strlen(VRT_PROTOCOL_PREFIX));
    1015          73 :     const auto nPosQuotationMark = osFilename.find('?');
    1016         146 :     CPLString osQueryString;
    1017          73 :     if (nPosQuotationMark != std::string::npos)
    1018             :     {
    1019          65 :         osQueryString = osFilename.substr(nPosQuotationMark + 1);
    1020          65 :         osFilename.resize(nPosQuotationMark);
    1021             :     }
    1022             : 
    1023             :     // Parse query string, get args required for initial Open()
    1024         146 :     const CPLStringList aosTokens(CSLTokenizeString2(osQueryString, "&", 0));
    1025         146 :     CPLStringList aosAllowedDrivers;
    1026         146 :     CPLStringList aosOpenOptions;
    1027             : 
    1028         166 :     for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(
    1029         235 :              aosTokens, /* bReturnNullKeyIfNotNameValue = */ true))
    1030             :     {
    1031          85 :         if (!pszKey)
    1032             :         {
    1033           2 :             CPLError(CE_Failure, CPLE_NotSupported,
    1034             :                      "Invalid option specification: %s\n"
    1035             :                      "must be in the form 'key=value'",
    1036             :                      pszValue);
    1037           4 :             return nullptr;
    1038             :         }
    1039          83 :         else if (EQUAL(pszKey, "if"))
    1040             :         {
    1041           4 :             if (!aosAllowedDrivers.empty())
    1042             :             {
    1043           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1044             :                          "'if' option should be specified once, use commas "
    1045             :                          "to input multiple values.");
    1046           1 :                 return nullptr;
    1047             :             }
    1048           3 :             aosAllowedDrivers = CSLTokenizeString2(pszValue, ",", 0);
    1049             :         }
    1050          79 :         else if (EQUAL(pszKey, "oo"))
    1051             :         {
    1052           3 :             if (!aosOpenOptions.empty())
    1053             :             {
    1054           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1055             :                          "'oo' option should be specified once, use commas "
    1056             :                          "to input multiple values.");
    1057           1 :                 return nullptr;
    1058             :             }
    1059           2 :             aosOpenOptions = CSLTokenizeString2(pszValue, ",", 0);
    1060             :         }
    1061             :     }
    1062             : 
    1063             :     // We don't open in GDAL_OF_SHARED mode to avoid issues when we open a
    1064             :     // http://.jp2 file with the JP2OpenJPEG driver through the HTTP driver,
    1065             :     // which returns a /vsimem/ file
    1066             :     auto poSrcDS = std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser>(
    1067             :         GDALDataset::Open(osFilename, GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
    1068          69 :                           aosAllowedDrivers.List(), aosOpenOptions.List(),
    1069         138 :                           nullptr));
    1070          69 :     if (poSrcDS == nullptr)
    1071             :     {
    1072           4 :         return nullptr;
    1073             :     }
    1074             : 
    1075          65 :     bool bFound_transpose = false;
    1076         142 :     for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(aosTokens))
    1077             :     {
    1078          77 :         if (EQUAL(pszKey, "transpose"))
    1079             :         {
    1080           4 :             bFound_transpose = true;
    1081             :             const CPLStringList aosTransposeTokens(
    1082           4 :                 CSLTokenizeString2(pszValue, ":", 0));
    1083           4 :             if (aosTransposeTokens.size() != 2)
    1084             :             {
    1085           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1086             :                          "Invalid transpose option: %s", pszValue);
    1087           0 :                 return nullptr;
    1088             :             }
    1089             :             const CPLStringList aosTransposeIndex(
    1090           4 :                 CSLTokenizeString2(aosTransposeTokens[1], ",", 0));
    1091             :             // fail if not two values
    1092           4 :             if (aosTransposeIndex.size() != 2)
    1093             :             {
    1094           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1095             :                          "Invalid transpose option: %s", pszValue);
    1096           0 :                 return nullptr;
    1097             :             }
    1098           4 :             int index_x = atoi(aosTransposeIndex[0]);
    1099           4 :             int index_y = atoi(aosTransposeIndex[1]);
    1100             : 
    1101             :             auto poMDimDS = std::unique_ptr<GDALDataset>(
    1102           4 :                 GDALDataset::Open(osFilename, GDAL_OF_MULTIDIM_RASTER));
    1103           4 :             if (!poMDimDS)
    1104           0 :                 return nullptr;
    1105           4 :             auto poMdimGroup = poMDimDS->GetRootGroup();
    1106           4 :             if (!poMdimGroup)
    1107             :             {
    1108           0 :                 return nullptr;
    1109             :             }
    1110             :             auto poArray =
    1111           8 :                 poMdimGroup->OpenMDArrayFromFullname(aosTransposeTokens[0]);
    1112           4 :             if (!poArray)
    1113             :             {
    1114           0 :                 return nullptr;
    1115             :             }
    1116             : 
    1117           4 :             auto poClassicDS = poArray->AsClassicDataset(index_x, index_y);
    1118             : 
    1119           4 :             if (!poClassicDS)
    1120           0 :                 return nullptr;
    1121             :             poSrcDS =
    1122           8 :                 std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser>(
    1123           4 :                     poClassicDS);
    1124             :         }
    1125             :     }
    1126             :     // scan for sd_name/sd in tokens, close the source dataset and reopen if found/valid
    1127          65 :     bool bFound_subdataset = false;
    1128         135 :     for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(aosTokens))
    1129             :     {
    1130          75 :         if (EQUAL(pszKey, "sd_name"))
    1131             :         {
    1132           5 :             if (bFound_transpose)
    1133             :             {
    1134           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1135             :                          "'sd_name' is mutually exclusive with option "
    1136             :                          "'transpose'");
    1137           5 :                 return nullptr;
    1138             :             }
    1139           4 :             if (bFound_subdataset)
    1140             :             {
    1141           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1142             :                          "'sd_name' is mutually exclusive with option "
    1143             :                          "'sd'");
    1144           1 :                 return nullptr;
    1145             :             }
    1146           3 :             char **papszSubdatasets = poSrcDS->GetMetadata("SUBDATASETS");
    1147           3 :             int nSubdatasets = CSLCount(papszSubdatasets);
    1148             : 
    1149           3 :             if (nSubdatasets > 0)
    1150             :             {
    1151           3 :                 bool bFound = false;
    1152          25 :                 for (int j = 0; j < nSubdatasets && papszSubdatasets[j]; j += 2)
    1153             :                 {
    1154          24 :                     const char *pszEqual = strchr(papszSubdatasets[j], '=');
    1155          24 :                     if (!pszEqual)
    1156             :                     {
    1157           0 :                         CPLError(CE_Failure, CPLE_IllegalArg,
    1158             :                                  "'sd_name:' failed to obtain "
    1159             :                                  "subdataset string ");
    1160           0 :                         return nullptr;
    1161             :                     }
    1162          24 :                     const char *pszSubdatasetSource = pszEqual + 1;
    1163             :                     GDALSubdatasetInfoH info =
    1164          24 :                         GDALGetSubdatasetInfo(pszSubdatasetSource);
    1165             :                     char *component =
    1166          24 :                         info ? GDALSubdatasetInfoGetSubdatasetComponent(info)
    1167          24 :                              : nullptr;
    1168             : 
    1169          24 :                     bFound = component && EQUAL(pszValue, component);
    1170          24 :                     bFound_subdataset = true;
    1171          24 :                     CPLFree(component);
    1172          24 :                     GDALDestroySubdatasetInfo(info);
    1173          24 :                     if (bFound)
    1174             :                     {
    1175           2 :                         poSrcDS.reset(GDALDataset::Open(
    1176             :                             pszSubdatasetSource,
    1177             :                             GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
    1178           2 :                             aosAllowedDrivers.List(), aosOpenOptions.List(),
    1179             :                             nullptr));
    1180           2 :                         if (poSrcDS == nullptr)
    1181             :                         {
    1182           0 :                             return nullptr;
    1183             :                         }
    1184             : 
    1185           2 :                         break;
    1186             :                     }
    1187             :                 }
    1188             : 
    1189           3 :                 if (!bFound)
    1190             :                 {
    1191           1 :                     CPLError(CE_Failure, CPLE_IllegalArg,
    1192             :                              "'sd_name' option should be be a valid "
    1193             :                              "subdataset component name");
    1194           1 :                     return nullptr;
    1195             :                 }
    1196             :             }
    1197             :         }
    1198             : 
    1199          72 :         if (EQUAL(pszKey, "sd"))
    1200             :         {
    1201           4 :             if (bFound_transpose)
    1202             :             {
    1203           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1204             :                          "'sd' is mutually exclusive with option "
    1205             :                          "'transpose'");
    1206           1 :                 return nullptr;
    1207             :             }
    1208           3 :             if (bFound_subdataset)
    1209             :             {
    1210           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1211             :                          "'sd' is mutually exclusive with option "
    1212             :                          "'sd_name'");
    1213           0 :                 return nullptr;
    1214             :             }
    1215           3 :             CSLConstList papszSubdatasets = poSrcDS->GetMetadata("SUBDATASETS");
    1216           3 :             int nSubdatasets = CSLCount(papszSubdatasets);
    1217             : 
    1218           3 :             if (nSubdatasets > 0)
    1219             :             {
    1220           3 :                 int iSubdataset = atoi(pszValue);
    1221           3 :                 if (iSubdataset < 1 || iSubdataset > (nSubdatasets) / 2)
    1222             :                 {
    1223           1 :                     CPLError(CE_Failure, CPLE_IllegalArg,
    1224             :                              "'sd' option should indicate a valid "
    1225             :                              "subdataset component number (starting with 1)");
    1226           1 :                     return nullptr;
    1227             :                 }
    1228             :                 const std::string osSubdatasetSource(
    1229           2 :                     strstr(papszSubdatasets[(iSubdataset - 1) * 2], "=") + 1);
    1230           2 :                 if (osSubdatasetSource.empty())
    1231             :                 {
    1232           0 :                     CPLError(CE_Failure, CPLE_IllegalArg,
    1233             :                              "'sd:' failed to obtain subdataset "
    1234             :                              "string ");
    1235           0 :                     return nullptr;
    1236             :                 }
    1237             : 
    1238           2 :                 poSrcDS.reset(GDALDataset::Open(
    1239             :                     osSubdatasetSource.c_str(),
    1240             :                     GDAL_OF_RASTER | GDAL_OF_VERBOSE_ERROR,
    1241           2 :                     aosAllowedDrivers.List(), aosOpenOptions.List(), nullptr));
    1242           2 :                 if (poSrcDS == nullptr)
    1243             :                 {
    1244           0 :                     return nullptr;
    1245             :                 }
    1246           2 :                 bFound_subdataset = true;
    1247             :             }
    1248             :         }
    1249             :     }
    1250             : 
    1251         120 :     std::vector<int> anBands;
    1252             : 
    1253         120 :     CPLStringList argv;
    1254          60 :     argv.AddString("-of");
    1255          60 :     argv.AddString("VRT");
    1256             : 
    1257         119 :     for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(aosTokens))
    1258             :     {
    1259          69 :         if (EQUAL(pszKey, "bands"))
    1260             :         {
    1261           6 :             const CPLStringList aosBands(CSLTokenizeString2(pszValue, ",", 0));
    1262          12 :             for (int j = 0; j < aosBands.size(); j++)
    1263             :             {
    1264           9 :                 if (EQUAL(aosBands[j], "mask"))
    1265             :                 {
    1266           1 :                     anBands.push_back(0);
    1267             :                 }
    1268             :                 else
    1269             :                 {
    1270           8 :                     const int nBand = atoi(aosBands[j]);
    1271           8 :                     if (nBand <= 0 || nBand > poSrcDS->GetRasterCount())
    1272             :                     {
    1273           3 :                         CPLError(CE_Failure, CPLE_IllegalArg,
    1274             :                                  "Invalid band number: %s", aosBands[j]);
    1275           3 :                         return nullptr;
    1276             :                     }
    1277           5 :                     anBands.push_back(nBand);
    1278             :                 }
    1279             :             }
    1280             : 
    1281           9 :             for (const int nBand : anBands)
    1282             :             {
    1283           6 :                 argv.AddString("-b");
    1284           6 :                 argv.AddString(nBand == 0 ? "mask" : CPLSPrintf("%d", nBand));
    1285             :             }
    1286             :         }
    1287             : 
    1288          63 :         else if (EQUAL(pszKey, "a_nodata"))
    1289             :         {
    1290           1 :             argv.AddString("-a_nodata");
    1291           1 :             argv.AddString(pszValue);
    1292             :         }
    1293             : 
    1294          62 :         else if (EQUAL(pszKey, "a_srs"))
    1295             :         {
    1296           1 :             argv.AddString("-a_srs");
    1297           1 :             argv.AddString(pszValue);
    1298             :         }
    1299             : 
    1300          61 :         else if (EQUAL(pszKey, "a_ullr"))
    1301             :         {
    1302             :             // Parse the limits
    1303           1 :             const CPLStringList aosUllr(CSLTokenizeString2(pszValue, ",", 0));
    1304             :             // fail if not four values
    1305           1 :             if (aosUllr.size() != 4)
    1306             :             {
    1307           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1308             :                          "Invalid a_ullr option: %s", pszValue);
    1309           0 :                 return nullptr;
    1310             :             }
    1311             : 
    1312           1 :             argv.AddString("-a_ullr");
    1313           1 :             argv.AddString(aosUllr[0]);
    1314           1 :             argv.AddString(aosUllr[1]);
    1315           1 :             argv.AddString(aosUllr[2]);
    1316           1 :             argv.AddString(aosUllr[3]);
    1317             :         }
    1318             : 
    1319          60 :         else if (EQUAL(pszKey, "ovr"))
    1320             :         {
    1321           1 :             argv.AddString("-ovr");
    1322           1 :             argv.AddString(pszValue);
    1323             :         }
    1324          59 :         else if (EQUAL(pszKey, "expand"))
    1325             :         {
    1326           1 :             argv.AddString("-expand");
    1327           1 :             argv.AddString(pszValue);
    1328             :         }
    1329          58 :         else if (EQUAL(pszKey, "a_scale"))
    1330             :         {
    1331           2 :             argv.AddString("-a_scale");
    1332           2 :             argv.AddString(pszValue);
    1333             :         }
    1334          56 :         else if (EQUAL(pszKey, "a_offset"))
    1335             :         {
    1336           1 :             argv.AddString("-a_offset");
    1337           1 :             argv.AddString(pszValue);
    1338             :         }
    1339          55 :         else if (EQUAL(pszKey, "ot"))
    1340             :         {
    1341           2 :             argv.AddString("-ot");
    1342           2 :             argv.AddString(pszValue);
    1343             :         }
    1344          53 :         else if (EQUAL(pszKey, "gcp"))
    1345             :         {
    1346           6 :             const CPLStringList aosGCP(CSLTokenizeString2(pszValue, ",", 0));
    1347             : 
    1348           6 :             if (aosGCP.size() < 4 || aosGCP.size() > 5)
    1349             :             {
    1350           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1351             :                          "Invalid value for GCP: %s\n  need 4, or 5 "
    1352             :                          "numbers, comma separated: "
    1353             :                          "'gcp=<pixel>,<line>,<easting>,<northing>[,<"
    1354             :                          "elevation>]'",
    1355             :                          pszValue);
    1356           1 :                 return nullptr;
    1357             :             }
    1358           5 :             argv.AddString("-gcp");
    1359          28 :             for (int j = 0; j < aosGCP.size(); j++)
    1360             :             {
    1361          23 :                 argv.AddString(aosGCP[j]);
    1362             :             }
    1363             :         }
    1364          47 :         else if (EQUAL(pszKey, "scale") || STARTS_WITH_CI(pszKey, "scale_"))
    1365             :         {
    1366             :             const CPLStringList aosScaleParams(
    1367           7 :                 CSLTokenizeString2(pszValue, ",", 0));
    1368             : 
    1369           7 :             if (!(aosScaleParams.size() == 2) &&
    1370           7 :                 !(aosScaleParams.size() == 4) && !(aosScaleParams.size() == 1))
    1371             :             {
    1372           0 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1373             :                          "Invalid value for scale, (or scale_bn): "
    1374             :                          "%s\n  need 'scale=true', or 2 or 4 "
    1375             :                          "numbers, comma separated: "
    1376             :                          "'scale=src_min,src_max[,dst_min,dst_max]' or "
    1377             :                          "'scale_bn=src_min,src_max[,dst_min,dst_max]'",
    1378             :                          pszValue);
    1379           0 :                 return nullptr;
    1380             :             }
    1381             : 
    1382             :             // -scale because scale=true or scale=min,max or scale=min,max,dstmin,dstmax
    1383           7 :             if (aosScaleParams.size() == 1 && CPLTestBool(aosScaleParams[0]))
    1384             :             {
    1385           2 :                 argv.AddString(CPLSPrintf("-%s", pszKey));
    1386             :             }
    1387             :             // add remaining params (length 2 or 4)
    1388           7 :             if (aosScaleParams.size() > 1)
    1389             :             {
    1390           5 :                 argv.AddString(CPLSPrintf("-%s", pszKey));
    1391          21 :                 for (int j = 0; j < aosScaleParams.size(); j++)
    1392             :                 {
    1393          16 :                     argv.AddString(aosScaleParams[j]);
    1394             :                 }
    1395           7 :             }
    1396             :         }
    1397          40 :         else if (EQUAL(pszKey, "exponent") ||
    1398          38 :                  STARTS_WITH_CI(pszKey, "exponent_"))
    1399             :         {
    1400           3 :             argv.AddString(CPLSPrintf("-%s", pszKey));
    1401           3 :             argv.AddString(pszValue);
    1402             :         }
    1403          37 :         else if (EQUAL(pszKey, "outsize"))
    1404             :         {
    1405             :             const CPLStringList aosOutSize(
    1406           4 :                 CSLTokenizeString2(pszValue, ",", 0));
    1407           4 :             if (aosOutSize.size() != 2)
    1408             :             {
    1409           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1410             :                          "Invalid outsize option: %s, must be two"
    1411             :                          "values separated by comma pixel,line or two "
    1412             :                          "fraction values with percent symbol",
    1413             :                          pszValue);
    1414           1 :                 return nullptr;
    1415             :             }
    1416           3 :             argv.AddString("-outsize");
    1417           3 :             argv.AddString(aosOutSize[0]);
    1418           3 :             argv.AddString(aosOutSize[1]);
    1419             :         }
    1420          33 :         else if (EQUAL(pszKey, "projwin"))
    1421             :         {
    1422             :             // Parse the limits
    1423             :             const CPLStringList aosProjWin(
    1424           3 :                 CSLTokenizeString2(pszValue, ",", 0));
    1425             :             // fail if not four values
    1426           3 :             if (aosProjWin.size() != 4)
    1427             :             {
    1428           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1429             :                          "Invalid projwin option: %s", pszValue);
    1430           1 :                 return nullptr;
    1431             :             }
    1432             : 
    1433           2 :             argv.AddString("-projwin");
    1434           2 :             argv.AddString(aosProjWin[0]);
    1435           2 :             argv.AddString(aosProjWin[1]);
    1436           2 :             argv.AddString(aosProjWin[2]);
    1437           2 :             argv.AddString(aosProjWin[3]);
    1438             :         }
    1439          30 :         else if (EQUAL(pszKey, "projwin_srs"))
    1440             :         {
    1441           2 :             argv.AddString("-projwin_srs");
    1442           2 :             argv.AddString(pszValue);
    1443             :         }
    1444          28 :         else if (EQUAL(pszKey, "tr"))
    1445             :         {
    1446             :             const CPLStringList aosTargetResolution(
    1447           3 :                 CSLTokenizeString2(pszValue, ",", 0));
    1448           3 :             if (aosTargetResolution.size() != 2)
    1449             :             {
    1450           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1451             :                          "Invalid tr option: %s, must be two "
    1452             :                          "values separated by comma xres,yres",
    1453             :                          pszValue);
    1454           1 :                 return nullptr;
    1455             :             }
    1456           2 :             argv.AddString("-tr");
    1457           2 :             argv.AddString(aosTargetResolution[0]);
    1458           2 :             argv.AddString(aosTargetResolution[1]);
    1459             :         }
    1460          25 :         else if (EQUAL(pszKey, "r"))
    1461             :         {
    1462           1 :             argv.AddString("-r");
    1463           1 :             argv.AddString(pszValue);
    1464             :         }
    1465             : 
    1466          24 :         else if (EQUAL(pszKey, "srcwin"))
    1467             :         {
    1468             :             // Parse the limits
    1469           6 :             const CPLStringList aosSrcWin(CSLTokenizeString2(pszValue, ",", 0));
    1470             :             // fail if not four values
    1471           6 :             if (aosSrcWin.size() != 4)
    1472             :             {
    1473           1 :                 CPLError(CE_Failure, CPLE_IllegalArg,
    1474             :                          "Invalid srcwin option: %s, must be four "
    1475             :                          "values separated by comma xoff,yoff,xsize,ysize",
    1476             :                          pszValue);
    1477           1 :                 return nullptr;
    1478             :             }
    1479             : 
    1480           5 :             argv.AddString("-srcwin");
    1481           5 :             argv.AddString(aosSrcWin[0]);
    1482           5 :             argv.AddString(aosSrcWin[1]);
    1483           5 :             argv.AddString(aosSrcWin[2]);
    1484           5 :             argv.AddString(aosSrcWin[3]);
    1485             :         }
    1486             : 
    1487          18 :         else if (EQUAL(pszKey, "a_gt"))
    1488             :         {
    1489             :             // Parse the limits
    1490             :             const CPLStringList aosAGeoTransform(
    1491           2 :                 CSLTokenizeString2(pszValue, ",", 0));
    1492             :             // fail if not six values
    1493           2 :             if (aosAGeoTransform.size() != 6)
    1494             :             {
    1495           1 :                 CPLError(CE_Failure, CPLE_IllegalArg, "Invalid a_gt option: %s",
    1496             :                          pszValue);
    1497           1 :                 return nullptr;
    1498             :             }
    1499             : 
    1500           1 :             argv.AddString("-a_gt");
    1501           1 :             argv.AddString(aosAGeoTransform[0]);
    1502           1 :             argv.AddString(aosAGeoTransform[1]);
    1503           1 :             argv.AddString(aosAGeoTransform[2]);
    1504           1 :             argv.AddString(aosAGeoTransform[3]);
    1505           1 :             argv.AddString(aosAGeoTransform[4]);
    1506           1 :             argv.AddString(aosAGeoTransform[5]);
    1507             :         }
    1508          16 :         else if (EQUAL(pszKey, "oo"))
    1509             :         {
    1510             :             // do nothing, we passed this in earlier
    1511             :         }
    1512          15 :         else if (EQUAL(pszKey, "if"))
    1513             :         {
    1514             :             // do nothing, we passed this in earlier
    1515             :         }
    1516          14 :         else if (EQUAL(pszKey, "sd_name"))
    1517             :         {
    1518             :             // do nothing, we passed this in earlier
    1519             :         }
    1520          12 :         else if (EQUAL(pszKey, "sd"))
    1521             :         {
    1522             :             // do nothing, we passed this in earlier
    1523             :         }
    1524          11 :         else if (EQUAL(pszKey, "transpose"))
    1525             :         {
    1526             :             // do nothing, we passed this in earlier
    1527             :         }
    1528           9 :         else if (EQUAL(pszKey, "unscale"))
    1529             :         {
    1530           1 :             if (CPLTestBool(pszValue))
    1531             :             {
    1532           1 :                 argv.AddString("-unscale");
    1533             :             }
    1534             :         }
    1535           8 :         else if (EQUAL(pszKey, "a_coord_epoch"))
    1536             :         {
    1537           0 :             argv.AddString("-a_coord_epoch");
    1538           0 :             argv.AddString(pszValue);
    1539             :         }
    1540           8 :         else if (EQUAL(pszKey, "nogcp"))
    1541             :         {
    1542           1 :             if (CPLTestBool(pszValue))
    1543             :             {
    1544           1 :                 argv.AddString("-nogcp");
    1545             :             }
    1546             :         }
    1547           7 :         else if (EQUAL(pszKey, "epo"))
    1548             :         {
    1549           3 :             if (CPLTestBool(pszValue))
    1550             :             {
    1551           2 :                 argv.AddString("-epo");
    1552             :             }
    1553             :         }
    1554           4 :         else if (EQUAL(pszKey, "eco"))
    1555             :         {
    1556           3 :             if (CPLTestBool(pszValue))
    1557             :             {
    1558           3 :                 argv.AddString("-eco");
    1559             :             }
    1560             :         }
    1561             : 
    1562             :         else
    1563             :         {
    1564           1 :             CPLError(CE_Failure, CPLE_NotSupported, "Unknown option: %s",
    1565             :                      pszKey);
    1566           1 :             return nullptr;
    1567             :         }
    1568             :     }
    1569             : 
    1570             :     GDALTranslateOptions *psOptions =
    1571          50 :         GDALTranslateOptionsNew(argv.List(), nullptr);
    1572             : 
    1573          50 :     auto hRet = GDALTranslate("", GDALDataset::ToHandle(poSrcDS.get()),
    1574             :                               psOptions, nullptr);
    1575             : 
    1576          50 :     GDALTranslateOptionsFree(psOptions);
    1577             : 
    1578             :     // Situation where we open a http://.jp2 file with the JP2OpenJPEG driver
    1579             :     // through the HTTP driver, which returns a /vsimem/ file
    1580             :     const bool bPatchSourceFilename =
    1581          50 :         (STARTS_WITH(osFilename.c_str(), "http://") ||
    1582          51 :          STARTS_WITH(osFilename.c_str(), "https://")) &&
    1583           1 :         osFilename != poSrcDS->GetDescription();
    1584             : 
    1585          50 :     poSrcDS.reset();
    1586             : 
    1587          50 :     auto poDS = dynamic_cast<VRTDataset *>(GDALDataset::FromHandle(hRet));
    1588          50 :     if (poDS)
    1589             :     {
    1590          47 :         if (bPatchSourceFilename)
    1591             :         {
    1592           2 :             for (int i = 0; i < poDS->nBands; ++i)
    1593             :             {
    1594             :                 auto poBand =
    1595           1 :                     dynamic_cast<VRTSourcedRasterBand *>(poDS->papoBands[i]);
    1596           2 :                 if (poBand && poBand->nSources == 1 &&
    1597           1 :                     poBand->papoSources[0]->IsSimpleSource())
    1598             :                 {
    1599           2 :                     auto poSource = cpl::down_cast<VRTSimpleSource *>(
    1600           1 :                         poBand->papoSources[0]);
    1601           1 :                     poSource->m_bRelativeToVRTOri = 0;
    1602           1 :                     poSource->m_osSourceFileNameOri = osFilename;
    1603             :                 }
    1604             :             }
    1605             :         }
    1606          47 :         poDS->SetDescription(pszSpec);
    1607          47 :         poDS->SetWritable(false);
    1608             :     }
    1609          50 :     return poDS;
    1610             : }
    1611             : 
    1612             : /************************************************************************/
    1613             : /*                              OpenXML()                               */
    1614             : /*                                                                      */
    1615             : /*      Create an open VRTDataset from a supplied XML representation    */
    1616             : /*      of the dataset.                                                 */
    1617             : /************************************************************************/
    1618             : 
    1619        2534 : std::unique_ptr<VRTDataset> VRTDataset::OpenXML(const char *pszXML,
    1620             :                                                 const char *pszVRTPath,
    1621             :                                                 GDALAccess eAccessIn)
    1622             : 
    1623             : {
    1624             :     /* -------------------------------------------------------------------- */
    1625             :     /*      Parse the XML.                                                  */
    1626             :     /* -------------------------------------------------------------------- */
    1627        5068 :     CPLXMLTreeCloser psTree(CPLParseXMLString(pszXML));
    1628        2534 :     if (psTree == nullptr)
    1629           0 :         return nullptr;
    1630             : 
    1631        2534 :     CPLXMLNode *psRoot = CPLGetXMLNode(psTree.get(), "=VRTDataset");
    1632        2534 :     if (psRoot == nullptr)
    1633             :     {
    1634           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Missing VRTDataset element.");
    1635           0 :         return nullptr;
    1636             :     }
    1637             : 
    1638        2534 :     const char *pszSubClass = CPLGetXMLValue(psRoot, "subClass", "");
    1639             : 
    1640        2534 :     const bool bIsPansharpened =
    1641        2534 :         strcmp(pszSubClass, "VRTPansharpenedDataset") == 0;
    1642        2534 :     const bool bIsProcessed = strcmp(pszSubClass, "VRTProcessedDataset") == 0;
    1643             : 
    1644        2460 :     if (!bIsPansharpened && !bIsProcessed &&
    1645        7125 :         CPLGetXMLNode(psRoot, "Group") == nullptr &&
    1646        2131 :         (CPLGetXMLNode(psRoot, "rasterXSize") == nullptr ||
    1647        2130 :          CPLGetXMLNode(psRoot, "rasterYSize") == nullptr ||
    1648        2130 :          CPLGetXMLNode(psRoot, "VRTRasterBand") == nullptr))
    1649             :     {
    1650           2 :         CPLError(CE_Failure, CPLE_AppDefined,
    1651             :                  "Missing one of rasterXSize, rasterYSize or bands on"
    1652             :                  " VRTDataset.");
    1653           2 :         return nullptr;
    1654             :     }
    1655             : 
    1656             :     /* -------------------------------------------------------------------- */
    1657             :     /*      Create the new virtual dataset object.                          */
    1658             :     /* -------------------------------------------------------------------- */
    1659        2532 :     const int nXSize = atoi(CPLGetXMLValue(psRoot, "rasterXSize", "0"));
    1660        2532 :     const int nYSize = atoi(CPLGetXMLValue(psRoot, "rasterYSize", "0"));
    1661             : 
    1662        2458 :     if (!bIsPansharpened && !bIsProcessed &&
    1663        7119 :         CPLGetXMLNode(psRoot, "VRTRasterBand") != nullptr &&
    1664        2129 :         !GDALCheckDatasetDimensions(nXSize, nYSize))
    1665             :     {
    1666           0 :         return nullptr;
    1667             :     }
    1668             : 
    1669        2532 :     std::unique_ptr<VRTDataset> poDS;
    1670        2532 :     if (strcmp(pszSubClass, "VRTWarpedDataset") == 0)
    1671         201 :         poDS = std::make_unique<VRTWarpedDataset>(nXSize, nYSize);
    1672        2331 :     else if (bIsPansharpened)
    1673          74 :         poDS = std::make_unique<VRTPansharpenedDataset>(nXSize, nYSize);
    1674        2257 :     else if (bIsProcessed)
    1675          96 :         poDS = std::make_unique<VRTProcessedDataset>(nXSize, nYSize);
    1676             :     else
    1677             :     {
    1678        2161 :         poDS = std::make_unique<VRTDataset>(nXSize, nYSize);
    1679        2161 :         poDS->eAccess = eAccessIn;
    1680             :     }
    1681             : 
    1682        2532 :     if (poDS->XMLInit(psRoot, pszVRTPath) != CE_None)
    1683             :     {
    1684         119 :         poDS.reset();
    1685             :     }
    1686             : 
    1687             :     /* -------------------------------------------------------------------- */
    1688             :     /*      Try to return a regular handle on the file.                     */
    1689             :     /* -------------------------------------------------------------------- */
    1690             : 
    1691        2532 :     return poDS;
    1692             : }
    1693             : 
    1694             : /************************************************************************/
    1695             : /*                              AddBand()                               */
    1696             : /************************************************************************/
    1697             : 
    1698      137540 : CPLErr VRTDataset::AddBand(GDALDataType eType, char **papszOptions)
    1699             : 
    1700             : {
    1701      137540 :     if (eType == GDT_Unknown || eType == GDT_TypeCount)
    1702             :     {
    1703           1 :         ReportError(CE_Failure, CPLE_IllegalArg,
    1704             :                     "Illegal GDT_Unknown/GDT_TypeCount argument");
    1705           1 :         return CE_Failure;
    1706             :     }
    1707             : 
    1708      137539 :     SetNeedsFlush();
    1709             : 
    1710             :     /* ==================================================================== */
    1711             :     /*      Handle a new raw band.                                          */
    1712             :     /* ==================================================================== */
    1713      137539 :     const char *pszSubClass = CSLFetchNameValue(papszOptions, "subclass");
    1714             : 
    1715      137539 :     if (pszSubClass != nullptr && EQUAL(pszSubClass, "VRTRawRasterBand"))
    1716             :     {
    1717           6 :         const int nWordDataSize = GDALGetDataTypeSizeBytes(eType);
    1718             : 
    1719             :         /* ---------------------------------------------------------------- */
    1720             :         /*      Collect required information.                               */
    1721             :         /* ---------------------------------------------------------------- */
    1722             :         const char *pszImageOffset =
    1723           6 :             CSLFetchNameValueDef(papszOptions, "ImageOffset", "0");
    1724          12 :         vsi_l_offset nImageOffset = CPLScanUIntBig(
    1725           6 :             pszImageOffset, static_cast<int>(strlen(pszImageOffset)));
    1726             : 
    1727           6 :         int nPixelOffset = nWordDataSize;
    1728             :         const char *pszPixelOffset =
    1729           6 :             CSLFetchNameValue(papszOptions, "PixelOffset");
    1730           6 :         if (pszPixelOffset != nullptr)
    1731           4 :             nPixelOffset = atoi(pszPixelOffset);
    1732             : 
    1733             :         int nLineOffset;
    1734             :         const char *pszLineOffset =
    1735           6 :             CSLFetchNameValue(papszOptions, "LineOffset");
    1736           6 :         if (pszLineOffset != nullptr)
    1737           4 :             nLineOffset = atoi(pszLineOffset);
    1738             :         else
    1739             :         {
    1740           4 :             if (nPixelOffset > INT_MAX / GetRasterXSize() ||
    1741           2 :                 nPixelOffset < INT_MIN / GetRasterXSize())
    1742             :             {
    1743           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
    1744           0 :                 return CE_Failure;
    1745             :             }
    1746           2 :             nLineOffset = nPixelOffset * GetRasterXSize();
    1747             :         }
    1748             : 
    1749           6 :         const char *pszByteOrder = CSLFetchNameValue(papszOptions, "ByteOrder");
    1750             : 
    1751             :         const char *pszFilename =
    1752           6 :             CSLFetchNameValue(papszOptions, "SourceFilename");
    1753           6 :         if (pszFilename == nullptr)
    1754             :         {
    1755           0 :             CPLError(CE_Failure, CPLE_AppDefined,
    1756             :                      "AddBand() requires a SourceFilename option for "
    1757             :                      "VRTRawRasterBands.");
    1758           0 :             return CE_Failure;
    1759             :         }
    1760             : 
    1761             :         const bool bRelativeToVRT =
    1762           6 :             CPLFetchBool(papszOptions, "relativeToVRT", false);
    1763             : 
    1764             :         /* --------------------------------------------------------------- */
    1765             :         /*      Create and initialize the band.                            */
    1766             :         /* --------------------------------------------------------------- */
    1767             : 
    1768             :         VRTRawRasterBand *poBand =
    1769           6 :             new VRTRawRasterBand(this, GetRasterCount() + 1, eType);
    1770             : 
    1771             :         char *l_pszVRTPath =
    1772           6 :             CPLStrdup(CPLGetPathSafe(GetDescription()).c_str());
    1773           6 :         if (EQUAL(l_pszVRTPath, ""))
    1774             :         {
    1775           0 :             CPLFree(l_pszVRTPath);
    1776           0 :             l_pszVRTPath = nullptr;
    1777             :         }
    1778             : 
    1779           6 :         const CPLErr eErr = poBand->SetRawLink(
    1780             :             pszFilename, l_pszVRTPath, bRelativeToVRT, nImageOffset,
    1781             :             nPixelOffset, nLineOffset, pszByteOrder);
    1782           6 :         CPLFree(l_pszVRTPath);
    1783           6 :         if (eErr != CE_None)
    1784             :         {
    1785           0 :             delete poBand;
    1786           0 :             return eErr;
    1787             :         }
    1788             : 
    1789           6 :         SetBand(GetRasterCount() + 1, poBand);
    1790             : 
    1791           6 :         return CE_None;
    1792             :     }
    1793             : 
    1794             :     /* ==================================================================== */
    1795             :     /*      Handle a new "sourced" band.                                    */
    1796             :     /* ==================================================================== */
    1797             :     else
    1798             :     {
    1799      137533 :         VRTSourcedRasterBand *poBand = nullptr;
    1800             : 
    1801             :         /* ---- Check for our sourced band 'derived' subclass ---- */
    1802      137533 :         if (pszSubClass != nullptr &&
    1803           8 :             EQUAL(pszSubClass, "VRTDerivedRasterBand"))
    1804             :         {
    1805             : 
    1806             :             /* We'll need a pointer to the subclass in case we need */
    1807             :             /* to set the new band's pixel function below. */
    1808             :             VRTDerivedRasterBand *poDerivedBand =
    1809           7 :                 new VRTDerivedRasterBand(this, GetRasterCount() + 1, eType,
    1810           7 :                                          GetRasterXSize(), GetRasterYSize());
    1811             : 
    1812             :             /* Set the pixel function options it provided. */
    1813             :             const char *pszFuncName =
    1814           7 :                 CSLFetchNameValue(papszOptions, "PixelFunctionType");
    1815           7 :             if (pszFuncName != nullptr)
    1816           6 :                 poDerivedBand->SetPixelFunctionName(pszFuncName);
    1817             : 
    1818             :             const char *pszLanguage =
    1819           7 :                 CSLFetchNameValue(papszOptions, "PixelFunctionLanguage");
    1820           7 :             if (pszLanguage != nullptr)
    1821           1 :                 poDerivedBand->SetPixelFunctionLanguage(pszLanguage);
    1822             : 
    1823             :             const char *pszSkipNonContributingSources =
    1824           7 :                 CSLFetchNameValue(papszOptions, "SkipNonContributingSources");
    1825           7 :             if (pszSkipNonContributingSources != nullptr)
    1826             :             {
    1827           3 :                 poDerivedBand->SetSkipNonContributingSources(
    1828           3 :                     CPLTestBool(pszSkipNonContributingSources));
    1829             :             }
    1830          46 :             for (const auto &[pszKey, pszValue] :
    1831          53 :                  cpl::IterateNameValue(static_cast<CSLConstList>(papszOptions)))
    1832             :             {
    1833          23 :                 if (STARTS_WITH(pszKey, "_PIXELFN_ARG_"))
    1834             :                 {
    1835           1 :                     poDerivedBand->AddPixelFunctionArgument(pszKey + 13,
    1836             :                                                             pszValue);
    1837             :                 }
    1838             :             }
    1839             : 
    1840             :             const char *pszTransferTypeName =
    1841           7 :                 CSLFetchNameValue(papszOptions, "SourceTransferType");
    1842           7 :             if (pszTransferTypeName != nullptr)
    1843             :             {
    1844             :                 const GDALDataType eTransferType =
    1845           5 :                     GDALGetDataTypeByName(pszTransferTypeName);
    1846           5 :                 if (eTransferType == GDT_Unknown)
    1847             :                 {
    1848           1 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1849             :                              "invalid SourceTransferType: \"%s\".",
    1850             :                              pszTransferTypeName);
    1851           1 :                     delete poDerivedBand;
    1852           1 :                     return CE_Failure;
    1853             :                 }
    1854           4 :                 poDerivedBand->SetSourceTransferType(eTransferType);
    1855             :             }
    1856             : 
    1857             :             /* We're done with the derived band specific stuff, so */
    1858             :             /* we can assign the base class pointer now. */
    1859           6 :             poBand = poDerivedBand;
    1860             :         }
    1861             :         else
    1862             :         {
    1863             :             int nBlockXSizeIn =
    1864      137526 :                 atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "0"));
    1865             :             int nBlockYSizeIn =
    1866      137526 :                 atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "0"));
    1867      137526 :             if (nBlockXSizeIn == 0 && nBlockYSizeIn == 0)
    1868             :             {
    1869       70417 :                 nBlockXSizeIn = m_nBlockXSize;
    1870       70417 :                 nBlockYSizeIn = m_nBlockYSize;
    1871             :             }
    1872             :             /* ---- Standard sourced band ---- */
    1873      137526 :             poBand = new VRTSourcedRasterBand(
    1874      137526 :                 this, GetRasterCount() + 1, eType, GetRasterXSize(),
    1875      137526 :                 GetRasterYSize(), nBlockXSizeIn, nBlockYSizeIn);
    1876             :         }
    1877             : 
    1878      137532 :         SetBand(GetRasterCount() + 1, poBand);
    1879             : 
    1880      271756 :         for (int i = 0; papszOptions != nullptr && papszOptions[i] != nullptr;
    1881             :              i++)
    1882             :         {
    1883      134224 :             if (STARTS_WITH_CI(papszOptions[i], "AddFuncSource="))
    1884             :             {
    1885           0 :                 char **papszTokens = CSLTokenizeStringComplex(
    1886           0 :                     papszOptions[i] + 14, ",", TRUE, FALSE);
    1887           0 :                 if (CSLCount(papszTokens) < 1)
    1888             :                 {
    1889           0 :                     CPLError(CE_Failure, CPLE_AppDefined,
    1890             :                              "AddFuncSource(): required argument missing.");
    1891             :                     // TODO: How should this error be handled?  Return
    1892             :                     // CE_Failure?
    1893             :                 }
    1894             : 
    1895           0 :                 VRTImageReadFunc pfnReadFunc = nullptr;
    1896           0 :                 sscanf(papszTokens[0], "%p", &pfnReadFunc);
    1897             : 
    1898           0 :                 void *pCBData = nullptr;
    1899           0 :                 if (CSLCount(papszTokens) > 1)
    1900           0 :                     sscanf(papszTokens[1], "%p", &pCBData);
    1901             : 
    1902           0 :                 const double dfNoDataValue = (CSLCount(papszTokens) > 2)
    1903           0 :                                                  ? CPLAtof(papszTokens[2])
    1904           0 :                                                  : VRT_NODATA_UNSET;
    1905             : 
    1906           0 :                 poBand->AddFuncSource(pfnReadFunc, pCBData, dfNoDataValue);
    1907             : 
    1908           0 :                 CSLDestroy(papszTokens);
    1909             :             }
    1910             :         }
    1911             : 
    1912      137532 :         return CE_None;
    1913             :     }
    1914             : }
    1915             : 
    1916             : /*! @endcond */
    1917             : /************************************************************************/
    1918             : /*                              VRTAddBand()                            */
    1919             : /************************************************************************/
    1920             : 
    1921             : /**
    1922             :  * @see VRTDataset::VRTAddBand().
    1923             :  *
    1924             :  * @note The return type of this function is int, but the actual values
    1925             :  * returned are of type CPLErr.
    1926             :  */
    1927             : 
    1928         960 : int CPL_STDCALL VRTAddBand(VRTDatasetH hDataset, GDALDataType eType,
    1929             :                            char **papszOptions)
    1930             : 
    1931             : {
    1932         960 :     VALIDATE_POINTER1(hDataset, "VRTAddBand", 0);
    1933             : 
    1934         960 :     return static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))
    1935         960 :         ->AddBand(eType, papszOptions);
    1936             : }
    1937             : 
    1938             : /*! @cond Doxygen_Suppress */
    1939             : 
    1940             : /************************************************************************/
    1941             : /*                               Create()                               */
    1942             : /************************************************************************/
    1943             : 
    1944         143 : GDALDataset *VRTDataset::Create(const char *pszName, int nXSize, int nYSize,
    1945             :                                 int nBandsIn, GDALDataType eType,
    1946             :                                 char **papszOptions)
    1947             : 
    1948             : {
    1949         286 :     return CreateVRTDataset(pszName, nXSize, nYSize, nBandsIn, eType,
    1950             :                             const_cast<CSLConstList>(papszOptions))
    1951         143 :         .release();
    1952             : }
    1953             : 
    1954             : /************************************************************************/
    1955             : /*                            CreateVRTDataset()                        */
    1956             : /************************************************************************/
    1957             : 
    1958             : std::unique_ptr<VRTDataset>
    1959         580 : VRTDataset::CreateVRTDataset(const char *pszName, int nXSize, int nYSize,
    1960             :                              int nBandsIn, GDALDataType eType,
    1961             :                              CSLConstList papszOptions)
    1962             : 
    1963             : {
    1964         580 :     if (STARTS_WITH_CI(pszName, "<VRTDataset"))
    1965             :     {
    1966           0 :         auto poDS = OpenXML(pszName, nullptr, GA_Update);
    1967           0 :         if (poDS != nullptr)
    1968           0 :             poDS->SetDescription("<FromXML>");
    1969           0 :         return poDS;
    1970             :     }
    1971             : 
    1972         580 :     const char *pszSubclass = CSLFetchNameValue(papszOptions, "SUBCLASS");
    1973             : 
    1974         580 :     std::unique_ptr<VRTDataset> poDS;
    1975             : 
    1976             :     const int nBlockXSize =
    1977         580 :         atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "0"));
    1978             :     const int nBlockYSize =
    1979         580 :         atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "0"));
    1980         580 :     if (pszSubclass == nullptr || EQUAL(pszSubclass, "VRTDataset"))
    1981         972 :         poDS = std::make_unique<VRTDataset>(nXSize, nYSize, nBlockXSize,
    1982         486 :                                             nBlockYSize);
    1983          94 :     else if (EQUAL(pszSubclass, "VRTWarpedDataset"))
    1984             :     {
    1985         188 :         poDS = std::make_unique<VRTWarpedDataset>(nXSize, nYSize, nBlockXSize,
    1986          94 :                                                   nBlockYSize);
    1987             :     }
    1988             :     else
    1989             :     {
    1990           0 :         CPLError(CE_Failure, CPLE_AppDefined, "SUBCLASS=%s not recognised.",
    1991             :                  pszSubclass);
    1992           0 :         return nullptr;
    1993             :     }
    1994         580 :     poDS->eAccess = GA_Update;
    1995             : 
    1996         580 :     poDS->SetDescription(pszName);
    1997             : 
    1998         812 :     for (int iBand = 0; iBand < nBandsIn; iBand++)
    1999         232 :         poDS->AddBand(eType, nullptr);
    2000             : 
    2001         580 :     poDS->SetNeedsFlush();
    2002             : 
    2003         580 :     poDS->oOvManager.Initialize(poDS.get(), pszName);
    2004             : 
    2005         580 :     return poDS;
    2006             : }
    2007             : 
    2008             : /************************************************************************/
    2009             : /*                     CreateMultiDimensional()                         */
    2010             : /************************************************************************/
    2011             : 
    2012             : GDALDataset *
    2013         106 : VRTDataset::CreateMultiDimensional(const char *pszFilename,
    2014             :                                    CSLConstList /*papszRootGroupOptions*/,
    2015             :                                    CSLConstList /*papszOptions*/)
    2016             : {
    2017         106 :     VRTDataset *poDS = new VRTDataset(0, 0);
    2018         106 :     poDS->eAccess = GA_Update;
    2019         106 :     poDS->SetDescription(pszFilename);
    2020         106 :     poDS->m_poRootGroup = VRTGroup::Create(std::string(), "/");
    2021         106 :     poDS->m_poRootGroup->SetIsRootGroup();
    2022         106 :     poDS->m_poRootGroup->SetFilename(pszFilename);
    2023         106 :     poDS->m_poRootGroup->SetDirty();
    2024             : 
    2025         106 :     return poDS;
    2026             : }
    2027             : 
    2028             : /************************************************************************/
    2029             : /*                            GetFileList()                             */
    2030             : /************************************************************************/
    2031             : 
    2032          59 : char **VRTDataset::GetFileList()
    2033             : {
    2034          59 :     char **papszFileList = GDALDataset::GetFileList();
    2035             : 
    2036          59 :     int nSize = CSLCount(papszFileList);
    2037          59 :     int nMaxSize = nSize;
    2038             : 
    2039             :     // Do not need an element deallocator as each string points to an
    2040             :     // element of the papszFileList.
    2041             :     CPLHashSet *hSetFiles =
    2042          59 :         CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, nullptr);
    2043             : 
    2044         129 :     for (int iBand = 0; iBand < nBands; iBand++)
    2045             :     {
    2046          70 :         static_cast<VRTRasterBand *>(papoBands[iBand])
    2047          70 :             ->GetFileList(&papszFileList, &nSize, &nMaxSize, hSetFiles);
    2048             :     }
    2049             : 
    2050          59 :     CPLHashSetDestroy(hSetFiles);
    2051             : 
    2052          59 :     return papszFileList;
    2053             : }
    2054             : 
    2055             : /************************************************************************/
    2056             : /*                              Delete()                                */
    2057             : /************************************************************************/
    2058             : 
    2059             : /* We implement Delete() to avoid that the default implementation */
    2060             : /* in GDALDriver::Delete() destroys the source files listed by GetFileList(),*/
    2061             : /* which would be an undesired effect... */
    2062          14 : CPLErr VRTDataset::Delete(const char *pszFilename)
    2063             : {
    2064          14 :     GDALDriverH hDriver = GDALIdentifyDriver(pszFilename, nullptr);
    2065             : 
    2066          14 :     if (!hDriver || !EQUAL(GDALGetDriverShortName(hDriver), "VRT"))
    2067           0 :         return CE_Failure;
    2068             : 
    2069          27 :     if (strstr(pszFilename, "<VRTDataset") == nullptr &&
    2070          13 :         VSIUnlink(pszFilename) != 0)
    2071             :     {
    2072           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
    2073           0 :                  pszFilename, VSIStrerror(errno));
    2074           0 :         return CE_Failure;
    2075             :     }
    2076             : 
    2077          14 :     return CE_None;
    2078             : }
    2079             : 
    2080             : /************************************************************************/
    2081             : /*                          CreateMaskBand()                            */
    2082             : /************************************************************************/
    2083             : 
    2084          45 : CPLErr VRTDataset::CreateMaskBand(int)
    2085             : {
    2086          45 :     if (m_poMaskBand != nullptr)
    2087             :     {
    2088           1 :         CPLError(CE_Failure, CPLE_AppDefined,
    2089             :                  "This VRT dataset has already a mask band");
    2090           1 :         return CE_Failure;
    2091             :     }
    2092             : 
    2093          44 :     SetMaskBand(new VRTSourcedRasterBand(this, 0));
    2094             : 
    2095          44 :     return CE_None;
    2096             : }
    2097             : 
    2098             : /************************************************************************/
    2099             : /*                           SetMaskBand()                              */
    2100             : /************************************************************************/
    2101             : 
    2102          73 : void VRTDataset::SetMaskBand(VRTRasterBand *poMaskBandIn)
    2103             : {
    2104          73 :     delete m_poMaskBand;
    2105          73 :     m_poMaskBand = poMaskBandIn;
    2106          73 :     m_poMaskBand->SetIsMaskBand();
    2107          73 : }
    2108             : 
    2109             : /************************************************************************/
    2110             : /*                        CloseDependentDatasets()                      */
    2111             : /************************************************************************/
    2112             : 
    2113         619 : int VRTDataset::CloseDependentDatasets()
    2114             : {
    2115             :     /* We need to call it before removing the sources, otherwise */
    2116             :     /* we would remove them from the serizalized VRT */
    2117         619 :     FlushCache(true);
    2118             : 
    2119         619 :     int bHasDroppedRef = GDALDataset::CloseDependentDatasets();
    2120             : 
    2121        1696 :     for (int iBand = 0; iBand < nBands; iBand++)
    2122             :     {
    2123        2154 :         bHasDroppedRef |= static_cast<VRTRasterBand *>(papoBands[iBand])
    2124        1077 :                               ->CloseDependentDatasets();
    2125             :     }
    2126             : 
    2127         619 :     return bHasDroppedRef;
    2128             : }
    2129             : 
    2130             : /************************************************************************/
    2131             : /*                      CheckCompatibleForDatasetIO()                   */
    2132             : /************************************************************************/
    2133             : 
    2134             : /* We will return TRUE only if all the bands are VRTSourcedRasterBands */
    2135             : /* made of identical sources, that are strictly VRTSimpleSource, and that */
    2136             : /* the band number of each source is the band number of the */
    2137             : /* VRTSourcedRasterBand. */
    2138             : 
    2139        9821 : bool VRTDataset::CheckCompatibleForDatasetIO() const
    2140             : {
    2141        9821 :     int nSources = 0;
    2142        9821 :     VRTSource **papoSources = nullptr;
    2143       19642 :     CPLString osResampling;
    2144             : 
    2145        9821 :     if (m_nCompatibleForDatasetIO >= 0)
    2146             :     {
    2147        7789 :         return CPL_TO_BOOL(m_nCompatibleForDatasetIO);
    2148             :     }
    2149             : 
    2150        2032 :     m_nCompatibleForDatasetIO = false;
    2151             : 
    2152        2032 :     GDALDataset *poFirstBandSourceDS = nullptr;
    2153        5998 :     for (int iBand = 0; iBand < nBands; iBand++)
    2154             :     {
    2155        4283 :         auto poVRTBand = static_cast<VRTRasterBand *>(papoBands[iBand]);
    2156        4283 :         assert(poVRTBand);
    2157        4283 :         if (!poVRTBand->IsSourcedRasterBand())
    2158          52 :             return false;
    2159             : 
    2160        4231 :         const VRTSourcedRasterBand *poBand =
    2161             :             static_cast<const VRTSourcedRasterBand *>(poVRTBand);
    2162             : 
    2163             :         // Do not allow VRTDerivedRasterBand for example
    2164        4231 :         if (typeid(*poBand) != typeid(VRTSourcedRasterBand))
    2165          52 :             return false;
    2166             : 
    2167        4179 :         if (iBand == 0)
    2168             :         {
    2169        1844 :             nSources = poBand->nSources;
    2170        1844 :             papoSources = poBand->papoSources;
    2171        3847 :             for (int iSource = 0; iSource < nSources; iSource++)
    2172             :             {
    2173        2132 :                 if (!papoSources[iSource]->IsSimpleSource())
    2174           4 :                     return false;
    2175             : 
    2176        2128 :                 const VRTSimpleSource *poSource =
    2177        2128 :                     static_cast<const VRTSimpleSource *>(papoSources[iSource]);
    2178        2128 :                 if (poSource->GetType() != VRTSimpleSource::GetTypeStatic())
    2179          98 :                     return false;
    2180             : 
    2181        6070 :                 if (poSource->m_nBand != iBand + 1 ||
    2182        2372 :                     poSource->m_bGetMaskBand ||
    2183         342 :                     (nSources > 1 && poSource->m_osSrcDSName.empty()))
    2184             :                 {
    2185          27 :                     return false;
    2186             :                 }
    2187        2003 :                 if (nSources == 1 && poSource->m_osSrcDSName.empty())
    2188             :                 {
    2189         947 :                     if (auto poSourceBand = poSource->GetRasterBand())
    2190             :                     {
    2191         947 :                         poFirstBandSourceDS = poSourceBand->GetDataset();
    2192             :                     }
    2193             :                     else
    2194             :                     {
    2195           0 :                         return false;
    2196             :                     }
    2197             :                 }
    2198        2003 :                 osResampling = poSource->GetResampling();
    2199             :             }
    2200             :         }
    2201        2335 :         else if (nSources != poBand->nSources)
    2202             :         {
    2203           0 :             return false;
    2204             :         }
    2205             :         else
    2206             :         {
    2207        5186 :             for (int iSource = 0; iSource < nSources; iSource++)
    2208             :             {
    2209        2935 :                 if (!poBand->papoSources[iSource]->IsSimpleSource())
    2210           0 :                     return false;
    2211        2935 :                 const VRTSimpleSource *poRefSource =
    2212        2935 :                     static_cast<const VRTSimpleSource *>(papoSources[iSource]);
    2213             : 
    2214        2935 :                 const VRTSimpleSource *poSource =
    2215             :                     static_cast<const VRTSimpleSource *>(
    2216        2935 :                         poBand->papoSources[iSource]);
    2217        2935 :                 if (poSource->GetType() != VRTSimpleSource::GetTypeStatic())
    2218          12 :                     return false;
    2219        8697 :                 if (poSource->m_nBand != iBand + 1 ||
    2220        3617 :                     poSource->m_bGetMaskBand ||
    2221         694 :                     (nSources > 1 && poSource->m_osSrcDSName.empty()))
    2222          72 :                     return false;
    2223        2851 :                 if (!poSource->IsSameExceptBandNumber(poRefSource))
    2224           0 :                     return false;
    2225        2851 :                 if (osResampling.compare(poSource->GetResampling()) != 0)
    2226           0 :                     return false;
    2227        2851 :                 if (nSources == 1 && poSource->m_osSrcDSName.empty())
    2228             :                 {
    2229        1831 :                     auto poSourceBand = poSource->GetRasterBand();
    2230        3662 :                     if (!poSourceBand ||
    2231        1831 :                         poFirstBandSourceDS != poSourceBand->GetDataset())
    2232             :                     {
    2233           0 :                         return false;
    2234             :                     }
    2235             :                 }
    2236             :             }
    2237             :         }
    2238             :     }
    2239             : 
    2240        1715 :     m_nCompatibleForDatasetIO = nSources != 0;
    2241        1715 :     return CPL_TO_BOOL(m_nCompatibleForDatasetIO);
    2242             : }
    2243             : 
    2244             : /************************************************************************/
    2245             : /*                         GetSingleSimpleSource()                      */
    2246             : /*                                                                      */
    2247             : /* Returns a non-NULL dataset if the VRT is made of a single source     */
    2248             : /* that is a simple source, in its full extent, and with all of its     */
    2249             : /* bands. Basically something produced by :                             */
    2250             : /*   gdal_translate src dst.vrt -of VRT (-a_srs / -a_ullr)              */
    2251             : /************************************************************************/
    2252             : 
    2253        1230 : GDALDataset *VRTDataset::GetSingleSimpleSource()
    2254             : {
    2255        1230 :     if (!CheckCompatibleForDatasetIO())
    2256          90 :         return nullptr;
    2257             : 
    2258        1140 :     VRTSourcedRasterBand *poVRTBand =
    2259        1140 :         static_cast<VRTSourcedRasterBand *>(papoBands[0]);
    2260        1140 :     if (poVRTBand->nSources != 1)
    2261           1 :         return nullptr;
    2262             : 
    2263        1139 :     VRTSimpleSource *poSource =
    2264        1139 :         static_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
    2265             : 
    2266        1139 :     GDALRasterBand *poBand = poSource->GetRasterBand();
    2267        1139 :     if (poBand == nullptr || poSource->GetMaskBandMainBand() != nullptr)
    2268           3 :         return nullptr;
    2269             : 
    2270        1136 :     GDALDataset *poSrcDS = poBand->GetDataset();
    2271        1136 :     if (poSrcDS == nullptr)
    2272           0 :         return nullptr;
    2273             : 
    2274             :     /* Check that it uses the full source dataset */
    2275        1136 :     double dfReqXOff = 0.0;
    2276        1136 :     double dfReqYOff = 0.0;
    2277        1136 :     double dfReqXSize = 0.0;
    2278        1136 :     double dfReqYSize = 0.0;
    2279        1136 :     int nReqXOff = 0;
    2280        1136 :     int nReqYOff = 0;
    2281        1136 :     int nReqXSize = 0;
    2282        1136 :     int nReqYSize = 0;
    2283        1136 :     int nOutXOff = 0;
    2284        1136 :     int nOutYOff = 0;
    2285        1136 :     int nOutXSize = 0;
    2286        1136 :     int nOutYSize = 0;
    2287        1136 :     bool bError = false;
    2288        2272 :     if (!poSource->GetSrcDstWindow(
    2289        1136 :             0, 0, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
    2290             :             poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), &dfReqXOff,
    2291             :             &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
    2292             :             &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize,
    2293             :             &nOutYSize, bError))
    2294           0 :         return nullptr;
    2295             : 
    2296         321 :     if (nReqXOff != 0 || nReqYOff != 0 ||
    2297        1673 :         nReqXSize != poSrcDS->GetRasterXSize() ||
    2298         216 :         nReqYSize != poSrcDS->GetRasterYSize())
    2299         922 :         return nullptr;
    2300             : 
    2301         214 :     if (nOutXOff != 0 || nOutYOff != 0 ||
    2302         619 :         nOutXSize != poSrcDS->GetRasterXSize() ||
    2303         191 :         nOutYSize != poSrcDS->GetRasterYSize())
    2304          23 :         return nullptr;
    2305             : 
    2306         191 :     return poSrcDS;
    2307             : }
    2308             : 
    2309             : /************************************************************************/
    2310             : /*                             AdviseRead()                             */
    2311             : /************************************************************************/
    2312             : 
    2313        3598 : CPLErr VRTDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
    2314             :                               int nBufXSize, int nBufYSize, GDALDataType eDT,
    2315             :                               int nBandCount, int *panBandList,
    2316             :                               char **papszOptions)
    2317             : {
    2318        3598 :     if (!CheckCompatibleForDatasetIO())
    2319         623 :         return CE_None;
    2320             : 
    2321        2975 :     VRTSourcedRasterBand *poVRTBand =
    2322        2975 :         static_cast<VRTSourcedRasterBand *>(papoBands[0]);
    2323        2975 :     if (poVRTBand->nSources != 1)
    2324          10 :         return CE_None;
    2325             : 
    2326        2965 :     VRTSimpleSource *poSource =
    2327        2965 :         static_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
    2328             : 
    2329             :     /* Find source window and buffer size */
    2330        2965 :     double dfReqXOff = 0.0;
    2331        2965 :     double dfReqYOff = 0.0;
    2332        2965 :     double dfReqXSize = 0.0;
    2333        2965 :     double dfReqYSize = 0.0;
    2334        2965 :     int nReqXOff = 0;
    2335        2965 :     int nReqYOff = 0;
    2336        2965 :     int nReqXSize = 0;
    2337        2965 :     int nReqYSize = 0;
    2338        2965 :     int nOutXOff = 0;
    2339        2965 :     int nOutYOff = 0;
    2340        2965 :     int nOutXSize = 0;
    2341        2965 :     int nOutYSize = 0;
    2342        2965 :     bool bError = false;
    2343        2965 :     if (!poSource->GetSrcDstWindow(nXOff, nYOff, nXSize, nYSize, nBufXSize,
    2344             :                                    nBufYSize, &dfReqXOff, &dfReqYOff,
    2345             :                                    &dfReqXSize, &dfReqYSize, &nReqXOff,
    2346             :                                    &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
    2347             :                                    &nOutYOff, &nOutXSize, &nOutYSize, bError))
    2348             :     {
    2349          74 :         return bError ? CE_Failure : CE_None;
    2350             :     }
    2351             : 
    2352        2891 :     GDALRasterBand *poBand = poSource->GetRasterBand();
    2353        2891 :     if (poBand == nullptr || poSource->GetMaskBandMainBand() != nullptr)
    2354           0 :         return CE_None;
    2355             : 
    2356        2891 :     GDALDataset *poSrcDS = poBand->GetDataset();
    2357        2891 :     if (poSrcDS == nullptr)
    2358           0 :         return CE_None;
    2359             : 
    2360        2891 :     return poSrcDS->AdviseRead(nReqXOff, nReqYOff, nReqXSize, nReqYSize,
    2361             :                                nOutXSize, nOutYSize, eDT, nBandCount,
    2362        2891 :                                panBandList, papszOptions);
    2363             : }
    2364             : 
    2365             : /************************************************************************/
    2366             : /*                           GetNumThreads()                            */
    2367             : /************************************************************************/
    2368             : 
    2369          37 : /* static */ int VRTDataset::GetNumThreads(GDALDataset *poDS)
    2370             : {
    2371          37 :     const char *pszNumThreads = nullptr;
    2372          37 :     if (poDS)
    2373          37 :         pszNumThreads = CSLFetchNameValueDef(poDS->GetOpenOptions(),
    2374             :                                              "NUM_THREADS", nullptr);
    2375          37 :     if (!pszNumThreads)
    2376          37 :         pszNumThreads = CPLGetConfigOption("VRT_NUM_THREADS", nullptr);
    2377          37 :     if (!pszNumThreads)
    2378          31 :         pszNumThreads = CPLGetConfigOption("GDAL_NUM_THREADS", "ALL_CPUS");
    2379          37 :     if (EQUAL(pszNumThreads, "0") || EQUAL(pszNumThreads, "1"))
    2380           5 :         return atoi(pszNumThreads);
    2381          32 :     const int nMaxPoolSize = GDALGetMaxDatasetPoolSize();
    2382          32 :     const int nLimit = std::min(CPLGetNumCPUs(), nMaxPoolSize);
    2383          32 :     if (EQUAL(pszNumThreads, "ALL_CPUS"))
    2384          31 :         return nLimit;
    2385           1 :     return std::min(atoi(pszNumThreads), nLimit);
    2386             : }
    2387             : 
    2388             : /************************************************************************/
    2389             : /*                       VRTDatasetRasterIOJob                          */
    2390             : /************************************************************************/
    2391             : 
    2392             : /** Structure used to declare a threaded job to satisfy IRasterIO()
    2393             :  * on a given source.
    2394             :  */
    2395             : struct VRTDatasetRasterIOJob
    2396             : {
    2397             :     std::atomic<int> *pnCompletedJobs = nullptr;
    2398             :     std::atomic<bool> *pbSuccess = nullptr;
    2399             :     CPLErrorAccumulator *poErrorAccumulator = nullptr;
    2400             : 
    2401             :     GDALDataType eVRTBandDataType = GDT_Unknown;
    2402             :     int nXOff = 0;
    2403             :     int nYOff = 0;
    2404             :     int nXSize = 0;
    2405             :     int nYSize = 0;
    2406             :     void *pData = nullptr;
    2407             :     int nBufXSize = 0;
    2408             :     int nBufYSize = 0;
    2409             :     int nBandCount = 0;
    2410             :     BANDMAP_TYPE panBandMap = nullptr;
    2411             :     GDALDataType eBufType = GDT_Unknown;
    2412             :     GSpacing nPixelSpace = 0;
    2413             :     GSpacing nLineSpace = 0;
    2414             :     GSpacing nBandSpace = 0;
    2415             :     GDALRasterIOExtraArg *psExtraArg = nullptr;
    2416             :     VRTSimpleSource *poSource = nullptr;
    2417             : 
    2418             :     static void Func(void *pData);
    2419             : };
    2420             : 
    2421             : /************************************************************************/
    2422             : /*                     VRTDatasetRasterIOJob::Func()                    */
    2423             : /************************************************************************/
    2424             : 
    2425          67 : void VRTDatasetRasterIOJob::Func(void *pData)
    2426             : {
    2427             :     auto psJob = std::unique_ptr<VRTDatasetRasterIOJob>(
    2428         134 :         static_cast<VRTDatasetRasterIOJob *>(pData));
    2429          67 :     if (*psJob->pbSuccess)
    2430             :     {
    2431          67 :         GDALRasterIOExtraArg sArg = *(psJob->psExtraArg);
    2432          67 :         sArg.pfnProgress = nullptr;
    2433          67 :         sArg.pProgressData = nullptr;
    2434             : 
    2435         134 :         auto oAccumulator = psJob->poErrorAccumulator->InstallForCurrentScope();
    2436          67 :         CPL_IGNORE_RET_VAL(oAccumulator);
    2437             : 
    2438         134 :         if (psJob->poSource->DatasetRasterIO(
    2439          67 :                 psJob->eVRTBandDataType, psJob->nXOff, psJob->nYOff,
    2440          67 :                 psJob->nXSize, psJob->nYSize, psJob->pData, psJob->nBufXSize,
    2441          67 :                 psJob->nBufYSize, psJob->eBufType, psJob->nBandCount,
    2442          67 :                 psJob->panBandMap, psJob->nPixelSpace, psJob->nLineSpace,
    2443         134 :                 psJob->nBandSpace, &sArg) != CE_None)
    2444             :         {
    2445           0 :             *psJob->pbSuccess = false;
    2446             :         }
    2447             :     }
    2448             : 
    2449          67 :     ++(*psJob->pnCompletedJobs);
    2450          67 : }
    2451             : 
    2452             : /************************************************************************/
    2453             : /*                              IRasterIO()                             */
    2454             : /************************************************************************/
    2455             : 
    2456        6144 : CPLErr VRTDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
    2457             :                              int nXSize, int nYSize, void *pData, int nBufXSize,
    2458             :                              int nBufYSize, GDALDataType eBufType,
    2459             :                              int nBandCount, BANDMAP_TYPE panBandMap,
    2460             :                              GSpacing nPixelSpace, GSpacing nLineSpace,
    2461             :                              GSpacing nBandSpace,
    2462             :                              GDALRasterIOExtraArg *psExtraArg)
    2463             : {
    2464        6144 :     m_bMultiThreadedRasterIOLastUsed = false;
    2465             : 
    2466        6144 :     if (nBands == 1 && nBandCount == 1)
    2467             :     {
    2468             :         VRTSourcedRasterBand *poBand =
    2469        1204 :             dynamic_cast<VRTSourcedRasterBand *>(papoBands[0]);
    2470        1204 :         if (poBand)
    2471             :         {
    2472        1202 :             return poBand->IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2473             :                                      pData, nBufXSize, nBufYSize, eBufType,
    2474        1202 :                                      nPixelSpace, nLineSpace, psExtraArg);
    2475             :         }
    2476             :     }
    2477             : 
    2478             :     bool bLocalCompatibleForDatasetIO =
    2479        4942 :         CPL_TO_BOOL(CheckCompatibleForDatasetIO());
    2480        4591 :     if (bLocalCompatibleForDatasetIO && eRWFlag == GF_Read &&
    2481        9533 :         (nBufXSize < nXSize || nBufYSize < nYSize) && m_apoOverviews.empty())
    2482             :     {
    2483           3 :         int bTried = FALSE;
    2484           3 :         const CPLErr eErr = TryOverviewRasterIO(
    2485             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
    2486             :             eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
    2487             :             nBandSpace, psExtraArg, &bTried);
    2488             : 
    2489           3 :         if (bTried)
    2490             :         {
    2491           1 :             return eErr;
    2492             :         }
    2493             : 
    2494           9 :         for (int iBand = 0; iBand < nBands; iBand++)
    2495             :         {
    2496           7 :             VRTSourcedRasterBand *poBand =
    2497           7 :                 static_cast<VRTSourcedRasterBand *>(papoBands[iBand]);
    2498             : 
    2499             :             // If there are overviews, let VRTSourcedRasterBand::IRasterIO()
    2500             :             // do the job.
    2501           7 :             if (poBand->GetOverviewCount() != 0)
    2502             :             {
    2503           0 :                 bLocalCompatibleForDatasetIO = false;
    2504           0 :                 break;
    2505             :             }
    2506             :         }
    2507             :     }
    2508             : 
    2509             :     // If resampling with non-nearest neighbour, we need to be careful
    2510             :     // if the VRT band exposes a nodata value, but the sources do not have it.
    2511             :     // To also avoid edge effects on sources when downsampling, use the
    2512             :     // base implementation of IRasterIO() (that is acquiring sources at their
    2513             :     // nominal resolution, and then downsampling), but only if none of the
    2514             :     // contributing sources have overviews.
    2515        4941 :     if (bLocalCompatibleForDatasetIO && eRWFlag == GF_Read &&
    2516        4567 :         (nXSize != nBufXSize || nYSize != nBufYSize) &&
    2517          23 :         psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
    2518             :     {
    2519           0 :         for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
    2520             :         {
    2521             :             VRTSourcedRasterBand *poBand = static_cast<VRTSourcedRasterBand *>(
    2522           0 :                 GetRasterBand(panBandMap[iBandIndex]));
    2523           0 :             if (!poBand->CanIRasterIOBeForwardedToEachSource(
    2524             :                     eRWFlag, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
    2525             :                     psExtraArg))
    2526             :             {
    2527           0 :                 bLocalCompatibleForDatasetIO = false;
    2528           0 :                 break;
    2529             :             }
    2530             :         }
    2531             :     }
    2532             : 
    2533        4941 :     if (bLocalCompatibleForDatasetIO && eRWFlag == GF_Read)
    2534             :     {
    2535       12418 :         for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
    2536             :         {
    2537             :             VRTSourcedRasterBand *poBand = static_cast<VRTSourcedRasterBand *>(
    2538        7828 :                 GetRasterBand(panBandMap[iBandIndex]));
    2539             : 
    2540             :             /* Dirty little trick to initialize the buffer without doing */
    2541             :             /* any real I/O */
    2542        7828 :             const int nSavedSources = poBand->nSources;
    2543        7828 :             poBand->nSources = 0;
    2544             : 
    2545        7828 :             GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
    2546        7828 :             psExtraArg->pfnProgress = nullptr;
    2547             : 
    2548        7828 :             GByte *pabyBandData =
    2549        7828 :                 static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
    2550             : 
    2551        7828 :             poBand->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
    2552             :                               pabyBandData, nBufXSize, nBufYSize, eBufType,
    2553        7828 :                               nPixelSpace, nLineSpace, psExtraArg);
    2554             : 
    2555        7828 :             psExtraArg->pfnProgress = pfnProgressGlobal;
    2556             : 
    2557        7828 :             poBand->nSources = nSavedSources;
    2558             :         }
    2559             : 
    2560        4590 :         CPLErr eErr = CE_None;
    2561             : 
    2562             :         // Use the last band, because when sources reference a GDALProxyDataset,
    2563             :         // they don't necessary instantiate all underlying rasterbands.
    2564        4590 :         VRTSourcedRasterBand *poBand =
    2565        4590 :             static_cast<VRTSourcedRasterBand *>(papoBands[nBands - 1]);
    2566             : 
    2567        4590 :         double dfXOff = nXOff;
    2568        4590 :         double dfYOff = nYOff;
    2569        4590 :         double dfXSize = nXSize;
    2570        4590 :         double dfYSize = nYSize;
    2571        4590 :         if (psExtraArg->bFloatingPointWindowValidity)
    2572             :         {
    2573          11 :             dfXOff = psExtraArg->dfXOff;
    2574          11 :             dfYOff = psExtraArg->dfYOff;
    2575          11 :             dfXSize = psExtraArg->dfXSize;
    2576          11 :             dfYSize = psExtraArg->dfYSize;
    2577             :         }
    2578             : 
    2579        4590 :         int nContributingSources = 0;
    2580        4590 :         int nMaxThreads = 0;
    2581        4590 :         constexpr int MINIMUM_PIXEL_COUNT_FOR_THREADED_IO = 1000 * 1000;
    2582        9180 :         if ((static_cast<int64_t>(nBufXSize) * nBufYSize >=
    2583        4427 :                  MINIMUM_PIXEL_COUNT_FOR_THREADED_IO ||
    2584        4427 :              static_cast<int64_t>(nXSize) * nYSize >=
    2585         163 :                  MINIMUM_PIXEL_COUNT_FOR_THREADED_IO) &&
    2586         163 :             poBand->CanMultiThreadRasterIO(dfXOff, dfYOff, dfXSize, dfYSize,
    2587         162 :                                            nContributingSources) &&
    2588        9184 :             nContributingSources > 1 &&
    2589           4 :             (nMaxThreads = VRTDataset::GetNumThreads(this)) > 1)
    2590             :         {
    2591           2 :             m_bMultiThreadedRasterIOLastUsed = true;
    2592           2 :             m_oMapSharedSources.InitMutex();
    2593             : 
    2594           4 :             CPLErrorAccumulator errorAccumulator;
    2595           2 :             std::atomic<bool> bSuccess = true;
    2596           2 :             CPLWorkerThreadPool *psThreadPool = GDALGetGlobalThreadPool(
    2597           2 :                 std::min(nContributingSources, nMaxThreads));
    2598             : 
    2599           2 :             CPLDebugOnly(
    2600             :                 "VRT",
    2601             :                 "IRasterIO(): use optimized "
    2602             :                 "multi-threaded code path for mosaic. "
    2603             :                 "Using %d threads",
    2604             :                 std::min(nContributingSources, psThreadPool->GetThreadCount()));
    2605             : 
    2606           2 :             auto oQueue = psThreadPool->CreateJobQueue();
    2607           2 :             std::atomic<int> nCompletedJobs = 0;
    2608         132 :             for (int iSource = 0; iSource < poBand->nSources; iSource++)
    2609             :             {
    2610         130 :                 auto poSource = poBand->papoSources[iSource];
    2611         130 :                 if (!poSource->IsSimpleSource())
    2612           0 :                     continue;
    2613             :                 auto poSimpleSource =
    2614         130 :                     cpl::down_cast<VRTSimpleSource *>(poSource);
    2615         130 :                 if (poSimpleSource->DstWindowIntersects(dfXOff, dfYOff, dfXSize,
    2616             :                                                         dfYSize))
    2617             :                 {
    2618          67 :                     auto psJob = new VRTDatasetRasterIOJob();
    2619          67 :                     psJob->pbSuccess = &bSuccess;
    2620          67 :                     psJob->poErrorAccumulator = &errorAccumulator;
    2621          67 :                     psJob->pnCompletedJobs = &nCompletedJobs;
    2622          67 :                     psJob->eVRTBandDataType = poBand->GetRasterDataType();
    2623          67 :                     psJob->nXOff = nXOff;
    2624          67 :                     psJob->nYOff = nYOff;
    2625          67 :                     psJob->nXSize = nXSize;
    2626          67 :                     psJob->nYSize = nYSize;
    2627          67 :                     psJob->pData = pData;
    2628          67 :                     psJob->nBufXSize = nBufXSize;
    2629          67 :                     psJob->nBufYSize = nBufYSize;
    2630          67 :                     psJob->eBufType = eBufType;
    2631          67 :                     psJob->nBandCount = nBandCount;
    2632          67 :                     psJob->panBandMap = panBandMap;
    2633          67 :                     psJob->nPixelSpace = nPixelSpace;
    2634          67 :                     psJob->nLineSpace = nLineSpace;
    2635          67 :                     psJob->nBandSpace = nBandSpace;
    2636          67 :                     psJob->psExtraArg = psExtraArg;
    2637          67 :                     psJob->poSource = poSimpleSource;
    2638             : 
    2639          67 :                     if (!oQueue->SubmitJob(VRTDatasetRasterIOJob::Func, psJob))
    2640             :                     {
    2641           0 :                         delete psJob;
    2642           0 :                         bSuccess = false;
    2643           0 :                         break;
    2644             :                     }
    2645             :                 }
    2646             :             }
    2647             : 
    2648          59 :             while (oQueue->WaitEvent())
    2649             :             {
    2650             :                 // Quite rough progress callback. We could do better by counting
    2651             :                 // the number of contributing pixels.
    2652          57 :                 if (psExtraArg->pfnProgress)
    2653             :                 {
    2654         114 :                     psExtraArg->pfnProgress(double(nCompletedJobs.load()) /
    2655             :                                                 nContributingSources,
    2656             :                                             "", psExtraArg->pProgressData);
    2657             :                 }
    2658             :             }
    2659             : 
    2660           2 :             errorAccumulator.ReplayErrors();
    2661           2 :             eErr = bSuccess ? CE_None : CE_Failure;
    2662             :         }
    2663             :         else
    2664             :         {
    2665        4588 :             GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
    2666        4588 :             void *pProgressDataGlobal = psExtraArg->pProgressData;
    2667             : 
    2668        9343 :             for (int iSource = 0; eErr == CE_None && iSource < poBand->nSources;
    2669             :                  iSource++)
    2670             :             {
    2671        4755 :                 psExtraArg->pfnProgress = GDALScaledProgress;
    2672        9510 :                 psExtraArg->pProgressData = GDALCreateScaledProgress(
    2673        4755 :                     1.0 * iSource / poBand->nSources,
    2674        4755 :                     1.0 * (iSource + 1) / poBand->nSources, pfnProgressGlobal,
    2675             :                     pProgressDataGlobal);
    2676             : 
    2677        4755 :                 VRTSimpleSource *poSource = static_cast<VRTSimpleSource *>(
    2678        4755 :                     poBand->papoSources[iSource]);
    2679             : 
    2680        4755 :                 eErr = poSource->DatasetRasterIO(
    2681             :                     poBand->GetRasterDataType(), nXOff, nYOff, nXSize, nYSize,
    2682             :                     pData, nBufXSize, nBufYSize, eBufType, nBandCount,
    2683             :                     panBandMap, nPixelSpace, nLineSpace, nBandSpace,
    2684             :                     psExtraArg);
    2685             : 
    2686        4755 :                 GDALDestroyScaledProgress(psExtraArg->pProgressData);
    2687             :             }
    2688             : 
    2689        4588 :             psExtraArg->pfnProgress = pfnProgressGlobal;
    2690        4588 :             psExtraArg->pProgressData = pProgressDataGlobal;
    2691             :         }
    2692             : 
    2693        4590 :         if (eErr == CE_None && psExtraArg->pfnProgress)
    2694             :         {
    2695        2646 :             psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
    2696             :         }
    2697             : 
    2698        4590 :         return eErr;
    2699             :     }
    2700             : 
    2701             :     CPLErr eErr;
    2702         351 :     if (eRWFlag == GF_Read &&
    2703         351 :         psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
    2704           2 :         nBufXSize < nXSize && nBufYSize < nYSize && nBandCount > 1)
    2705             :     {
    2706             :         // Force going through VRTSourcedRasterBand::IRasterIO(), otherwise
    2707             :         // GDALDataset::IRasterIOResampled() would be used without source
    2708             :         // overviews being potentially used.
    2709           2 :         eErr = GDALDataset::BandBasedRasterIO(
    2710             :             eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
    2711             :             eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
    2712             :             nBandSpace, psExtraArg);
    2713             :     }
    2714             :     else
    2715             :     {
    2716         349 :         eErr = GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
    2717             :                                       pData, nBufXSize, nBufYSize, eBufType,
    2718             :                                       nBandCount, panBandMap, nPixelSpace,
    2719             :                                       nLineSpace, nBandSpace, psExtraArg);
    2720             :     }
    2721         351 :     return eErr;
    2722             : }
    2723             : 
    2724             : /************************************************************************/
    2725             : /*                  UnsetPreservedRelativeFilenames()                   */
    2726             : /************************************************************************/
    2727             : 
    2728         143 : void VRTDataset::UnsetPreservedRelativeFilenames()
    2729             : {
    2730         315 :     for (int iBand = 0; iBand < nBands; iBand++)
    2731             :     {
    2732         447 :         if (!static_cast<VRTRasterBand *>(papoBands[iBand])
    2733         172 :                  ->IsSourcedRasterBand())
    2734         103 :             continue;
    2735             : 
    2736          69 :         VRTSourcedRasterBand *poBand =
    2737          69 :             static_cast<VRTSourcedRasterBand *>(papoBands[iBand]);
    2738          69 :         const int nSources = poBand->nSources;
    2739          69 :         VRTSource **papoSources = poBand->papoSources;
    2740         111 :         for (int iSource = 0; iSource < nSources; iSource++)
    2741             :         {
    2742          42 :             if (!papoSources[iSource]->IsSimpleSource())
    2743           0 :                 continue;
    2744             : 
    2745          42 :             VRTSimpleSource *poSource =
    2746          42 :                 static_cast<VRTSimpleSource *>(papoSources[iSource]);
    2747          42 :             poSource->UnsetPreservedRelativeFilenames();
    2748             :         }
    2749             :     }
    2750         143 : }
    2751             : 
    2752             : /************************************************************************/
    2753             : /*                        BuildVirtualOverviews()                       */
    2754             : /************************************************************************/
    2755             : 
    2756        5588 : static bool CheckBandForOverview(GDALRasterBand *poBand,
    2757             :                                  GDALRasterBand *&poFirstBand, int &nOverviews,
    2758             :                                  std::set<std::pair<int, int>> &oSetOvrSizes,
    2759             :                                  std::vector<GDALDataset *> &apoOverviewsBak)
    2760             : {
    2761        5588 :     if (!cpl::down_cast<VRTRasterBand *>(poBand)->IsSourcedRasterBand())
    2762           0 :         return false;
    2763             : 
    2764             :     VRTSourcedRasterBand *poVRTBand =
    2765        5588 :         cpl::down_cast<VRTSourcedRasterBand *>(poBand);
    2766        5588 :     if (poVRTBand->nSources != 1)
    2767        4270 :         return false;
    2768        1318 :     if (!poVRTBand->papoSources[0]->IsSimpleSource())
    2769           0 :         return false;
    2770             : 
    2771             :     VRTSimpleSource *poSource =
    2772        1318 :         cpl::down_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
    2773        1318 :     const char *pszType = poSource->GetType();
    2774        1368 :     if (pszType != VRTSimpleSource::GetTypeStatic() &&
    2775          50 :         pszType != VRTComplexSource::GetTypeStatic())
    2776             :     {
    2777           2 :         return false;
    2778             :     }
    2779        1316 :     GDALRasterBand *poSrcBand = poBand->GetBand() == 0
    2780        1316 :                                     ? poSource->GetMaskBandMainBand()
    2781        1306 :                                     : poSource->GetRasterBand();
    2782        1316 :     if (poSrcBand == nullptr)
    2783          79 :         return false;
    2784             : 
    2785             :     // To prevent recursion
    2786        1237 :     apoOverviewsBak.push_back(nullptr);
    2787        1237 :     const int nOvrCount = poSrcBand->GetOverviewCount();
    2788             :     oSetOvrSizes.insert(
    2789        1237 :         std::pair<int, int>(poSrcBand->GetXSize(), poSrcBand->GetYSize()));
    2790        1392 :     for (int i = 0; i < nOvrCount; ++i)
    2791             :     {
    2792         155 :         auto poSrcOvrBand = poSrcBand->GetOverview(i);
    2793         155 :         if (poSrcOvrBand)
    2794             :         {
    2795         155 :             oSetOvrSizes.insert(std::pair<int, int>(poSrcOvrBand->GetXSize(),
    2796         310 :                                                     poSrcOvrBand->GetYSize()));
    2797             :         }
    2798             :     }
    2799        1237 :     apoOverviewsBak.resize(0);
    2800             : 
    2801        1237 :     if (nOvrCount == 0)
    2802        1145 :         return false;
    2803          92 :     if (poFirstBand == nullptr)
    2804             :     {
    2805          33 :         if (poSrcBand->GetXSize() == 0 || poSrcBand->GetYSize() == 0)
    2806           0 :             return false;
    2807          33 :         poFirstBand = poSrcBand;
    2808          33 :         nOverviews = nOvrCount;
    2809             :     }
    2810          59 :     else if (nOvrCount < nOverviews)
    2811           0 :         nOverviews = nOvrCount;
    2812          92 :     return true;
    2813             : }
    2814             : 
    2815        5554 : void VRTDataset::BuildVirtualOverviews()
    2816             : {
    2817             :     // Currently we expose virtual overviews only if the dataset is made of
    2818             :     // a single SimpleSource/ComplexSource, in each band.
    2819             :     // And if the underlying sources have overviews of course
    2820        5554 :     if (!m_apoOverviews.empty() || !m_apoOverviewsBak.empty())
    2821        5532 :         return;
    2822             : 
    2823        5518 :     int nOverviews = 0;
    2824        5518 :     GDALRasterBand *poFirstBand = nullptr;
    2825        5518 :     std::set<std::pair<int, int>> oSetOvrSizes;
    2826             : 
    2827        5608 :     for (int iBand = 0; iBand < nBands; iBand++)
    2828             :     {
    2829        5578 :         if (!CheckBandForOverview(papoBands[iBand], poFirstBand, nOverviews,
    2830        5578 :                                   oSetOvrSizes, m_apoOverviewsBak))
    2831        5488 :             return;
    2832             :     }
    2833             : 
    2834          30 :     if (m_poMaskBand)
    2835             :     {
    2836          10 :         if (!CheckBandForOverview(m_poMaskBand, poFirstBand, nOverviews,
    2837          10 :                                   oSetOvrSizes, m_apoOverviewsBak))
    2838           8 :             return;
    2839             :     }
    2840          22 :     if (poFirstBand == nullptr)
    2841             :     {
    2842             :         // to make cppcheck happy
    2843           0 :         CPLAssert(false);
    2844             :         return;
    2845             :     }
    2846             : 
    2847             :     VRTSourcedRasterBand *l_poVRTBand =
    2848          22 :         cpl::down_cast<VRTSourcedRasterBand *>(papoBands[0]);
    2849             :     VRTSimpleSource *poSource =
    2850          22 :         cpl::down_cast<VRTSimpleSource *>(l_poVRTBand->papoSources[0]);
    2851          22 :     const double dfDstToSrcXRatio =
    2852          22 :         poSource->m_dfDstXSize / poSource->m_dfSrcXSize;
    2853          22 :     const double dfDstToSrcYRatio =
    2854          22 :         poSource->m_dfDstYSize / poSource->m_dfSrcYSize;
    2855             : 
    2856          54 :     for (int j = 0; j < nOverviews; j++)
    2857             :     {
    2858          36 :         auto poOvrBand = poFirstBand->GetOverview(j);
    2859          36 :         if (!poOvrBand)
    2860           0 :             return;
    2861          36 :         const double dfXRatio = static_cast<double>(poOvrBand->GetXSize()) /
    2862          36 :                                 poFirstBand->GetXSize();
    2863          36 :         const double dfYRatio = static_cast<double>(poOvrBand->GetYSize()) /
    2864          36 :                                 poFirstBand->GetYSize();
    2865          36 :         if (dfXRatio >= dfDstToSrcXRatio || dfYRatio >= dfDstToSrcYRatio)
    2866             :         {
    2867           5 :             continue;
    2868             :         }
    2869          31 :         int nOvrXSize = static_cast<int>(0.5 + nRasterXSize * dfXRatio);
    2870          31 :         int nOvrYSize = static_cast<int>(0.5 + nRasterYSize * dfYRatio);
    2871          31 :         if (nOvrXSize < DEFAULT_BLOCK_SIZE || nOvrYSize < DEFAULT_BLOCK_SIZE)
    2872             :             break;
    2873             : 
    2874             :         // Look for a source overview whose size is very close to the
    2875             :         // theoretical computed one.
    2876          97 :         for (const auto &ovrSize : oSetOvrSizes)
    2877             :         {
    2878          86 :             if (std::abs(ovrSize.first - nOvrXSize) <= 1 &&
    2879          16 :                 std::abs(ovrSize.second - nOvrYSize) <= 1)
    2880             :             {
    2881          16 :                 nOvrXSize = ovrSize.first;
    2882          16 :                 nOvrYSize = ovrSize.second;
    2883          16 :                 break;
    2884             :             }
    2885             :         }
    2886             : 
    2887          27 :         int nBlockXSize = 0;
    2888          27 :         int nBlockYSize = 0;
    2889          27 :         l_poVRTBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
    2890          27 :         if (VRTDataset::IsDefaultBlockSize(nBlockXSize, nRasterXSize))
    2891          10 :             nBlockXSize = 0;
    2892          27 :         if (VRTDataset::IsDefaultBlockSize(nBlockYSize, nRasterYSize))
    2893          14 :             nBlockYSize = 0;
    2894             : 
    2895             :         VRTDataset *poOvrVDS =
    2896          27 :             new VRTDataset(nOvrXSize, nOvrYSize, nBlockXSize, nBlockYSize);
    2897          27 :         m_apoOverviews.push_back(poOvrVDS);
    2898             : 
    2899             :         const auto CreateOverviewBand =
    2900          75 :             [&poOvrVDS, nOvrXSize, nOvrYSize, dfXRatio,
    2901         150 :              dfYRatio](VRTSourcedRasterBand *poVRTBand)
    2902             :         {
    2903             :             VRTSourcedRasterBand *poOvrVRTBand = new VRTSourcedRasterBand(
    2904          75 :                 poOvrVDS, poVRTBand->GetBand(), poVRTBand->GetRasterDataType(),
    2905          75 :                 nOvrXSize, nOvrYSize);
    2906          75 :             poOvrVRTBand->CopyCommonInfoFrom(poVRTBand);
    2907          75 :             poOvrVRTBand->m_bNoDataValueSet = poVRTBand->m_bNoDataValueSet;
    2908          75 :             poOvrVRTBand->m_dfNoDataValue = poVRTBand->m_dfNoDataValue;
    2909          75 :             poOvrVRTBand->m_bHideNoDataValue = poVRTBand->m_bHideNoDataValue;
    2910             : 
    2911             :             VRTSimpleSource *poSrcSource =
    2912          75 :                 cpl::down_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
    2913          75 :             VRTSimpleSource *poNewSource = nullptr;
    2914          75 :             const char *pszType = poSrcSource->GetType();
    2915          75 :             if (pszType == VRTSimpleSource::GetTypeStatic())
    2916             :             {
    2917          70 :                 poNewSource =
    2918          70 :                     new VRTSimpleSource(poSrcSource, dfXRatio, dfYRatio);
    2919             :             }
    2920           5 :             else if (pszType == VRTComplexSource::GetTypeStatic())
    2921             :             {
    2922           5 :                 poNewSource = new VRTComplexSource(
    2923           5 :                     cpl::down_cast<VRTComplexSource *>(poSrcSource), dfXRatio,
    2924           5 :                     dfYRatio);
    2925             :             }
    2926             :             else
    2927             :             {
    2928           0 :                 CPLAssert(false);
    2929             :             }
    2930          75 :             if (poNewSource)
    2931             :             {
    2932          75 :                 auto poNewSourceBand = poVRTBand->GetBand() == 0
    2933          75 :                                            ? poNewSource->GetMaskBandMainBand()
    2934          71 :                                            : poNewSource->GetRasterBand();
    2935          75 :                 CPLAssert(poNewSourceBand);
    2936          75 :                 auto poNewSourceBandDS = poNewSourceBand->GetDataset();
    2937          75 :                 if (poNewSourceBandDS)
    2938          75 :                     poNewSourceBandDS->Reference();
    2939          75 :                 poOvrVRTBand->AddSource(poNewSource);
    2940             :             }
    2941             : 
    2942          75 :             return poOvrVRTBand;
    2943          27 :         };
    2944             : 
    2945          98 :         for (int i = 0; i < nBands; i++)
    2946             :         {
    2947             :             VRTSourcedRasterBand *poSrcBand =
    2948          71 :                 cpl::down_cast<VRTSourcedRasterBand *>(GetRasterBand(i + 1));
    2949          71 :             auto poOvrVRTBand = CreateOverviewBand(poSrcBand);
    2950          71 :             poOvrVDS->SetBand(poOvrVDS->GetRasterCount() + 1, poOvrVRTBand);
    2951             :         }
    2952             : 
    2953          27 :         if (m_poMaskBand)
    2954             :         {
    2955             :             VRTSourcedRasterBand *poSrcBand =
    2956           4 :                 cpl::down_cast<VRTSourcedRasterBand *>(m_poMaskBand);
    2957           4 :             auto poOvrVRTBand = CreateOverviewBand(poSrcBand);
    2958           4 :             poOvrVDS->SetMaskBand(poOvrVRTBand);
    2959             :         }
    2960             :     }
    2961             : }
    2962             : 
    2963             : /************************************************************************/
    2964             : /*                        AddVirtualOverview()                          */
    2965             : /************************************************************************/
    2966             : 
    2967          36 : bool VRTDataset::AddVirtualOverview(int nOvFactor, const char *pszResampling)
    2968             : {
    2969          36 :     if (nRasterXSize / nOvFactor == 0 || nRasterYSize / nOvFactor == 0)
    2970             :     {
    2971           1 :         return false;
    2972             :     }
    2973             : 
    2974          70 :     CPLStringList argv;
    2975          35 :     argv.AddString("-of");
    2976          35 :     argv.AddString("VRT");
    2977          35 :     argv.AddString("-outsize");
    2978          35 :     argv.AddString(CPLSPrintf("%d", nRasterXSize / nOvFactor));
    2979          35 :     argv.AddString(CPLSPrintf("%d", nRasterYSize / nOvFactor));
    2980          35 :     argv.AddString("-r");
    2981          35 :     argv.AddString(pszResampling);
    2982             : 
    2983          35 :     int nBlockXSize = 0;
    2984          35 :     int nBlockYSize = 0;
    2985          35 :     GetRasterBand(1)->GetBlockSize(&nBlockXSize, &nBlockYSize);
    2986          35 :     if (!VRTDataset::IsDefaultBlockSize(nBlockXSize, nRasterXSize))
    2987             :     {
    2988           6 :         argv.AddString("-co");
    2989           6 :         argv.AddString(CPLSPrintf("BLOCKXSIZE=%d", nBlockXSize));
    2990             :     }
    2991          35 :     if (!VRTDataset::IsDefaultBlockSize(nBlockYSize, nRasterYSize))
    2992             :     {
    2993          10 :         argv.AddString("-co");
    2994          10 :         argv.AddString(CPLSPrintf("BLOCKYSIZE=%d", nBlockYSize));
    2995             :     }
    2996             : 
    2997             :     GDALTranslateOptions *psOptions =
    2998          35 :         GDALTranslateOptionsNew(argv.List(), nullptr);
    2999             : 
    3000             :     // Add a dummy overview so that BuildVirtualOverviews() doesn't trigger
    3001          35 :     m_apoOverviews.push_back(nullptr);
    3002          35 :     CPLAssert(m_bCanTakeRef);
    3003          35 :     m_bCanTakeRef =
    3004             :         false;  // we don't want hOverviewDS to take a reference on ourselves.
    3005             :     GDALDatasetH hOverviewDS =
    3006          35 :         GDALTranslate("", GDALDataset::ToHandle(this), psOptions, nullptr);
    3007          35 :     m_bCanTakeRef = true;
    3008          35 :     m_apoOverviews.pop_back();
    3009             : 
    3010          35 :     GDALTranslateOptionsFree(psOptions);
    3011          35 :     if (hOverviewDS == nullptr)
    3012           0 :         return false;
    3013             : 
    3014          35 :     m_anOverviewFactors.push_back(nOvFactor);
    3015          35 :     m_apoOverviews.push_back(GDALDataset::FromHandle(hOverviewDS));
    3016          35 :     return true;
    3017             : }
    3018             : 
    3019             : /************************************************************************/
    3020             : /*                          IBuildOverviews()                           */
    3021             : /************************************************************************/
    3022             : 
    3023          32 : CPLErr VRTDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
    3024             :                                    const int *panOverviewList, int nListBands,
    3025             :                                    const int *panBandList,
    3026             :                                    GDALProgressFunc pfnProgress,
    3027             :                                    void *pProgressData,
    3028             :                                    CSLConstList papszOptions)
    3029             : {
    3030          32 :     if (CPLTestBool(CPLGetConfigOption("VRT_VIRTUAL_OVERVIEWS", "NO")))
    3031             :     {
    3032          14 :         SetNeedsFlush();
    3033          27 :         if (nOverviews == 0 ||
    3034          13 :             (!m_apoOverviews.empty() && m_anOverviewFactors.empty()))
    3035             :         {
    3036           2 :             m_anOverviewFactors.clear();
    3037           2 :             m_apoOverviewsBak.insert(m_apoOverviewsBak.end(),
    3038             :                                      m_apoOverviews.begin(),
    3039           4 :                                      m_apoOverviews.end());
    3040           2 :             m_apoOverviews.clear();
    3041             :         }
    3042          14 :         m_osOverviewResampling = pszResampling;
    3043          38 :         for (int i = 0; i < nOverviews; i++)
    3044             :         {
    3045          24 :             if (std::find(m_anOverviewFactors.begin(),
    3046             :                           m_anOverviewFactors.end(),
    3047          24 :                           panOverviewList[i]) == m_anOverviewFactors.end())
    3048             :             {
    3049          24 :                 AddVirtualOverview(panOverviewList[i], pszResampling);
    3050             :             }
    3051             :         }
    3052          14 :         return CE_None;
    3053             :     }
    3054             : 
    3055          18 :     if (!oOvManager.IsInitialized())
    3056             :     {
    3057           0 :         const char *pszDesc = GetDescription();
    3058           0 :         if (pszDesc[0])
    3059             :         {
    3060           0 :             oOvManager.Initialize(this, pszDesc);
    3061             :         }
    3062             :     }
    3063             : 
    3064             :     // Make implicit overviews invisible, but do not destroy them in case they
    3065             :     // are already used.  Should the client do that?  Behavior might undefined
    3066             :     // in GDAL API?
    3067          18 :     if (!m_apoOverviews.empty())
    3068             :     {
    3069           2 :         m_apoOverviewsBak.insert(m_apoOverviewsBak.end(),
    3070           4 :                                  m_apoOverviews.begin(), m_apoOverviews.end());
    3071           2 :         m_apoOverviews.clear();
    3072             :     }
    3073             :     else
    3074             :     {
    3075             :         // Add a dummy overview so that GDALDataset::IBuildOverviews()
    3076             :         // doesn't manage to get a virtual implicit overview.
    3077          16 :         m_apoOverviews.push_back(nullptr);
    3078             :     }
    3079             : 
    3080          18 :     CPLErr eErr = GDALDataset::IBuildOverviews(
    3081             :         pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
    3082             :         pfnProgress, pProgressData, papszOptions);
    3083             : 
    3084          18 :     m_apoOverviews.clear();
    3085          18 :     return eErr;
    3086             : }
    3087             : 
    3088             : /************************************************************************/
    3089             : /*                         GetShiftedDataset()                          */
    3090             : /*                                                                      */
    3091             : /* Returns true if the VRT is made of a single source that is a simple  */
    3092             : /* in its full resolution.                                              */
    3093             : /************************************************************************/
    3094             : 
    3095          50 : bool VRTDataset::GetShiftedDataset(int nXOff, int nYOff, int nXSize, int nYSize,
    3096             :                                    GDALDataset *&poSrcDataset, int &nSrcXOff,
    3097             :                                    int &nSrcYOff)
    3098             : {
    3099          50 :     if (!CheckCompatibleForDatasetIO())
    3100           0 :         return false;
    3101             : 
    3102          50 :     VRTSourcedRasterBand *poVRTBand =
    3103          50 :         static_cast<VRTSourcedRasterBand *>(papoBands[0]);
    3104          50 :     if (poVRTBand->nSources != 1)
    3105           0 :         return false;
    3106             : 
    3107          50 :     VRTSimpleSource *poSource =
    3108          50 :         static_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
    3109             : 
    3110          50 :     GDALRasterBand *poBand = poSource->GetRasterBand();
    3111          50 :     if (!poBand || poSource->GetMaskBandMainBand())
    3112           4 :         return false;
    3113             : 
    3114          46 :     poSrcDataset = poBand->GetDataset();
    3115          46 :     if (!poSrcDataset)
    3116           0 :         return false;
    3117             : 
    3118          46 :     double dfReqXOff = 0.0;
    3119          46 :     double dfReqYOff = 0.0;
    3120          46 :     double dfReqXSize = 0.0;
    3121          46 :     double dfReqYSize = 0.0;
    3122          46 :     int nReqXOff = 0;
    3123          46 :     int nReqYOff = 0;
    3124          46 :     int nReqXSize = 0;
    3125          46 :     int nReqYSize = 0;
    3126          46 :     int nOutXOff = 0;
    3127          46 :     int nOutYOff = 0;
    3128          46 :     int nOutXSize = 0;
    3129          46 :     int nOutYSize = 0;
    3130          46 :     bool bError = false;
    3131          46 :     if (!poSource->GetSrcDstWindow(nXOff, nYOff, nXSize, nYSize, nXSize, nYSize,
    3132             :                                    &dfReqXOff, &dfReqYOff, &dfReqXSize,
    3133             :                                    &dfReqYSize, &nReqXOff, &nReqYOff,
    3134             :                                    &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
    3135             :                                    &nOutXSize, &nOutYSize, bError))
    3136           0 :         return false;
    3137             : 
    3138          46 :     if (nReqXSize != nXSize || nReqYSize != nYSize || nReqXSize != nOutXSize ||
    3139          46 :         nReqYSize != nOutYSize)
    3140           0 :         return false;
    3141             : 
    3142          46 :     nSrcXOff = nReqXOff;
    3143          46 :     nSrcYOff = nReqYOff;
    3144          46 :     return true;
    3145             : }
    3146             : 
    3147             : /************************************************************************/
    3148             : /*                       GetCompressionFormats()                        */
    3149             : /************************************************************************/
    3150             : 
    3151           0 : CPLStringList VRTDataset::GetCompressionFormats(int nXOff, int nYOff,
    3152             :                                                 int nXSize, int nYSize,
    3153             :                                                 int nBandCount,
    3154             :                                                 const int *panBandList)
    3155             : {
    3156             :     GDALDataset *poSrcDataset;
    3157             :     int nSrcXOff;
    3158             :     int nSrcYOff;
    3159           0 :     if (!GetShiftedDataset(nXOff, nYOff, nXSize, nYSize, poSrcDataset, nSrcXOff,
    3160             :                            nSrcYOff))
    3161           0 :         return CPLStringList();
    3162             :     return poSrcDataset->GetCompressionFormats(nSrcXOff, nSrcYOff, nXSize,
    3163           0 :                                                nYSize, nBandCount, panBandList);
    3164             : }
    3165             : 
    3166             : /************************************************************************/
    3167             : /*                       ReadCompressedData()                           */
    3168             : /************************************************************************/
    3169             : 
    3170          50 : CPLErr VRTDataset::ReadCompressedData(const char *pszFormat, int nXOff,
    3171             :                                       int nYOff, int nXSize, int nYSize,
    3172             :                                       int nBandCount, const int *panBandList,
    3173             :                                       void **ppBuffer, size_t *pnBufferSize,
    3174             :                                       char **ppszDetailedFormat)
    3175             : {
    3176             :     GDALDataset *poSrcDataset;
    3177             :     int nSrcXOff;
    3178             :     int nSrcYOff;
    3179          50 :     if (!GetShiftedDataset(nXOff, nYOff, nXSize, nYSize, poSrcDataset, nSrcXOff,
    3180             :                            nSrcYOff))
    3181           4 :         return CE_Failure;
    3182          46 :     return poSrcDataset->ReadCompressedData(
    3183             :         pszFormat, nSrcXOff, nSrcYOff, nXSize, nYSize, nBandCount, panBandList,
    3184          46 :         ppBuffer, pnBufferSize, ppszDetailedFormat);
    3185             : }
    3186             : 
    3187             : /************************************************************************/
    3188             : /*                          ClearStatistics()                           */
    3189             : /************************************************************************/
    3190             : 
    3191           2 : void VRTDataset::ClearStatistics()
    3192             : {
    3193           6 :     for (int i = 1; i <= nBands; ++i)
    3194             :     {
    3195           4 :         bool bChanged = false;
    3196           4 :         GDALRasterBand *poBand = GetRasterBand(i);
    3197           4 :         CSLConstList papszOldMD = poBand->GetMetadata();
    3198           8 :         CPLStringList aosNewMD;
    3199          14 :         for (const char *pszMDItem : cpl::Iterate(papszOldMD))
    3200             :         {
    3201          10 :             if (STARTS_WITH_CI(pszMDItem, "STATISTICS_"))
    3202             :             {
    3203          10 :                 bChanged = true;
    3204             :             }
    3205             :             else
    3206             :             {
    3207           0 :                 aosNewMD.AddString(pszMDItem);
    3208             :             }
    3209             :         }
    3210           4 :         if (bChanged)
    3211             :         {
    3212           2 :             poBand->SetMetadata(aosNewMD.List());
    3213             :         }
    3214             :     }
    3215             : 
    3216           2 :     GDALDataset::ClearStatistics();
    3217           2 : }
    3218             : 
    3219             : /************************************************************************/
    3220             : /*                   VRTMapSharedResources::Get()                       */
    3221             : /************************************************************************/
    3222             : 
    3223        3284 : GDALDataset *VRTMapSharedResources::Get(const std::string &osKey) const
    3224             : {
    3225        3284 :     if (poMutex)
    3226         134 :         poMutex->lock();
    3227        3284 :     auto oIter = oMap.find(osKey);
    3228        3284 :     GDALDataset *poRet = nullptr;
    3229        3284 :     if (oIter != oMap.end())
    3230         322 :         poRet = oIter->second;
    3231        3284 :     if (poMutex)
    3232         134 :         poMutex->unlock();
    3233        3284 :     return poRet;
    3234             : }
    3235             : 
    3236             : /************************************************************************/
    3237             : /*                   VRTMapSharedResources::Get()                       */
    3238             : /************************************************************************/
    3239             : 
    3240        3108 : void VRTMapSharedResources::Insert(const std::string &osKey, GDALDataset *poDS)
    3241             : {
    3242        3108 :     if (poMutex)
    3243         134 :         poMutex->lock();
    3244        3108 :     oMap[osKey] = poDS;
    3245        3108 :     if (poMutex)
    3246         134 :         poMutex->unlock();
    3247        3108 : }
    3248             : 
    3249             : /************************************************************************/
    3250             : /*                   VRTMapSharedResources::InitMutex()                 */
    3251             : /************************************************************************/
    3252             : 
    3253          20 : void VRTMapSharedResources::InitMutex()
    3254             : {
    3255          20 :     poMutex = &oMutex;
    3256          20 : }
    3257             : 
    3258             : /*! @endcond */

Generated by: LCOV version 1.14