1 : /******************************************************************************
2 : * $Id: vrtdriver.cpp 17852 2009-10-18 11:15:09Z rouault $
3 : *
4 : * Project: Virtual GDAL Datasets
5 : * Purpose: Implementation of VRTDriver
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2003, Frank Warmerdam <warmerdam@pobox.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 : #include "cpl_minixml.h"
32 : #include "cpl_string.h"
33 :
34 : CPL_CVSID("$Id: vrtdriver.cpp 17852 2009-10-18 11:15:09Z rouault $");
35 :
36 : /************************************************************************/
37 : /* VRTDriver() */
38 : /************************************************************************/
39 :
40 392 : VRTDriver::VRTDriver()
41 :
42 : {
43 392 : papszSourceParsers = NULL;
44 392 : }
45 :
46 : /************************************************************************/
47 : /* ~VRTDriver() */
48 : /************************************************************************/
49 :
50 380 : VRTDriver::~VRTDriver()
51 :
52 : {
53 380 : CSLDestroy( papszSourceParsers );
54 380 : }
55 :
56 : /************************************************************************/
57 : /* GetMetadata() */
58 : /************************************************************************/
59 :
60 17 : char **VRTDriver::GetMetadata( const char *pszDomain )
61 :
62 : {
63 17 : if( pszDomain && EQUAL(pszDomain,"SourceParsers") )
64 0 : return papszSourceParsers;
65 : else
66 17 : return GDALDriver::GetMetadata( pszDomain );
67 : }
68 :
69 : /************************************************************************/
70 : /* SetMetadata() */
71 : /************************************************************************/
72 :
73 0 : CPLErr VRTDriver::SetMetadata( char **papszMetadata, const char *pszDomain )
74 :
75 : {
76 0 : if( pszDomain && EQUAL(pszDomain,"SourceParsers") )
77 : {
78 0 : CSLDestroy( papszSourceParsers );
79 0 : papszSourceParsers = CSLDuplicate( papszMetadata );
80 0 : return CE_None;
81 : }
82 : else
83 0 : return GDALDriver::SetMetadata( papszMetadata, pszDomain );
84 : }
85 :
86 : /************************************************************************/
87 : /* AddSourceParser() */
88 : /************************************************************************/
89 :
90 : void VRTDriver::AddSourceParser( const char *pszElementName,
91 1568 : VRTSourceParser pfnParser )
92 :
93 : {
94 : char szPtrValue[128];
95 :
96 1568 : sprintf( szPtrValue, "%p", pfnParser );
97 : papszSourceParsers = CSLSetNameValue( papszSourceParsers,
98 1568 : pszElementName, szPtrValue );
99 1568 : }
100 :
101 : /************************************************************************/
102 : /* ParseSource() */
103 : /************************************************************************/
104 :
105 423 : VRTSource *VRTDriver::ParseSource( CPLXMLNode *psSrc, const char *pszVRTPath )
106 :
107 : {
108 : const char *pszParserFunc;
109 :
110 423 : if( psSrc == NULL || psSrc->eType != CXT_Element )
111 : {
112 : CPLError( CE_Failure, CPLE_AppDefined,
113 0 : "Corrupt or empty VRT source XML document." );
114 0 : return NULL;
115 : }
116 :
117 423 : pszParserFunc = CSLFetchNameValue( papszSourceParsers, psSrc->pszValue );
118 423 : if( pszParserFunc == NULL )
119 221 : return NULL;
120 :
121 202 : VRTSourceParser pfnParser = NULL;
122 :
123 202 : sscanf( pszParserFunc, "%p", &pfnParser );
124 :
125 202 : if( pfnParser == NULL )
126 0 : return NULL;
127 : else
128 202 : return pfnParser( psSrc, pszVRTPath );
129 : }
130 :
131 : /************************************************************************/
132 : /* VRTCreateCopy() */
133 : /************************************************************************/
134 :
135 : static GDALDataset *
136 : VRTCreateCopy( const char * pszFilename, GDALDataset *poSrcDS,
137 : int bStrict, char ** papszOptions,
138 21 : GDALProgressFunc pfnProgress, void * pProgressData )
139 :
140 : {
141 21 : VRTDataset *poVRTDS = NULL;
142 :
143 : (void) bStrict;
144 : (void) papszOptions;
145 :
146 21 : CPLAssert( NULL != poSrcDS );
147 :
148 : /* -------------------------------------------------------------------- */
149 : /* If the source dataset is a virtual dataset then just write */
150 : /* it to disk as a special case to avoid extra layers of */
151 : /* indirection. */
152 : /* -------------------------------------------------------------------- */
153 21 : if( EQUAL(poSrcDS->GetDriver()->GetDescription(),"VRT") )
154 : {
155 :
156 : /* -------------------------------------------------------------------- */
157 : /* Convert tree to a single block of XML text. */
158 : /* -------------------------------------------------------------------- */
159 2 : char *pszVRTPath = CPLStrdup(CPLGetPath(pszFilename));
160 2 : CPLXMLNode *psDSTree = ((VRTDataset *) poSrcDS)->SerializeToXML( pszVRTPath );
161 :
162 2 : char *pszXML = CPLSerializeXMLTree( psDSTree );
163 :
164 2 : CPLDestroyXMLNode( psDSTree );
165 :
166 2 : CPLFree( pszVRTPath );
167 :
168 : /* -------------------------------------------------------------------- */
169 : /* Write to disk. */
170 : /* -------------------------------------------------------------------- */
171 2 : GDALDataset* pCopyDS = NULL;
172 :
173 2 : if( 0 != strlen( pszFilename ) )
174 : {
175 2 : FILE *fpVRT = NULL;
176 :
177 2 : fpVRT = VSIFOpen( pszFilename, "w" );
178 2 : CPLAssert( NULL != fpVRT );
179 :
180 2 : VSIFWrite( pszXML, 1, strlen(pszXML), fpVRT );
181 2 : VSIFClose( fpVRT );
182 :
183 2 : pCopyDS = (GDALDataset *) GDALOpen( pszFilename, GA_Update );
184 : }
185 : else
186 : {
187 : /* No destination file is given, so pass serialized XML directly. */
188 :
189 0 : pCopyDS = (GDALDataset *) GDALOpen( pszXML, GA_Update );
190 : }
191 :
192 2 : CPLFree( pszXML );
193 :
194 2 : return pCopyDS;
195 : }
196 :
197 : /* -------------------------------------------------------------------- */
198 : /* Create the virtual dataset. */
199 : /* -------------------------------------------------------------------- */
200 : poVRTDS = (VRTDataset *)
201 : VRTDataset::Create( pszFilename,
202 : poSrcDS->GetRasterXSize(),
203 : poSrcDS->GetRasterYSize(),
204 19 : 0, GDT_Byte, NULL );
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Do we have a geotransform? */
208 : /* -------------------------------------------------------------------- */
209 : double adfGeoTransform[6];
210 :
211 19 : if( poSrcDS->GetGeoTransform( adfGeoTransform ) == CE_None )
212 : {
213 19 : poVRTDS->SetGeoTransform( adfGeoTransform );
214 : }
215 :
216 : /* -------------------------------------------------------------------- */
217 : /* Copy projection */
218 : /* -------------------------------------------------------------------- */
219 19 : poVRTDS->SetProjection( poSrcDS->GetProjectionRef() );
220 :
221 : /* -------------------------------------------------------------------- */
222 : /* Emit dataset level metadata. */
223 : /* -------------------------------------------------------------------- */
224 19 : poVRTDS->SetMetadata( poSrcDS->GetMetadata() );
225 :
226 : /* -------------------------------------------------------------------- */
227 : /* Copy any special domains that should be transportable. */
228 : /* -------------------------------------------------------------------- */
229 : char **papszMD;
230 :
231 19 : papszMD = poSrcDS->GetMetadata( "RPC" );
232 19 : if( papszMD )
233 0 : poVRTDS->SetMetadata( papszMD, "RPC" );
234 :
235 19 : papszMD = poSrcDS->GetMetadata( "IMD" );
236 19 : if( papszMD )
237 0 : poVRTDS->SetMetadata( papszMD, "IMD" );
238 :
239 : /* -------------------------------------------------------------------- */
240 : /* GCPs */
241 : /* -------------------------------------------------------------------- */
242 19 : if( poSrcDS->GetGCPCount() > 0 )
243 : {
244 : poVRTDS->SetGCPs( poSrcDS->GetGCPCount(),
245 : poSrcDS->GetGCPs(),
246 0 : poSrcDS->GetGCPProjection() );
247 : }
248 :
249 : /* -------------------------------------------------------------------- */
250 : /* Loop over all the bands. */
251 : /* -------------------------------------------------------------------- */
252 49 : for( int iBand = 0; iBand < poSrcDS->GetRasterCount(); iBand++ )
253 : {
254 30 : GDALRasterBand *poSrcBand = poSrcDS->GetRasterBand( iBand+1 );
255 :
256 : /* -------------------------------------------------------------------- */
257 : /* Create the band with the appropriate band type. */
258 : /* -------------------------------------------------------------------- */
259 30 : poVRTDS->AddBand( poSrcBand->GetRasterDataType(), NULL );
260 :
261 : VRTSourcedRasterBand *poVRTBand =
262 30 : (VRTSourcedRasterBand *) poVRTDS->GetRasterBand( iBand+1 );
263 :
264 : /* -------------------------------------------------------------------- */
265 : /* Setup source mapping. */
266 : /* -------------------------------------------------------------------- */
267 30 : poVRTBand->AddSimpleSource( poSrcBand );
268 :
269 : /* -------------------------------------------------------------------- */
270 : /* Emit various band level metadata. */
271 : /* -------------------------------------------------------------------- */
272 30 : poVRTBand->CopyCommonInfoFrom( poSrcBand );
273 : }
274 :
275 19 : poVRTDS->FlushCache();
276 :
277 19 : return poVRTDS;
278 : }
279 :
280 : /************************************************************************/
281 : /* GDALRegister_VRT() */
282 : /************************************************************************/
283 :
284 683 : void GDALRegister_VRT()
285 :
286 : {
287 : VRTDriver *poDriver;
288 :
289 683 : if( GDALGetDriverByName( "VRT" ) == NULL )
290 : {
291 392 : poDriver = new VRTDriver();
292 :
293 392 : poDriver->SetDescription( "VRT" );
294 : poDriver->SetMetadataItem( GDAL_DMD_LONGNAME,
295 392 : "Virtual Raster" );
296 392 : poDriver->SetMetadataItem( GDAL_DMD_EXTENSION, "vrt" );
297 392 : poDriver->SetMetadataItem( GDAL_DMD_HELPTOPIC, "gdal_vrttut.html" );
298 : poDriver->SetMetadataItem( GDAL_DMD_CREATIONDATATYPES,
299 392 : "Byte Int16 UInt16 Int32 UInt32 Float32 Float64 CInt16 CInt32 CFloat32 CFloat64" );
300 :
301 392 : poDriver->pfnOpen = VRTDataset::Open;
302 392 : poDriver->pfnCreateCopy = VRTCreateCopy;
303 392 : poDriver->pfnCreate = VRTDataset::Create;
304 392 : poDriver->pfnIdentify = VRTDataset::Identify;
305 392 : poDriver->pfnDelete = VRTDataset::Delete;
306 :
307 : poDriver->AddSourceParser( "SimpleSource",
308 392 : VRTParseCoreSources );
309 : poDriver->AddSourceParser( "ComplexSource",
310 392 : VRTParseCoreSources );
311 : poDriver->AddSourceParser( "AveragedSource",
312 392 : VRTParseCoreSources );
313 :
314 : poDriver->AddSourceParser( "KernelFilteredSource",
315 392 : VRTParseFilterSources );
316 :
317 392 : GetGDALDriverManager()->RegisterDriver( poDriver );
318 : }
319 683 : }
320 :
|