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