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