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

Generated by: LCOV version 1.14