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