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