LCOV - code coverage report
Current view: top level - frmts/vrt - vrtdriver.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 212 248 85.5 %
Date: 2026-06-15 16:25:14 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        1872 : VRTDriver::VRTDriver() : papszSourceParsers(nullptr)
      32             : {
      33             : #if 0
      34             :     pDeserializerData = GDALRegisterTransformDeserializer(
      35             :         "WarpedOverviewTransformer",
      36             :         VRTWarpedOverviewTransform,
      37             :         VRTDeserializeWarpedOverviewTransformer );
      38             : #endif
      39        1872 : }
      40             : 
      41             : /************************************************************************/
      42             : /*                             ~VRTDriver()                             */
      43             : /************************************************************************/
      44             : 
      45        2602 : VRTDriver::~VRTDriver()
      46             : 
      47             : {
      48        1301 :     CSLDestroy(papszSourceParsers);
      49        1301 :     VRTDerivedRasterBand::Cleanup();
      50             : #if 0
      51             :     if(  pDeserializerData )
      52             :     {
      53             :         GDALUnregisterTransformDeserializer( pDeserializerData );
      54             :     }
      55             : #endif
      56        2602 : }
      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        1227 : CSLConstList VRTDriver::GetMetadata(const char *pszDomain)
      73             : 
      74             : {
      75        2454 :     std::lock_guard oLock(m_oMutex);
      76        1227 :     if (pszDomain && EQUAL(pszDomain, "SourceParsers"))
      77           0 :         return papszSourceParsers;
      78             : 
      79        1227 :     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       11232 : void VRTDriver::AddSourceParser(const char *pszElementName,
     106             :                                 VRTSourceParser pfnParser)
     107             : 
     108             : {
     109       11232 :     m_oMapSourceParser[pszElementName] = pfnParser;
     110             : 
     111             :     // Below won't work on architectures with "capability pointers"
     112             : 
     113       11232 :     char szPtrValue[128] = {'\0'};
     114             :     void *ptr;
     115       11232 :     CPL_STATIC_ASSERT(sizeof(pfnParser) == sizeof(void *));
     116       11232 :     memcpy(&ptr, &pfnParser, sizeof(void *));
     117       11232 :     int nRet = CPLPrintPointer(szPtrValue, ptr, sizeof(szPtrValue));
     118       11232 :     szPtrValue[nRet] = 0;
     119             : 
     120       11232 :     papszSourceParsers =
     121       11232 :         CSLSetNameValue(papszSourceParsers, pszElementName, szPtrValue);
     122       11232 : }
     123             : 
     124             : /************************************************************************/
     125             : /*                            ParseSource()                             */
     126             : /************************************************************************/
     127             : 
     128      109233 : VRTSource *VRTDriver::ParseSource(const CPLXMLNode *psSrc,
     129             :                                   const char *pszVRTPath,
     130             :                                   VRTMapSharedResources &oMapSharedSources)
     131             : 
     132             : {
     133             : 
     134      109233 :     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      109233 :     if (!m_oMapSourceParser.empty())
     142             :     {
     143      109233 :         auto oIter = m_oMapSourceParser.find(psSrc->pszValue);
     144      109233 :         if (oIter != m_oMapSourceParser.end())
     145             :         {
     146      104195 :             return oIter->second(psSrc, pszVRTPath, oMapSharedSources);
     147             :         }
     148        5038 :         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         380 : static GDALDataset *VRTCreateCopy(const char *pszFilename, GDALDataset *poSrcDS,
     175             :                                   int /* bStrict */, CSLConstList papszOptions,
     176             :                                   GDALProgressFunc pfnProgress,
     177             :                                   void *pProgressData)
     178             : {
     179         380 :     CPLAssert(nullptr != poSrcDS);
     180             : 
     181         380 :     VRTDataset *poSrcVRTDS = nullptr;
     182             : 
     183         380 :     void *pHandle = poSrcDS->GetInternalHandle("VRT_DATASET");
     184         380 :     if (pHandle && poSrcDS->GetInternalHandle(nullptr) == nullptr)
     185             :     {
     186           1 :         poSrcVRTDS = static_cast<VRTDataset *>(pHandle);
     187             :     }
     188             :     else
     189             :     {
     190         379 :         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         380 :     if (poSrcVRTDS)
     199             :     {
     200             : 
     201             :         /* --------------------------------------------------------------------
     202             :          */
     203             :         /*      Convert tree to a single block of XML text. */
     204             :         /* --------------------------------------------------------------------
     205             :          */
     206         129 :         char *pszVRTPath = CPLStrdup(CPLGetPathSafe(pszFilename).c_str());
     207         129 :         poSrcVRTDS->UnsetPreservedRelativeFilenames();
     208         129 :         CPLXMLNode *psDSTree = poSrcVRTDS->SerializeToXML(pszVRTPath);
     209             : 
     210         129 :         char *pszXML = CPLSerializeXMLTree(psDSTree);
     211             : 
     212         129 :         CPLDestroyXMLNode(psDSTree);
     213             : 
     214         129 :         CPLFree(pszVRTPath);
     215             : 
     216             :         /* --------------------------------------------------------------------
     217             :          */
     218             :         /*      Write to disk. */
     219             :         /* --------------------------------------------------------------------
     220             :          */
     221         129 :         GDALDataset *pCopyDS = nullptr;
     222             : 
     223         129 :         if (0 != strlen(pszFilename))
     224             :         {
     225         118 :             VSILFILE *fpVRT = VSIFOpenL(pszFilename, "wb");
     226         118 :             if (fpVRT == nullptr)
     227             :             {
     228           1 :                 CPLError(CE_Failure, CPLE_AppDefined, "Cannot create %s",
     229             :                          pszFilename);
     230           1 :                 CPLFree(pszXML);
     231           1 :                 return nullptr;
     232             :             }
     233             : 
     234         117 :             bool bRet = VSIFWriteL(pszXML, strlen(pszXML), 1, fpVRT) > 0;
     235         117 :             if (VSIFCloseL(fpVRT) != 0)
     236           0 :                 bRet = false;
     237             : 
     238         117 :             if (bRet)
     239         117 :                 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          11 :             pCopyDS = GDALDataset::Open(pszXML, GDAL_OF_RASTER |
     247             :                                                     GDAL_OF_MULTIDIM_RASTER |
     248             :                                                     GDAL_OF_UPDATE);
     249             :         }
     250             : 
     251         128 :         CPLFree(pszXML);
     252             : 
     253         128 :         return pCopyDS;
     254             :     }
     255             : 
     256             :     /* -------------------------------------------------------------------- */
     257             :     /*      Multidimensional raster ?                                       */
     258             :     /* -------------------------------------------------------------------- */
     259         502 :     auto poSrcGroup = poSrcDS->GetRootGroup();
     260         251 :     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           4 :         if (pfnProgress)
     277           4 :             pfnProgress(1.0, "", pProgressData);
     278           4 :         return poDstDS.release();
     279             :     }
     280             : 
     281             :     /* -------------------------------------------------------------------- */
     282             :     /*      Create the virtual dataset.                                     */
     283             :     /* -------------------------------------------------------------------- */
     284             :     auto poVRTDS = VRTDataset::CreateVRTDataset(
     285             :         pszFilename, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), 0,
     286         494 :         GDT_UInt8, papszOptions);
     287         247 :     if (poVRTDS == nullptr)
     288           0 :         return nullptr;
     289             : 
     290             :     /* -------------------------------------------------------------------- */
     291             :     /*      Do we have a geotransform?                                      */
     292             :     /* -------------------------------------------------------------------- */
     293         247 :     GDALGeoTransform gt;
     294         247 :     if (poSrcDS->GetGeoTransform(gt) == CE_None)
     295             :     {
     296         216 :         poVRTDS->SetGeoTransform(gt);
     297             :     }
     298             : 
     299             :     /* -------------------------------------------------------------------- */
     300             :     /*      Copy projection                                                 */
     301             :     /* -------------------------------------------------------------------- */
     302         247 :     poVRTDS->SetSpatialRef(poSrcDS->GetSpatialRef());
     303             : 
     304             :     /* -------------------------------------------------------------------- */
     305             :     /*      Emit dataset level metadata.                                    */
     306             :     /* -------------------------------------------------------------------- */
     307             :     const char *pszCopySrcMDD =
     308         247 :         CSLFetchNameValueDef(papszOptions, "COPY_SRC_MDD", "AUTO");
     309         247 :     char **papszSrcMDD = CSLFetchNameValueMultiple(papszOptions, "SRC_MDD");
     310         247 :     if (EQUAL(pszCopySrcMDD, "AUTO") || CPLTestBool(pszCopySrcMDD) ||
     311             :         papszSrcMDD)
     312             :     {
     313         248 :         if (!papszSrcMDD || CSLFindString(papszSrcMDD, "") >= 0 ||
     314           2 :             CSLFindString(papszSrcMDD, "_DEFAULT_") >= 0)
     315             :         {
     316         244 :             poVRTDS->SetMetadata(poSrcDS->GetMetadata());
     317             :         }
     318             : 
     319             :         /* -------------------------------------------------------------------- */
     320             :         /*      Copy any special domains that should be transportable.          */
     321             :         /* -------------------------------------------------------------------- */
     322         246 :         constexpr const char *apszDefaultDomains[] = {
     323             :             GDAL_MDD_RPC, GDAL_MDD_IMD, GDAL_MDD_GEOLOCATION};
     324         984 :         for (const char *pszDomain : apszDefaultDomains)
     325             :         {
     326         738 :             if (!papszSrcMDD || CSLFindString(papszSrcMDD, pszDomain) >= 0)
     327             :             {
     328         729 :                 CSLConstList papszMD = poSrcDS->GetMetadata(pszDomain);
     329         729 :                 if (papszMD)
     330           0 :                     poVRTDS->SetMetadata(papszMD, pszDomain);
     331             :             }
     332             :         }
     333             : 
     334         246 :         if ((!EQUAL(pszCopySrcMDD, "AUTO") && CPLTestBool(pszCopySrcMDD)) ||
     335             :             papszSrcMDD)
     336             :         {
     337           4 :             char **papszDomainList = poSrcDS->GetMetadataDomainList();
     338           4 :             constexpr const char *apszReservedDomains[] = {
     339             :                 GDAL_MDD_IMAGE_STRUCTURE, "DERIVED_SUBDATASETS"};
     340          18 :             for (char **papszIter = papszDomainList; papszIter && *papszIter;
     341             :                  ++papszIter)
     342             :             {
     343          14 :                 const char *pszDomain = *papszIter;
     344          22 :                 if (pszDomain[0] != 0 &&
     345           8 :                     (!papszSrcMDD ||
     346           8 :                      CSLFindString(papszSrcMDD, pszDomain) >= 0))
     347             :                 {
     348           6 :                     bool bCanCopy = true;
     349          24 :                     for (const char *pszOtherDomain : apszDefaultDomains)
     350             :                     {
     351          18 :                         if (EQUAL(pszDomain, pszOtherDomain))
     352             :                         {
     353           0 :                             bCanCopy = false;
     354           0 :                             break;
     355             :                         }
     356             :                     }
     357           6 :                     if (!papszSrcMDD)
     358             :                     {
     359           6 :                         for (const char *pszOtherDomain : apszReservedDomains)
     360             :                         {
     361           5 :                             if (EQUAL(pszDomain, pszOtherDomain))
     362             :                             {
     363           2 :                                 bCanCopy = false;
     364           2 :                                 break;
     365             :                             }
     366             :                         }
     367             :                     }
     368           6 :                     if (bCanCopy)
     369             :                     {
     370           8 :                         poVRTDS->SetMetadata(poSrcDS->GetMetadata(pszDomain),
     371           4 :                                              pszDomain);
     372             :                     }
     373             :                 }
     374             :             }
     375           4 :             CSLDestroy(papszDomainList);
     376             :         }
     377             :     }
     378         247 :     CSLDestroy(papszSrcMDD);
     379             : 
     380             :     {
     381         494 :         const char *pszInterleave = poSrcDS->GetMetadataItem(
     382         247 :             GDALMD_INTERLEAVE, GDAL_MDD_IMAGE_STRUCTURE);
     383         247 :         if (pszInterleave)
     384             :         {
     385         213 :             poVRTDS->SetMetadataItem(GDALMD_INTERLEAVE, pszInterleave,
     386         213 :                                      GDAL_MDD_IMAGE_STRUCTURE);
     387             :         }
     388             :     }
     389             :     {
     390         494 :         const char *pszCompression = poSrcDS->GetMetadataItem(
     391         247 :             GDALMD_COMPRESSION, GDAL_MDD_IMAGE_STRUCTURE);
     392         247 :         if (pszCompression)
     393             :         {
     394           6 :             poVRTDS->SetMetadataItem(GDALMD_COMPRESSION, pszCompression,
     395           6 :                                      GDAL_MDD_IMAGE_STRUCTURE);
     396             :         }
     397             :     }
     398             : 
     399             :     /* -------------------------------------------------------------------- */
     400             :     /*      GCPs                                                            */
     401             :     /* -------------------------------------------------------------------- */
     402         247 :     if (poSrcDS->GetGCPCount() > 0)
     403             :     {
     404           2 :         poVRTDS->SetGCPs(poSrcDS->GetGCPCount(), poSrcDS->GetGCPs(),
     405           1 :                          poSrcDS->GetGCPSpatialRef());
     406             :     }
     407             : 
     408             :     /* -------------------------------------------------------------------- */
     409             :     /*      Loop over all the bands.                                        */
     410             :     /* -------------------------------------------------------------------- */
     411       66133 :     for (int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++)
     412             :     {
     413       65886 :         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(iBand + 1);
     414             : 
     415             :         /* --------------------------------------------------------------------
     416             :          */
     417             :         /*      Create the band with the appropriate band type. */
     418             :         /* --------------------------------------------------------------------
     419             :          */
     420      131772 :         CPLStringList aosAddBandOptions;
     421       65886 :         int nBlockXSize = poVRTDS->GetBlockXSize();
     422       65886 :         int nBlockYSize = poVRTDS->GetBlockYSize();
     423       65886 :         if (!poVRTDS->IsBlockSizeSpecified())
     424             :         {
     425       65884 :             poSrcBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
     426             :         }
     427             :         aosAddBandOptions.SetNameValue("BLOCKXSIZE",
     428       65886 :                                        CPLSPrintf("%d", nBlockXSize));
     429             :         aosAddBandOptions.SetNameValue("BLOCKYSIZE",
     430       65886 :                                        CPLSPrintf("%d", nBlockYSize));
     431       65886 :         poVRTDS->AddBand(poSrcBand->GetRasterDataType(), aosAddBandOptions);
     432             : 
     433             :         VRTSourcedRasterBand *poVRTBand = static_cast<VRTSourcedRasterBand *>(
     434       65886 :             poVRTDS->GetRasterBand(iBand + 1));
     435             : 
     436             :         /* --------------------------------------------------------------------
     437             :          */
     438             :         /*      Setup source mapping. */
     439             :         /* --------------------------------------------------------------------
     440             :          */
     441       65886 :         poVRTBand->AddSimpleSource(poSrcBand);
     442             : 
     443             :         /* --------------------------------------------------------------------
     444             :          */
     445             :         /*      Emit various band level metadata. */
     446             :         /* --------------------------------------------------------------------
     447             :          */
     448       65886 :         poVRTBand->CopyCommonInfoFrom(poSrcBand);
     449             : 
     450      131772 :         const char *pszCompression = poSrcBand->GetMetadataItem(
     451       65886 :             GDALMD_COMPRESSION, GDAL_MDD_IMAGE_STRUCTURE);
     452       65886 :         if (pszCompression)
     453             :         {
     454           3 :             poVRTBand->SetMetadataItem(GDALMD_COMPRESSION, pszCompression,
     455           3 :                                        GDAL_MDD_IMAGE_STRUCTURE);
     456             :         }
     457             : 
     458             :         /* --------------------------------------------------------------------
     459             :          */
     460             :         /*      Add specific mask band. */
     461             :         /* --------------------------------------------------------------------
     462             :          */
     463       65886 :         if ((poSrcBand->GetMaskFlags() &
     464       65886 :              (GMF_PER_DATASET | GMF_ALL_VALID | GMF_NODATA)) == 0)
     465             :         {
     466             :             auto poVRTMaskBand = std::make_unique<VRTSourcedRasterBand>(
     467           0 :                 poVRTDS.get(), 0, poSrcBand->GetMaskBand()->GetRasterDataType(),
     468           0 :                 poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize());
     469           0 :             poVRTMaskBand->AddMaskBandSource(poSrcBand);
     470           0 :             poVRTBand->SetMaskBand(std::move(poVRTMaskBand));
     471             :         }
     472             :     }
     473             : 
     474             :     /* -------------------------------------------------------------------- */
     475             :     /*      Add dataset mask band                                           */
     476             :     /* -------------------------------------------------------------------- */
     477         247 :     if (poSrcDS->GetRasterCount() != 0 &&
     478         493 :         poSrcDS->GetRasterBand(1) != nullptr &&
     479         246 :         poSrcDS->GetRasterBand(1)->GetMaskFlags() == GMF_PER_DATASET)
     480             :     {
     481           2 :         GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
     482             :         auto poVRTMaskBand = std::make_unique<VRTSourcedRasterBand>(
     483           2 :             poVRTDS.get(), 0, poSrcBand->GetMaskBand()->GetRasterDataType(),
     484           4 :             poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize());
     485           2 :         poVRTMaskBand->AddMaskBandSource(poSrcBand);
     486           2 :         poVRTDS->SetMaskBand(std::move(poVRTMaskBand));
     487             :     }
     488             : 
     489         247 :     if (strcmp(pszFilename, "") != 0)
     490             :     {
     491         163 :         CPLErrorReset();
     492         163 :         poVRTDS->FlushCache(true);
     493         163 :         if (CPLGetLastErrorType() != CE_None)
     494             :         {
     495          11 :             poVRTDS.reset();
     496             :         }
     497             :     }
     498             : 
     499         247 :     if (pfnProgress)
     500         247 :         pfnProgress(1.0, "", pProgressData);
     501             : 
     502         247 :     return poVRTDS.release();
     503             : }
     504             : 
     505             : /************************************************************************/
     506             : /*                          GDALRegister_VRT()                          */
     507             : /************************************************************************/
     508             : 
     509        9323 : void GDALRegister_VRT()
     510             : 
     511             : {
     512        9323 :     auto poDM = GetGDALDriverManager();
     513        9323 :     if (poDM->GetDriverByName("VRT") != nullptr)
     514        7451 :         return;
     515             : 
     516             :     static std::once_flag flag;
     517        1872 :     std::call_once(flag,
     518        1672 :                    []()
     519             :                    {
     520             :                        // First register the pixel functions
     521        1672 :                        GDALRegisterDefaultPixelFunc();
     522             : 
     523             :                        // Register functions for VRTProcessedDataset
     524        1672 :                        GDALVRTRegisterDefaultProcessedDatasetFuncs();
     525        1672 :                    });
     526             : 
     527        1872 :     VRTDriver *poDriver = new VRTDriver();
     528             : 
     529        1872 :     poDriver->SetDescription("VRT");
     530        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_RASTER, "YES");
     531        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_MULTIDIM_RASTER, "YES");
     532        1872 :     poDriver->SetMetadataItem(GDAL_DMD_LONGNAME, "Virtual Raster");
     533        1872 :     poDriver->SetMetadataItem(GDAL_DMD_EXTENSION, "vrt");
     534        1872 :     poDriver->SetMetadataItem(GDAL_DMD_HELPTOPIC, "drivers/raster/vrt.html");
     535        1872 :     poDriver->SetMetadataItem(
     536             :         GDAL_DMD_CREATIONDATATYPES,
     537             :         "Byte Int8 Int16 UInt16 Int32 UInt32 Int64 UInt64 "
     538             :         "Float16 Float32 Float64 "
     539        1872 :         "CInt16 CInt32 CFloat16 CFloat32 CFloat64");
     540        1872 :     poDriver->SetMetadataItem(
     541             :         GDAL_DMD_CREATIONOPTIONLIST,
     542             :         "<CreationOptionList>\n"
     543             :         "   <Option name='SUBCLASS' type='string-select' "
     544             :         "default='VRTDataset'>\n"
     545             :         "       <Value>VRTDataset</Value>\n"
     546             :         "       <Value>VRTWarpedDataset</Value>\n"
     547             :         "   </Option>\n"
     548             :         "   <Option name='BLOCKXSIZE' type='int' description='Block width'/>\n"
     549             :         "   <Option name='BLOCKYSIZE' type='int' description='Block height'/>\n"
     550        1872 :         "</CreationOptionList>\n");
     551             : 
     552        1872 :     auto poGTiffDrv = poDM->GetDriverByName("GTiff");
     553        1872 :     if (poGTiffDrv)
     554             :     {
     555             :         const char *pszGTiffOvrCO =
     556        1872 :             poGTiffDrv->GetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST);
     557        1872 :         if (pszGTiffOvrCO &&
     558        1872 :             STARTS_WITH(pszGTiffOvrCO, "<OverviewCreationOptionList>"))
     559             :         {
     560             :             std::string ocoList =
     561             :                 "<OverviewCreationOptionList>"
     562             :                 "   <Option name='VIRTUAL' type='boolean' "
     563             :                 "default='NO' "
     564             :                 "description='Whether virtual overviews rather than "
     565        3744 :                 "materialized external GeoTIFF .ovr should be created'/>";
     566        1872 :             ocoList += (pszGTiffOvrCO + strlen("<OverviewCreationOptionList>"));
     567        1872 :             poDriver->SetMetadataItem(GDAL_DMD_OVERVIEW_CREATIONOPTIONLIST,
     568        1872 :                                       ocoList.c_str());
     569             :         }
     570             :     }
     571             : 
     572        1872 :     poDriver->SetMetadataItem(
     573             :         GDAL_DMD_MULTIDIM_DATASET_CREATIONOPTIONLIST,
     574             :         "<MultiDimDatasetCreationOptionList>"
     575             :         "   <Option name='GUESS_REGULARLY_SPACED_ARRAYS' type='boolean' "
     576             :         "description='Whether content of 1D-arrays should be read to deduce "
     577             :         "if they are regularly spaced. Can be slow on huge remote datasets' "
     578             :         "default='YES'/>"
     579        1872 :         "</MultiDimDatasetCreationOptionList>");
     580             : 
     581        1872 :     poDriver->SetMetadataItem(
     582             :         GDAL_DMD_MULTIDIM_ARRAY_CREATIONOPTIONLIST,
     583             :         "<MultiDimArrayCreationOptionList>"
     584             :         "   <Option name='BLOCKSIZE' type='int' description='Block size in "
     585             :         "pixels'/>"
     586        1872 :         "</MultiDimArrayCreationOptionList>");
     587             : 
     588        1872 :     poDriver->pfnCreateCopy = VRTCreateCopy;
     589        1872 :     poDriver->pfnCreate = VRTDataset::Create;
     590        1872 :     poDriver->pfnCreateMultiDimensional = VRTDataset::CreateMultiDimensional;
     591             : 
     592             : #ifndef NO_OPEN
     593        1872 :     poDriver->pfnOpen = VRTDataset::Open;
     594        1872 :     poDriver->pfnIdentify = VRTDataset::Identify;
     595        1872 :     poDriver->pfnDelete = VRTDataset::Delete;
     596             : 
     597        1872 :     poDriver->SetMetadataItem(
     598             :         GDAL_DMD_OPENOPTIONLIST,
     599             :         "<OpenOptionList>"
     600             :         "  <Option name='ROOT_PATH' type='string' description='Root path to "
     601             :         "evaluate "
     602             :         "relative paths inside the VRT. Mainly useful for inlined VRT, or "
     603             :         "in-memory "
     604             :         "VRT, where their own directory does not make sense'/>"
     605             :         "<Option name='NUM_THREADS' type='string' description="
     606             :         "'Number of worker threads for reading. Can be set to ALL_CPUS' "
     607             :         "default='ALL_CPUS'/>"
     608        1872 :         "</OpenOptionList>");
     609             : #endif
     610             : 
     611        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_VIRTUALIO, "YES");
     612        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_COORDINATE_EPOCH, "YES");
     613             : 
     614        1872 :     poDriver->SetMetadataItem(GDAL_DCAP_UPDATE, "YES");
     615        1872 :     poDriver->SetMetadataItem(GDAL_DMD_UPDATE_ITEMS,
     616             :                               "GeoTransform SRS GCPs NoData "
     617             :                               "ColorInterpretation "
     618        1872 :                               "DatasetMetadata BandMetadata");
     619             : 
     620        1872 :     const char *pszExpressionDialects = "ExpressionDialects";
     621             : #if defined(GDAL_VRT_ENABLE_MUPARSER) && defined(GDAL_VRT_ENABLE_EXPRTK)
     622        1872 :     poDriver->SetMetadataItem(pszExpressionDialects, "muparser,exprtk");
     623             : #elif defined(GDAL_VRT_ENABLE_MUPARSER)
     624             :     poDriver->SetMetadataItem(pszExpressionDialects, "muparser");
     625             : #elif defined(GDAL_VRT_ENABLE_EXPRTK)
     626             :     poDriver->SetMetadataItem(pszExpressionDialects, "exprtk");
     627             : #else
     628             :     poDriver->SetMetadataItem(pszExpressionDialects, "none");
     629             : #endif
     630             : 
     631             : #ifdef GDAL_VRT_ENABLE_MUPARSER
     632        1872 :     if (gdal::MuParserHasDefineFunUserData())
     633             :     {
     634           0 :         poDriver->SetMetadataItem("MUPARSER_HAS_DEFINE_FUN_USER_DATA", "YES");
     635             :     }
     636             : #endif
     637             : 
     638             : #ifdef GDAL_VRT_ENABLE_RAWRASTERBAND
     639        1872 :     poDriver->SetMetadataItem("GDAL_VRT_ENABLE_RAWRASTERBAND", "YES");
     640             : #endif
     641             : 
     642        1872 :     poDriver->AddSourceParser("SimpleSource", VRTParseCoreSources);
     643        1872 :     poDriver->AddSourceParser("ComplexSource", VRTParseCoreSources);
     644        1872 :     poDriver->AddSourceParser("AveragedSource", VRTParseCoreSources);
     645        1872 :     poDriver->AddSourceParser("NoDataFromMaskSource", VRTParseCoreSources);
     646        1872 :     poDriver->AddSourceParser("KernelFilteredSource", VRTParseFilterSources);
     647        1872 :     poDriver->AddSourceParser("ArraySource", VRTParseArraySource);
     648             : 
     649        1872 :     poDM->RegisterDriver(poDriver);
     650             : }
     651             : 
     652             : /*! @endcond */

Generated by: LCOV version 1.14