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