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 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "vrtdataset.h"
31
32 #include "cpl_minixml.h"
33 #include "cpl_string.h"
34 #include "gdal_alg_priv.h"
35 #include "gdal_frmts.h"
36
37 CPL_CVSID("$Id: vrtdriver.cpp d83599e9d76b3a12acd9d519fa8bd21c7f9be44b 2020-11-13 17:05:11 +0100 Even Rouault $")
38
39 /*! @cond Doxygen_Suppress */
40
41 /************************************************************************/
42 /* VRTDriver() */
43 /************************************************************************/
44
45 VRTDriver::VRTDriver() :
46 papszSourceParsers(nullptr)
47 {
48 #if 0
49 pDeserializerData = GDALRegisterTransformDeserializer(
50 "WarpedOverviewTransformer",
51 VRTWarpedOverviewTransform,
52 VRTDeserializeWarpedOverviewTransformer );
53 #endif
54 }
55
56 /************************************************************************/
57 /* ~VRTDriver() */
58 /************************************************************************/
59
60 VRTDriver::~VRTDriver()
61
62 {
63 CSLDestroy( papszSourceParsers );
64 VRTDerivedRasterBand::Cleanup();
65 #if 0
66 if( pDeserializerData )
67 {
68 GDALUnregisterTransformDeserializer( pDeserializerData );
69 }
70 #endif
71 }
72
73 /************************************************************************/
74 /* GetMetadataDomainList() */
75 /************************************************************************/
76
77 char **VRTDriver::GetMetadataDomainList()
setTargetFile($file)78 {
79 return BuildMetadataDomainList( GDALDriver::GetMetadataDomainList(),
80 TRUE,
81 "SourceParsers", nullptr );
82 }
83
84 /************************************************************************/
85 /* GetMetadata() */
86 /************************************************************************/
87
88 char **VRTDriver::GetMetadata( const char *pszDomain )
89
90 {
91 if( pszDomain && EQUAL(pszDomain,"SourceParsers") )
92 return papszSourceParsers;
93
94 return GDALDriver::GetMetadata( pszDomain );
95 }
96
97 /************************************************************************/
98 /* SetMetadata() */
setDisallowedPropertyPrefixes($prefixes)99 /************************************************************************/
100
101 CPLErr VRTDriver::SetMetadata( char **papszMetadata, const char *pszDomain )
102
103 {
104 if( pszDomain && EQUAL(pszDomain,"SourceParsers") )
105 {
106 CSLDestroy( papszSourceParsers );
107 papszSourceParsers = CSLDuplicate( papszMetadata );
108 return CE_None;
109 }
110
111 return GDALDriver::SetMetadata( papszMetadata, pszDomain );
112 }
113
114 /************************************************************************/
115 /* AddSourceParser() */
116 /************************************************************************/
117
118 void VRTDriver::AddSourceParser( const char *pszElementName,
119 VRTSourceParser pfnParser )
120
121 {
122 char szPtrValue[128] = { '\0' };
123 void* ptr;
124 CPL_STATIC_ASSERT(sizeof(pfnParser) == sizeof(void*));
125 memcpy(&ptr, &pfnParser, sizeof(void*));
126 int nRet = CPLPrintPointer( szPtrValue,
127 ptr,
128 sizeof(szPtrValue) );
129 szPtrValue[nRet] = 0;
130
isDisallowedPropery($propertyName)131 papszSourceParsers = CSLSetNameValue( papszSourceParsers,
132 pszElementName, szPtrValue );
133 }
134
135 /************************************************************************/
136 /* ParseSource() */
137 /************************************************************************/
138
139 VRTSource *VRTDriver::ParseSource( CPLXMLNode *psSrc, const char *pszVRTPath,
140 void* pUniqueHandle,
141 std::map<CPLString, GDALDataset*>& oMapSharedSources )
142
143 {
144
145 if( psSrc == nullptr || psSrc->eType != CXT_Element )
146 {
147 CPLError( CE_Failure, CPLE_AppDefined,
148 "Corrupt or empty VRT source XML document." );
149 return nullptr;
150 }
151
152 const char *pszParserFunc
153 = CSLFetchNameValue( papszSourceParsers, psSrc->pszValue );
154 if( pszParserFunc == nullptr )
155 return nullptr;
156
157 VRTSourceParser pfnParser;
158 CPL_STATIC_ASSERT(sizeof(pfnParser) == sizeof(void*));
159 void* ptr = CPLScanPointer( pszParserFunc,
160 static_cast<int>(strlen(pszParserFunc)) );
161 memcpy(&pfnParser, &ptr, sizeof(void*));
162
163 if( pfnParser == nullptr )
164 return nullptr;
165
166 return pfnParser( psSrc, pszVRTPath, pUniqueHandle, oMapSharedSources );
167 }
168
169 /************************************************************************/
170 /* VRTCreateCopy() */
171 /************************************************************************/
172
173 static GDALDataset *
174 VRTCreateCopy( const char * pszFilename,
175 GDALDataset *poSrcDS,
176 int /* bStrict */,
177 char ** /* papszOptions */,
178 GDALProgressFunc /* pfnProgress */,
179 void * /* pProgressData */ )
180 {
181 CPLAssert( nullptr != poSrcDS );
182
183 /* -------------------------------------------------------------------- */
184 /* If the source dataset is a virtual dataset then just write */
185 /* it to disk as a special case to avoid extra layers of */
186 /* indirection. */
187 /* -------------------------------------------------------------------- */
188 if( poSrcDS->GetDriver() != nullptr &&
189 EQUAL(poSrcDS->GetDriver()->GetDescription(),"VRT") )
190 {
191
192 /* -------------------------------------------------------------------- */
193 /* Convert tree to a single block of XML text. */
194 /* -------------------------------------------------------------------- */
195 char *pszVRTPath = CPLStrdup(CPLGetPath(pszFilename));
196 static_cast<VRTDataset *>(
197 poSrcDS )->UnsetPreservedRelativeFilenames();
198 CPLXMLNode *psDSTree = static_cast<VRTDataset *>(
199 poSrcDS )->SerializeToXML( pszVRTPath );
200
201 char *pszXML = CPLSerializeXMLTree( psDSTree );
202
203 CPLDestroyXMLNode( psDSTree );
204
205 CPLFree( pszVRTPath );
206
207 /* -------------------------------------------------------------------- */
208 /* Write to disk. */
209 /* -------------------------------------------------------------------- */
210 GDALDataset* pCopyDS = nullptr;
211
212 if( 0 != strlen( pszFilename ) )
213 {
214 VSILFILE *fpVRT = VSIFOpenL( pszFilename, "wb" );
215 if( fpVRT == nullptr )
216 {
217 CPLError(CE_Failure, CPLE_AppDefined,
218 "Cannot create %s", pszFilename);
219 CPLFree( pszXML );
220 return nullptr;
221 }
222
223 bool bRet = VSIFWriteL( pszXML, strlen(pszXML), 1, fpVRT ) > 0;
224 if( VSIFCloseL( fpVRT ) != 0 )
225 bRet = false;
226
227 if( bRet )
228 pCopyDS = GDALDataset::Open( pszFilename,
229 GDAL_OF_RASTER | GDAL_OF_MULTIDIM_RASTER | GDAL_OF_UPDATE);
230 }
231 else
232 {
233 /* No destination file is given, so pass serialized XML directly. */
234 pCopyDS = GDALDataset::Open( pszXML,
235 GDAL_OF_RASTER | GDAL_OF_MULTIDIM_RASTER | GDAL_OF_UPDATE);
236 }
237
238 CPLFree( pszXML );
239
240 return pCopyDS;
241 }
242
243 /* -------------------------------------------------------------------- */
244 /* Multidimensional raster ? */
245 /* -------------------------------------------------------------------- */
246 auto poSrcGroup = poSrcDS->GetRootGroup();
247 if( poSrcGroup != nullptr )
248 {
249 auto poDstDS = std::unique_ptr<GDALDataset>(
250 VRTDataset::CreateMultiDimensional(pszFilename,
251 nullptr,
252 nullptr));
253 if( !poDstDS )
254 return nullptr;
255 auto poDstGroup = poDstDS->GetRootGroup();
256 if( !poDstGroup )
257 return nullptr;
258 if( GDALDriver::DefaultCreateCopyMultiDimensional(poSrcDS,
259 poDstDS.get(),
260 false,
261 nullptr,
262 nullptr,
263 nullptr) != CE_None )
264 return nullptr;
265 return poDstDS.release();
266 }
267
268 /* -------------------------------------------------------------------- */
269 /* Create the virtual dataset. */
270 /* -------------------------------------------------------------------- */
271 VRTDataset *poVRTDS = static_cast<VRTDataset *>(
272 VRTDataset::Create( pszFilename,
273 poSrcDS->GetRasterXSize(),
274 poSrcDS->GetRasterYSize(),
275 0, GDT_Byte, nullptr ) );
276 if( poVRTDS == nullptr )
277 return nullptr;
278
279 /* -------------------------------------------------------------------- */
280 /* Do we have a geotransform? */
281 /* -------------------------------------------------------------------- */
282 double adfGeoTransform[6] = { 0.0 };
283
284 if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
285 {
286 poVRTDS->SetGeoTransform( adfGeoTransform );
287 }
288
289 /* -------------------------------------------------------------------- */
290 /* Copy projection */
291 /* -------------------------------------------------------------------- */
292 poVRTDS->SetSpatialRef( poSrcDS->GetSpatialRef() );
293
294 /* -------------------------------------------------------------------- */
295 /* Emit dataset level metadata. */
296 /* -------------------------------------------------------------------- */
297 poVRTDS->SetMetadata( poSrcDS->GetMetadata() );
298
299 /* -------------------------------------------------------------------- */
300 /* Copy any special domains that should be transportable. */
301 /* -------------------------------------------------------------------- */
302 char **papszMD = poSrcDS->GetMetadata( "RPC" );
303 if( papszMD )
304 poVRTDS->SetMetadata( papszMD, "RPC" );
305
306 papszMD = poSrcDS->GetMetadata( "IMD" );
307 if( papszMD )
308 poVRTDS->SetMetadata( papszMD, "IMD" );
309
310 papszMD = poSrcDS->GetMetadata( "GEOLOCATION" );
311 if( papszMD )
312 poVRTDS->SetMetadata( papszMD, "GEOLOCATION" );
313
314 {
315 const char* pszInterleave = poSrcDS->GetMetadataItem("INTERLEAVE", "IMAGE_STRUCTURE");
316 if (pszInterleave)
317 {
318 poVRTDS->SetMetadataItem("INTERLEAVE", pszInterleave, "IMAGE_STRUCTURE");
319 }
320 }
321 {
322 const char* pszCompression = poSrcDS->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE");
323 if( pszCompression )
324 {
325 poVRTDS->SetMetadataItem("COMPRESSION", pszCompression, "IMAGE_STRUCTURE");
326 }
327 }
328
329 /* -------------------------------------------------------------------- */
330 /* GCPs */
331 /* -------------------------------------------------------------------- */
332 if( poSrcDS->GetGCPCount() > 0 )
333 {
334 poVRTDS->SetGCPs( poSrcDS->GetGCPCount(),
335 poSrcDS->GetGCPs(),
336 poSrcDS->GetGCPSpatialRef() );
337 }
338
339 /* -------------------------------------------------------------------- */
340 /* Loop over all the bands. */
341 /* -------------------------------------------------------------------- */
342 for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
343 {
344 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
345
346 /* -------------------------------------------------------------------- */
347 /* Create the band with the appropriate band type. */
348 /* -------------------------------------------------------------------- */
349 CPLStringList aosAddBandOptions;
350 int nSrcBlockXSize, nSrcBlockYSize;
351 poSrcBand->GetBlockSize(&nSrcBlockXSize, &nSrcBlockYSize);
352 aosAddBandOptions.SetNameValue("BLOCKXSIZE", CPLSPrintf("%d", nSrcBlockXSize));
353 aosAddBandOptions.SetNameValue("BLOCKYSIZE", CPLSPrintf("%d", nSrcBlockYSize));
354 poVRTDS->AddBand( poSrcBand->GetRasterDataType(), aosAddBandOptions );
355
356 VRTSourcedRasterBand *poVRTBand
357 = static_cast<VRTSourcedRasterBand *>(
358 poVRTDS->GetRasterBand( iBand+1 ) );
359
360 /* -------------------------------------------------------------------- */
361 /* Setup source mapping. */
362 /* -------------------------------------------------------------------- */
363 poVRTBand->AddSimpleSource( poSrcBand );
364
365 /* -------------------------------------------------------------------- */
366 /* Emit various band level metadata. */
367 /* -------------------------------------------------------------------- */
368 poVRTBand->CopyCommonInfoFrom( poSrcBand );
369
370 const char* pszCompression = poSrcBand->GetMetadataItem("COMPRESSION", "IMAGE_STRUCTURE");
371 if( pszCompression )
372 {
373 poVRTBand->SetMetadataItem("COMPRESSION", pszCompression, "IMAGE_STRUCTURE");
374 }
375
376 /* -------------------------------------------------------------------- */
377 /* Add specific mask band. */
378 /* -------------------------------------------------------------------- */
379 if( (poSrcBand->GetMaskFlags()
380 & (GMF_PER_DATASET | GMF_ALL_VALID | GMF_NODATA)) == 0)
381 {
382 VRTSourcedRasterBand* poVRTMaskBand = new VRTSourcedRasterBand(
383 poVRTDS, 0,
384 poSrcBand->GetMaskBand()->GetRasterDataType(),
385 poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize());
386 poVRTMaskBand->AddMaskBandSource( poSrcBand );
387 poVRTBand->SetMaskBand( poVRTMaskBand );
388 }
389 }
390
391 /* -------------------------------------------------------------------- */
392 /* Add dataset mask band */
393 /* -------------------------------------------------------------------- */
394 if( poSrcDS->GetRasterCount() != 0 &&
395 poSrcDS->GetRasterBand(1) != nullptr &&
396 poSrcDS->GetRasterBand(1)->GetMaskFlags() == GMF_PER_DATASET )
397 {
398 GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand(1);
399 VRTSourcedRasterBand* poVRTMaskBand = new VRTSourcedRasterBand(
400 poVRTDS, 0,
401 poSrcBand->GetMaskBand()->GetRasterDataType(),
402 poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize() );
403 poVRTMaskBand->AddMaskBandSource( poSrcBand );
404 poVRTDS->SetMaskBand( poVRTMaskBand );
405 }
406
407 CPLErrorReset();
408 poVRTDS->FlushCache();
409 if( CPLGetLastErrorType() != CE_None )
410 {
411 delete poVRTDS;
412 poVRTDS = nullptr;
413 }
414
415 return poVRTDS;
416 }
417
418 /************************************************************************/
419 /* GDALRegister_VRT() */
420 /************************************************************************/
421
422 void GDALRegister_VRT()
423
424 {
425 if( GDALGetDriverByName( "VRT" ) != nullptr )
426 return;
427
428 // First register the pixel functions
429 GDALRegisterDefaultPixelFunc();
430
431 VRTDriver *poDriver = new VRTDriver();
432
433 poDriver->SetDescription( "VRT" );
434 poDriver->SetMetadataItem( GDAL_DCAP_RASTER, "YES" );
435 poDriver->SetMetadataItem( GDAL_DCAP_MULTIDIM_RASTER, "YES" );
436 poDriver->SetMetadataItem( GDAL_DMD_LONGNAME, "Virtual Raster" );
437 poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "vrt" );
438 poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "drivers/raster/vrt.html" );
439 poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
440 "Byte Int16 UInt16 Int32 UInt32 Float32 Float64 "
441 "CInt16 CInt32 CFloat32 CFloat64" );
442
443 poDriver->pfnOpen = VRTDataset::Open;
444 poDriver->pfnCreateCopy = VRTCreateCopy;
445 poDriver->pfnCreate = VRTDataset::Create;
446 poDriver->pfnCreateMultiDimensional = VRTDataset::CreateMultiDimensional;
447 poDriver->pfnIdentify = VRTDataset::Identify;
448 poDriver->pfnDelete = VRTDataset::Delete;
449
450 poDriver->SetMetadataItem( GDAL_DMD_OPENOPTIONLIST,
451 "<OpenOptionList>"
452 " <Option name='ROOT_PATH' type='string' description='Root path to evaluate "
453 "relative paths inside the VRT. Mainly useful for inlined VRT, or in-memory "
454 "VRT, where their own directory does not make sense'/>"
455 "</OpenOptionList>" );
456
457 poDriver->SetMetadataItem( GDAL_DCAP_VIRTUALIO, "YES" );
458
459 poDriver->AddSourceParser( "SimpleSource", VRTParseCoreSources );
460 poDriver->AddSourceParser( "ComplexSource", VRTParseCoreSources );
461 poDriver->AddSourceParser( "AveragedSource", VRTParseCoreSources );
462 poDriver->AddSourceParser( "KernelFilteredSource", VRTParseFilterSources );
463
464 GetGDALDriverManager()->RegisterDriver( poDriver );
465 }
466
467 /*! @endcond */
468