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

Generated by: LCOV version 1.14