LCOV - code coverage report
Current view: top level - frmts/vrt - vrtdriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 210 249 84.3 %
Date: 2026-09-09 22:24:20 Functions: 9 11 81.8 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  Virtual GDAL Datasets
       4             :  * Purpose:  Implementation of VRTDriver
       5             :  * Author:   Frank Warmerdam <warmerdam@pobox.com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.com>
       9             :  * Copyright (c) 2009-2013, Even Rouault <even dot rouault at spatialys.com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "vrtdataset.h"
      15             : 
      16             : #include "cpl_minixml.h"
      17             : #include "cpl_string.h"
      18             : #include "gdal_alg_priv.h"
      19             : #include "gdal_frmts.h"
      20             : #include "gdal_priv.h"
      21             : #include "vrtexpression.h"
      22             : 
      23             : #include <mutex>
      24             : 
      25             : /*! @cond Doxygen_Suppress */
      26             : 
      27             : /************************************************************************/
      28             : /*                             VRTDriver()                              */
      29             : /************************************************************************/
      30             : 
      31        1799 : VRTDriver::VRTDriver() : papszSourceParsers(nullptr)
      32             : {
      33             : #if 0
      34             :     pDeserializerData = GDALRegisterTransformDeserializer(
      35             :         "WarpedOverviewTransformer",
      36             :         VRTWarpedOverviewTransform,
      37             :         VRTDeserializeWarpedOverviewTransformer );
      38             : #endif
      39        1799 : }
      40             : 
      41             : /************************************************************************/
      42             : /*                             ~VRTDriver()                             */
      43             : /************************************************************************/
      44             : 
      45        2454 : VRTDriver::~VRTDriver()
      46             : 
      47             : {
      48        1227 :     CSLDestroy(papszSourceParsers);
      49        1227 :     VRTDerivedRasterBand::Cleanup();
      50             : #if 0
      51             :     if(  pDeserializerData )
      52             :     {
      53             :         GDALUnregisterTransformDeserializer( pDeserializerData );
      54             :     }
      55             : #endif
      56        2454 : }
      57             : 
      58             : /************************************************************************/
      59             : /*                       GetMetadataDomainList()                        */
      60             : /************************************************************************/
      61             : 
      62           0 : char **VRTDriver::GetMetadataDomainList()
      63             : {
      64           0 :     return BuildMetadataDomainList(GDALDriver::GetMetadataDomainList(), TRUE,
      65           0 :                                    "SourceParsers", nullptr);
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                            GetMetadata()                             */
      70             : /************************************************************************/
      71             : 
      72        1256 : CSLConstList VRTDriver::GetMetadata(const char *pszDomain)
      73             : 
      74             : {
      75        2512 :     std::lock_guard oLock(m_oMutex);
      76        1256 :     if (pszDomain && EQUAL(pszDomain, "SourceParsers"))
      77           0 :         return papszSourceParsers;
      78             : 
      79        1256 :     return GDALDriver::GetMetadata(pszDomain);
      80             : }
      81             : 
      82             : /************************************************************************/
      83             : /*                            SetMetadata()                             */
      84             : /************************************************************************/
      85             : 
      86           0 : CPLErr VRTDriver::SetMetadata(CSLConstList papszMetadata, const char *pszDomain)
      87             : 
      88             : {
      89           0 :     std::lock_guard oLock(m_oMutex);
      90           0 :     if (pszDomain && EQUAL(pszDomain, "SourceParsers"))
      91             :     {
      92           0 :         m_oMapSourceParser.clear();
      93           0 :         CSLDestroy(papszSourceParsers);
      94           0 :         papszSourceParsers = CSLDuplicate(papszMetadata);
      95           0 :         return CE_None;
      96             :     }
      97             : 
      98           0 :     return GDALDriver::SetMetadata(papszMetadata, pszDomain);
      99             : }
     100             : 
     101             : /************************************************************************/
     102             : /*                          AddSourceParser()                           */
     103             : /************************************************************************/
     104             : 
     105       10794 : void VRTDriver::AddSourceParser(const char *pszElementName,
     106             :                                 VRTSourceParser pfnParser)
     107             : 
     108             : {
     109       10794 :     m_oMapSourceParser[pszElementName] = pfnParser;
     110             : 
     111             :     // Below won't work on architectures with "capability pointers"
     112             : 
     113       10794 :     char szPtrValue[128] = {'\0'};
     114             :     void *ptr;
     115       10794 :     CPL_STATIC_ASSERT(sizeof(pfnParser) == sizeof(void *));
     116       10794 :     memcpy(&ptr, &pfnParser, sizeof(void *));
     117       10794 :     int nRet = CPLPrintPointer(szPtrValue, ptr, sizeof(szPtrValue));
     118       10794 :     szPtrValue[nRet] = 0;
     119             : 
     120       10794 :     papszSourceParsers =
     121       10794 :         CSLSetNameValue(papszSourceParsers, pszElementName, szPtrValue);
     122       10794 : }
     123             : 
     124             : /************************************************************************/
     125             : /*                            ParseSource()                             */
     126             : /************************************************************************/
     127             : 
     128      108524 : VRTSource *VRTDriver::ParseSource(const CPLXMLNode *psSrc,
     129             :                                   const char *pszVRTPath,
     130             :                                   VRTMapSharedResources &oMapSharedSources)
     131             : 
     132             : {
     133             : 
     134      108524 :     if (psSrc == nullptr || psSrc->eType != CXT_Element)
     135             :     {
     136           0 :         CPLError(CE_Failure, CPLE_AppDefined,
     137             :                  "Corrupt or empty VRT source XML document.");
     138           0 :         return nullptr;
     139             :     }
     140             : 
     141      108524 :     if (!m_oMapSourceParser.empty())
     142             :     {
     143      108524 :         auto oIter = m_oMapSourceParser.find(psSrc->pszValue);
     144      108524 :         if (oIter != m_oMapSourceParser.end())
     145             :         {
     146      103891 :             return oIter->second(psSrc, pszVRTPath, oMapSharedSources);
     147             :         }
     148        4633 :         return nullptr;
     149             :     }
     150             : 
     151             :     // Below won't work on architectures with "capability pointers"
     152             : 
     153             :     const char *pszParserFunc =
     154           0 :         CSLFetchNameValue(papszSourceParsers, psSrc->pszValue);
     155           0 :     if (pszParserFunc == nullptr)
     156           0 :         return nullptr;
     157             : 
     158             :     VRTSourceParser pfnParser;
     159           0 :     CPL_STATIC_ASSERT(sizeof(pfnParser) == sizeof(void *));
     160             :     void *ptr =
     161           0 :         CPLScanPointer(pszParserFunc, static_cast<int>(strlen(pszParserFunc)));
     162           0 :     memcpy(&pfnParser, &ptr, sizeof(void *));
     163             : 
     164           0 :     if (pfnParser == nullptr)
     165           0 :         return nullptr;
     166             : 
     167           0 :     return pfnParser(psSrc, pszVRTPath, oMapSharedSources);
     168             : }
     169             : 
     170             : /************************************************************************/
     171             : /*                           VRTCreateCopy()                            */
     172             : /************************************************************************/
     173             : 
     174         306 : static GDALDataset *VRTCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
     175             :                                   int /* bStrict */, CSLConstList papszOptions,
     176             :                                   GDALProgressFunc pfnProgress,
     177             :                                   void *pProgressData)
     178             : {
     179         306 :     CPLAssert(nullptr != poSrcDS);
     180             : 
     181         306 :     VRTDataset *poSrcVRTDS = nullptr;
     182             : 
     183         306 :     void *pHandle = poSrcDS->GetInternalHandle("VRT_DATASET");
     184         306 :     if (pHandle && poSrcDS->GetInternalHandle(nullptr) == nullptr)
     185             :     {
     186           2 :         poSrcVRTDS = static_cast<VRTDataset *>(pHandle);
     187             :     }
     188             :     else
     189             :     {
     190         304 :         poSrcVRTDS = dynamic_cast<VRTDataset *>(poSrcDS);
     191             :     }
     192             : 
     193             :     /* -------------------------------------------------------------------- */
     194             :     /*      If the source dataset is a virtual dataset then just write      */
     195             :     /*      it to disk as a special case to avoid extra layers of           */
     196             :     /*      indirection.                                                    */
     197             :     /* -------------------------------------------------------------------- */
     198         306 :     if (poSrcVRTDS)
     199             :     {
     200             : 
     201             :         /* --------------------------------------------------------------------
     202             :          */
     203             :         /*      Convert tree to a single block of XML text. */
     204             :         /* --------------------------------------------------------------------
     205             :          */
     206         130 :         char *pszVRTPath = CPLStrdup(CPLGetPathSafe(pszFilename).c_str());
     207         130 :         poSrcVRTDS->UnsetPreservedRelativeFilenames();
     208         130 :         CPLXMLNode *psDSTree = poSrcVRTDS->SerializeToXML(pszVRTPath);
     209             : 
     210         130 :         char *pszXML = CPLSerializeXMLTree(psDSTree);
     211             : 
     212         130 :         CPLDestroyXMLNode(psDSTree);
     213             : 
     214         130 :         CPLFree(pszVRTPath);
     215             : 
     216             :         /* --------------------------------------------------------------------
     217             :          */
     218             :         /*      Write to disk. */
     219             :         /* --------------------------------------------------------------------
     220             :          */
     221         130 :         GDALDataset *pCopyDS = nullptr;
     222             : 
     223         130 :         if (0 != strlen(pszFilename))
     224             :         {
     225         118 :             VSILFILE *fpVRT = VSIFOpenL(pszFilename, "wb");
     226         118 :             if (fpVRT == nullptr)
     227             :             {
     228           0 :                 CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
     229             :                          pszFilename);
     230           0 :                 CPLFree(pszXML);
     231           0 :                 return nullptr;
     232             :             }
     233             : 
     234         118 :             bool bRet = VSIFWriteL(pszXML, strlen(pszXML), 1, fpVRT) > 0;
     235         118 :             if (VSIFCloseL(fpVRT) != 0)
     236           0 :                 bRet = false;
     237             : 
     238         118 :             if (bRet)
     239         118 :                 pCopyDS = GDALDataset::Open(
     240             :                     pszFilename,
     241             :                     GDAL_OF_RASTER | GDAL_OF_MULTIDIM_RASTER | GDAL_OF_UPDATE);
     242             :         }
     243             :         else
     244             :         {
     245             :             /* No destination file is given, so pass serialized XML directly. */
     246          12 :             pCopyDS = GDALDataset::Open(pszXML, GDAL_OF_RASTER |
     247             :                                                     GDAL_OF_MULTIDIM_RASTER |
     248             :                                                     GDAL_OF_UPDATE);
     249             :         }
     250             : 
     251         130 :         CPLFree(pszXML);
     252             : 
     253         130 :         return pCopyDS;
     254             :     }
     255             : 
     256             :     /* -------------------------------------------------------------------- */
     257             :     /*      Multidimensional raster ?                                       */
     258             :     /* -------------------------------------------------------------------- */
     259         352 :     auto poSrcGroup = poSrcDS->GetRootGroup();
     260         176 :     if (poSrcGroup != nullptr)
     261             :     {
     262             :         auto poDstDS = VRTDataset::CreateVRTMultiDimensional(pszFilename,
     263           8 :                                                              nullptr, nullptr);
     264           4 :         if (!poDstDS)
     265           0 :             return nullptr;
     266           8 :         auto poDstGroup = poDstDS->GetRootVRTGroup();
     267           4 :         if (!poDstGroup)
     268           0 :             return nullptr;
     269           4 :         poDstGroup->SetGuessRegularlySpacedArrays(
     270           4 :             CPLTestBool(CSLFetchNameValueDef(
     271             :                 papszOptions, "GUESS_REGULARLY_SPACED_ARRAYS", "YES")));
     272           4 :         if (GDALDriver::DefaultCreateCopyMultiDimensional(
     273           8 :                 poSrcDS, poDstDS.get(), false, nullptr, nullptr, nullptr) !=
     274             :             CE_None)
     275           0 :             return nullptr;
     276             : 
     277           4 :         if (strcmp(pszFilename, "") != 0)
     278             :         {
     279           4 :             if (poDstDS->FlushCache(true) != CE_None)
     280             :             {
     281           1 :                 poDstDS.reset();
     282             :             }
     283             :         }
     284             : 
     285           4 :         if (pfnProgress)
     286           4 :             pfnProgress(1.0, "", pProgressData);
     287           4 :         return poDstDS.release();
     288             :     }
     289             : 
     290             :     /* -------------------------------------------------------------------- */
     291             :     /*      Create the virtual dataset.                                     */
     292             :     /* -------------------------------------------------------------------- */
     293             :     auto poVRTDS = VRTDataset::CreateVRTDataset(
     294             :         pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), 0,
     295         344 :         GDT_UInt8, papszOptions);
     296         172 :     if (poVRTDS == nullptr)
     297           0 :         return nullptr;
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      Do we have a geotransform?                                      */
     301             :     /* -------------------------------------------------------------------- */
     302         172 :     GDALGeoTransform gt;
     303         172 :     if (poSrcDS->GetGeoTransform(gt) == CE_None)
     304             :     {
     305         139 :         poVRTDS->SetGeoTransform(gt);
     306             :     }
     307             : 
     308             :     /* -------------------------------------------------------------------- */
     309             :     /*      Copy projection                                                 */
     310             :     /* -------------------------------------------------------------------- */
     311         172 :     poVRTDS->SetSpatialRef(poSrcDS->GetSpatialRef());
     312             : 
     313             :     /* -------------------------------------------------------------------- */
     314             :     /*      Emit dataset level metadata.                                    */
     315             :     /* -------------------------------------------------------------------- */
     316             :     const char *pszCopySrcMDD =
     317         172 :         CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
     318         172 :     char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
     319         172 :     if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
     320             :         papszSrcMDD)
     321             :     {
     322         173 :         if (!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
     323           2 :             CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0)
     324             :         {
     325         169 :             poVRTDS->SetMetadata(poSrcDS->GetMetadata());
     326             :         }
     327             : 
     328             :         /* -------------------------------------------------------------------- */
     329             :         /*      Copy any special domains that should be transportable.          */
     330             :         /* -------------------------------------------------------------------- */
     331         171 :         constexpr const char *apszDefaultDomains[] = {
     332             :             GDAL_MDD_RPC, GDAL_MDD_IMD, GDAL_MDD_GEOLOCATION};
     333         684 :         for (const char *pszDomain : apszDefaultDomains)
     334             :         {
     335         513 :             if (!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0)
     336             :             {
     337         504 :                 CSLConstList papszMD = poSrcDS->GetMetadata(pszDomain);
     338         504 :                 if (papszMD)
     339           0 :                     poVRTDS->SetMetadata(papszMD, pszDomain);
     340             :             }
     341             :         }
     342             : 
     343         171 :         if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
     344             :             papszSrcMDD)
     345             :         {
     346           4 :             char **papszDomainList = poSrcDS->GetMetadataDomainList();
     347           4 :             constexpr const char *apszReservedDomains[] = {
     348             :                 GDAL_MDD_IMAGE_STRUCTURE, "DERIVED_SUBDATASETS"};
     349          18 :             for (char **papszIter = papszDomainList; papszIter && *papszIter;
     350             :                  ++papszIter)
     351             :             {
     352          14 :                 const char *pszDomain = *papszIter;
     353          22 :                 if (pszDomain[0] != 0 &&
     354           8 :                     (!papszSrcMDD ||
     355           8 :                      CSLFindString(papszSrcMDD, pszDomain) >= 0))
     356             :                 {
     357           6 :                     bool bCanCopy = true;
     358          24 :                     for (const char *pszOtherDomain : apszDefaultDomains)
     359             :                     {
     360          18 :                         if (EQUAL(pszDomain, pszOtherDomain))
     361             :                         {
     362           0 :                             bCanCopy = false;
     363           0 :                             break;
     364             :                         }
     365             :                     }
     366           6 :                     if (!papszSrcMDD)
     367             :                     {
     368           6 :                         for (const char *pszOtherDomain : apszReservedDomains)
     369             :                         {
     370           5 :                             if (EQUAL(pszDomain, pszOtherDomain))
     371             :                             {
     372           2 :                                 bCanCopy = false;
     373           2 :                                 break;
     374             :                             }
     375             :                         }
     376             :                     }
     377           6 :                     if (bCanCopy)
     378             :                     {
     379           8 :                         poVRTDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
     380           4 :                                              pszDomain);
     381             :                     }
     382             :                 }
     383             :             }
     384           4 :             CSLDestroy(papszDomainList);
     385             :         }
     386             :     }
     387         172 :     CSLDestroy(papszSrcMDD);
     388             : 
     389             :     {
     390         344 :         const char *pszInterleave = poSrcDS->GetMetadataItem(
     391         172 :             GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE);
     392         172 :         if (pszInterleave)
     393             :         {
     394         138 :             poVRTDS->SetMetadataItem(GDALMD_INTERLEAVE, pszInterleave,
     395         138 :                                      GDAL_MDD_IMAGE_STRUCTURE);
     396             :         }
     397             :     }
     398             :     {
     399         344 :         const char *pszCompression = poSrcDS->GetMetadataItem(
     400         172 :             GDALMD_COMPRESSION, GDAL_MDD_IMAGE_STRUCTURE);
     401         172 :         if (pszCompression)
     402             :         {
     403           6 :             poVRTDS->SetMetadataItem(GDALMD_COMPRESSION, pszCompression,
     404           6 :                                      GDAL_MDD_IMAGE_STRUCTURE);
     405             :         }
     406             :     }
     407             : 
     408             :     /* -------------------------------------------------------------------- */
     409             :     /*      GCPs                                                            */
     410             :     /* -------------------------------------------------------------------- */
     411         172 :     if (poSrcDS->GetGCPCount() > 0)
     412             :     {
     413           2 :         poVRTDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
     414           1 :                          poSrcDS->GetGCPSpatialRef());
     415             :     }
     416             : 
     417             :     /* -------------------------------------------------------------------- */
     418             :     /*      Loop over all the bands.                                        */
     419             :     /* -------------------------------------------------------------------- */
     420       66019 :     for (int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++)
     421             :     {
     422       65847 :         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
     423             : 
     424             :         /* --------------------------------------------------------------------
     425             :          */
     426             :         /*      Create the band with the appropriate band type. */
     427             :         /* --------------------------------------------------------------------
     428             :          */
     429      131694 :         CPLStringList aosAddBandOptions;
     430       65847 :         int nBlockXSize = poVRTDS->GetBlockXSize();
     431       65847 :         int nBlockYSize = poVRTDS->GetBlockYSize();
     432       65847 :         if (!poVRTDS->IsBlockSizeSpecified())
     433             :         {
     434       65845 :             poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     435             :         }
     436             :         aosAddBandOptions.SetNameValue("BLOCKXSIZE",
     437       65847 :                                        CPLSPrintf("%d", nBlockXSize));
     438             :         aosAddBandOptions.SetNameValue("BLOCKYSIZE",
     439       65847 :                                        CPLSPrintf("%d", nBlockYSize));
     440       65847 :         poVRTDS->AddBand(poSrcBand->GetRasterDataType(), aosAddBandOptions);
     441             : 
     442             :         VRTSourcedRasterBand *poVRTBand = static_cast<VRTSourcedRasterBand *>(
     443       65847 :             poVRTDS->GetRasterBand(iBand + 1));
     444             : 
     445             :         /* --------------------------------------------------------------------
     446             :          */
     447             :         /*      Setup source mapping. */
     448             :         /* --------------------------------------------------------------------
     449             :          */
     450       65847 :         poVRTBand->AddSimpleSource(poSrcBand);
     451             : 
     452             :         /* --------------------------------------------------------------------
     453             :          */
     454             :         /*      Emit various band level metadata. */
     455             :         /* --------------------------------------------------------------------
     456             :          */
     457       65847 :         poVRTBand->CopyCommonInfoFrom(poSrcBand);
     458             : 
     459      131694 :         const char *pszCompression = poSrcBand->GetMetadataItem(
     460       65847 :             GDALMD_COMPRESSION, GDAL_MDD_IMAGE_STRUCTURE);
     461       65847 :         if (pszCompression)
     462             :         {
     463           3 :             poVRTBand->SetMetadataItem(GDALMD_COMPRESSION, pszCompression,
     464           3 :                                        GDAL_MDD_IMAGE_STRUCTURE);
     465             :         }
     466             : 
     467             :         /* --------------------------------------------------------------------
     468             :          */
     469             :         /*      Add specific mask band. */
     470             :         /* --------------------------------------------------------------------
     471             :          */
     472       65847 :         if ((poSrcBand->GetMaskFlags() &
     473       65847 :              (GMF_PER_DATASET | GMF_ALL_VALID | GMF_NODATA)) == 0)
     474             :         {
     475             :             auto poVRTMaskBand = std::make_unique<VRTSourcedRasterBand>(
     476           0 :                 poVRTDS.get(), 0, poSrcBand->GetMaskBand()->GetRasterDataType(),
     477           0 :                 poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize());
     478           0 :             poVRTMaskBand->AddMaskBandSource(poSrcBand);
     479           0 :             poVRTBand->SetMaskBand(std::move(poVRTMaskBand));
     480             :         }
     481             :     }
     482             : 
     483             :     /* -------------------------------------------------------------------- */
     484             :     /*      Add dataset mask band                                           */
     485             :     /* -------------------------------------------------------------------- */
     486         172 :     if (poSrcDS->GetRasterCount() != 0 &&
     487         343 :         poSrcDS->GetRasterBand(1) != nullptr &&
     488         171 :         poSrcDS->GetRasterBand(1)->GetMaskFlags() == GMF_PER_DATASET)
     489             :     {
     490           2 :         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
     491             :         auto poVRTMaskBand = std::make_unique<VRTSourcedRasterBand>(
     492           2 :             poVRTDS.get(), 0, poSrcBand->GetMaskBand()->GetRasterDataType(),
     493           4 :             poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize());
     494           2 :         poVRTMaskBand->AddMaskBandSource(poSrcBand);
     495           2 :         poVRTDS->SetMaskBand(std::move(poVRTMaskBand));
     496             :     }
     497             : 
     498         172 :     if (strcmp(pszFilename, "") != 0)
     499             :     {
     500          86 :         if (poVRTDS->FlushCache(true) != CE_None)
     501             :         {
     502          11 :             poVRTDS.reset();
     503             :         }
     504             :     }
     505             : 
     506         172 :     if (pfnProgress)
     507         172 :         pfnProgress(1.0, "", pProgressData);
     508             : 
     509         172 :     return poVRTDS.release();
     510             : }
     511             : 
     512             : /************************************************************************/
     513             : /*                          GDALRegister_VRT()                          */
     514             : /************************************************************************/
     515             : 
     516        8699 : void GDALRegister_VRT()
     517             : 
     518             : {
     519        8699 :     auto poDM = GetGDALDriverManager();
     520        8699 :     if (poDM->GetDriverByName("VRT") != nullptr)
     521        6900 :         return;
     522             : 
     523             :     static std::once_flag flag;
     524        1799 :     std::call_once(flag,
     525        1599 :                    []()
     526             :                    {
     527             :                        // First register the pixel functions
     528        1599 :                        GDALRegisterDefaultPixelFunc();
     529             : 
     530             :                        // Register functions for VRTProcessedDataset
     531        1599 :                        GDALVRTRegisterDefaultProcessedDatasetFuncs();
     532        1599 :                    });
     533             : 
     534        1799 :     VRTDriver *poDriver = new VRTDriver();
     535             : 
     536        1799 :     poDriver->SetDescription("VRT");
     537        1799 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     538        1799 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     539        1799 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Virtual Raster");
     540        1799 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "vrt");
     541        1799 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/vrt.html");
     542        1799 :     poDriver->SetMetadataItem(
     543             :         GDAL_DMD_CREATIONDATATYPES,
     544             :         "Byte Int8 Int16 UInt16 Int32 UInt32 Int64 UInt64 "
     545             :         "Float16 Float32 Float64 "
     546        1799 :         "CInt16 CInt32 CFloat16 CFloat32 CFloat64");
     547        1799 :     poDriver->SetMetadataItem(
     548             :         GDAL_DMD_CREATIONOPTIONLIST,
     549             :         "<CreationOptionList>\n"
     550             :         "   <Option name='SUBCLASS' type='string-select' "
     551             :         "default='VRTDataset'>\n"
     552             :         "       <Value>VRTDataset</Value>\n"
     553             :         "       <Value>VRTWarpedDataset</Value>\n"
     554             :         "   </Option>\n"
     555             :         "   <Option name='BLOCKXSIZE' type='int' description='Block width'/>\n"
     556             :         "   <Option name='BLOCKYSIZE' type='int' description='Block height'/>\n"
     557        1799 :         "</CreationOptionList>\n");
     558             : 
     559        1799 :     auto poGTiffDrv = poDM->GetDriverByName("GTiff");
     560        1799 :     if (poGTiffDrv)
     561             :     {
     562             :         const char *pszGTiffOvrCO =
     563        1799 :             poGTiffDrv->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
     564        1799 :         if (pszGTiffOvrCO &&
     565        1799 :             STARTS_WITH(pszGTiffOvrCO, "<OverviewCreationOptionList>"))
     566             :         {
     567             :             std::string ocoList =
     568             :                 "<OverviewCreationOptionList>"
     569             :                 "   <Option name='VIRTUAL' type='boolean' "
     570             :                 "default='NO' "
     571             :                 "description='Whether virtual overviews rather than "
     572        3598 :                 "materialized external GeoTIFF .ovr should be created'/>";
     573        1799 :             ocoList += (pszGTiffOvrCO + strlen("<OverviewCreationOptionList>"));
     574        1799 :             poDriver->SetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST,
     575        1799 :                                       ocoList.c_str());
     576             :         }
     577             :     }
     578             : 
     579        1799 :     poDriver->SetMetadataItem(
     580             :         GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
     581             :         "<MultiDimDatasetCreationOptionList>"
     582             :         "   <Option name='GUESS_REGULARLY_SPACED_ARRAYS' type='boolean' "
     583             :         "description='Whether content of 1D-arrays should be read to deduce "
     584             :         "if they are regularly spaced. Can be slow on huge remote datasets' "
     585             :         "default='YES'/>"
     586        1799 :         "</MultiDimDatasetCreationOptionList>");
     587             : 
     588        1799 :     poDriver->SetMetadataItem(
     589             :         GDAL_DMD_MULTIDIM_ARRAY_CREATIONOPTIONLIST,
     590             :         "<MultiDimArrayCreationOptionList>"
     591             :         "   <Option name='BLOCKSIZE' type='int' description='Block size in "
     592             :         "pixels'/>"
     593        1799 :         "</MultiDimArrayCreationOptionList>");
     594             : 
     595        1799 :     poDriver->pfnCreateCopy = VRTCreateCopy;
     596        1799 :     poDriver->pfnCreate = VRTDataset::Create;
     597        1799 :     poDriver->pfnCreateMultiDimensional = VRTDataset::CreateMultiDimensional;
     598             : 
     599             : #ifndef NO_OPEN
     600        1799 :     poDriver->pfnOpen = VRTDataset::Open;
     601        1799 :     poDriver->pfnIdentify = VRTDataset::Identify;
     602        1799 :     poDriver->pfnDelete = VRTDataset::Delete;
     603             : 
     604        1799 :     poDriver->SetMetadataItem(
     605             :         GDAL_DMD_OPENOPTIONLIST,
     606             :         "<OpenOptionList>"
     607             :         "  <Option name='ROOT_PATH' type='string' description='Root path to "
     608             :         "evaluate "
     609             :         "relative paths inside the VRT. Mainly useful for inlined VRT, or "
     610             :         "in-memory "
     611             :         "VRT, where their own directory does not make sense'/>"
     612             :         "<Option name='NUM_THREADS' type='string' description="
     613             :         "'Number of worker threads for reading. Can be set to ALL_CPUS' "
     614             :         "default='ALL_CPUS'/>"
     615        1799 :         "</OpenOptionList>");
     616             : #endif
     617             : 
     618        1799 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     619        1799 :     poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
     620             : 
     621        1799 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
     622        1799 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
     623             :                               "GeoTransform SRS GCPs NoData "
     624             :                               "ColorInterpretation "
     625        1799 :                               "DatasetMetadata BandMetadata");
     626             : 
     627        1799 :     const char *pszExpressionDialects = "ExpressionDialects";
     628             : #if defined(GDAL_VRT_ENABLE_MUPARSER) && defined(GDAL_VRT_ENABLE_EXPRTK)
     629        1799 :     poDriver->SetMetadataItem(pszExpressionDialects, "muparser,exprtk");
     630             : #elif defined(GDAL_VRT_ENABLE_MUPARSER)
     631             :     poDriver->SetMetadataItem(pszExpressionDialects, "muparser");
     632             : #elif defined(GDAL_VRT_ENABLE_EXPRTK)
     633             :     poDriver->SetMetadataItem(pszExpressionDialects, "exprtk");
     634             : #else
     635             :     poDriver->SetMetadataItem(pszExpressionDialects, "none");
     636             : #endif
     637             : 
     638             : #ifdef GDAL_VRT_ENABLE_MUPARSER
     639        1799 :     if (gdal::MuParserHasDefineFunUserData())
     640             :     {
     641           0 :         poDriver->SetMetadataItem("MUPARSER_HAS_DEFINE_FUN_USER_DATA", "YES");
     642             :     }
     643             : #endif
     644             : 
     645             : #ifdef GDAL_VRT_ENABLE_RAWRASTERBAND
     646        1799 :     poDriver->SetMetadataItem("GDAL_VRT_ENABLE_RAWRASTERBAND", "YES");
     647             : #endif
     648             : 
     649        1799 :     poDriver->AddSourceParser("SimpleSource", VRTParseCoreSources);
     650        1799 :     poDriver->AddSourceParser("ComplexSource", VRTParseCoreSources);
     651        1799 :     poDriver->AddSourceParser("AveragedSource", VRTParseCoreSources);
     652        1799 :     poDriver->AddSourceParser("NoDataFromMaskSource", VRTParseCoreSources);
     653        1799 :     poDriver->AddSourceParser("KernelFilteredSource", VRTParseFilterSources);
     654        1799 :     poDriver->AddSourceParser("ArraySource", VRTParseArraySource);
     655             : 
     656        1799 :     poDM->RegisterDriver(poDriver);
     657             : }
     658             : 
     659             : /*! @endcond */

Generated by: LCOV version 1.14