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