LCOV - code coverage report
Current view: top level - frmts/vrt - vrtdataset.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 1155 1288 89.7 %
Date: 2024-05-07 17:03:27 Functions: 51 54 94.4 %

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

Generated by: LCOV version 1.14