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