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