1 : /******************************************************************************
2 : * $Id: vrtdataset.cpp 17852 2009-10-18 11:15:09Z rouault $
3 : *
4 : * Project: Virtual GDAL Datasets
5 : * Purpose: Implementation of VRTDataset
6 : * Author: Frank Warmerdam <warmerdam@pobox.com>
7 : *
8 : ******************************************************************************
9 : * Copyright (c) 2001, 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_string.h"
32 : #include "cpl_minixml.h"
33 : #include "ogr_spatialref.h"
34 :
35 : CPL_CVSID("$Id: vrtdataset.cpp 17852 2009-10-18 11:15:09Z rouault $");
36 :
37 : /************************************************************************/
38 : /* VRTDataset() */
39 : /************************************************************************/
40 :
41 203 : VRTDataset::VRTDataset( int nXSize, int nYSize )
42 :
43 : {
44 203 : nRasterXSize = nXSize;
45 203 : nRasterYSize = nYSize;
46 203 : pszProjection = NULL;
47 :
48 203 : bNeedsFlush = FALSE;
49 203 : bWritable = TRUE;
50 :
51 203 : bGeoTransformSet = FALSE;
52 203 : adfGeoTransform[0] = 0.0;
53 203 : adfGeoTransform[1] = 1.0;
54 203 : adfGeoTransform[2] = 0.0;
55 203 : adfGeoTransform[3] = 0.0;
56 203 : adfGeoTransform[4] = 0.0;
57 203 : adfGeoTransform[5] = 1.0;
58 :
59 203 : nGCPCount = 0;
60 203 : pasGCPList = NULL;
61 203 : pszGCPProjection = CPLStrdup("");
62 :
63 203 : pszVRTPath = NULL;
64 :
65 203 : GDALRegister_VRT();
66 203 : poDriver = (GDALDriver *) GDALGetDriverByName( "VRT" );
67 203 : }
68 :
69 : /************************************************************************/
70 : /* VRTCreate() */
71 : /************************************************************************/
72 :
73 : /**
74 : * @see VRTDataset::VRTDataset()
75 : */
76 :
77 26 : VRTDatasetH CPL_STDCALL VRTCreate(int nXSize, int nYSize)
78 :
79 : {
80 26 : return ( new VRTDataset(nXSize, nYSize) );
81 : }
82 :
83 : /************************************************************************/
84 : /* ~VRTDataset() */
85 : /************************************************************************/
86 :
87 359 : VRTDataset::~VRTDataset()
88 :
89 : {
90 203 : FlushCache();
91 203 : CPLFree( pszProjection );
92 :
93 203 : CPLFree( pszGCPProjection );
94 203 : if( nGCPCount > 0 )
95 : {
96 9 : GDALDeinitGCPs( nGCPCount, pasGCPList );
97 9 : CPLFree( pasGCPList );
98 : }
99 203 : CPLFree( pszVRTPath );
100 359 : }
101 :
102 : /************************************************************************/
103 : /* FlushCache() */
104 : /************************************************************************/
105 :
106 262 : void VRTDataset::FlushCache()
107 :
108 : {
109 262 : GDALDataset::FlushCache();
110 :
111 262 : if( !bNeedsFlush || bWritable == FALSE)
112 190 : return;
113 :
114 72 : bNeedsFlush = FALSE;
115 :
116 : // We don't write to disk if there is no filename. This is a
117 : // memory only dataset.
118 124 : if( strlen(GetDescription()) == 0
119 52 : || EQUALN(GetDescription(),"<VRTDataset",11) )
120 20 : return;
121 :
122 : /* -------------------------------------------------------------------- */
123 : /* Create the output file. */
124 : /* -------------------------------------------------------------------- */
125 : FILE *fpVRT;
126 :
127 52 : fpVRT = VSIFOpenL( GetDescription(), "w" );
128 52 : if( fpVRT == NULL )
129 : {
130 : CPLError( CE_Failure, CPLE_AppDefined,
131 0 : "Failed to write .vrt file in FlushCache()." );
132 0 : return;
133 : }
134 :
135 : /* -------------------------------------------------------------------- */
136 : /* Convert tree to a single block of XML text. */
137 : /* -------------------------------------------------------------------- */
138 52 : char *pszVRTPath = CPLStrdup(CPLGetPath(GetDescription()));
139 52 : CPLXMLNode *psDSTree = SerializeToXML( pszVRTPath );
140 : char *pszXML;
141 :
142 52 : pszXML = CPLSerializeXMLTree( psDSTree );
143 :
144 52 : CPLDestroyXMLNode( psDSTree );
145 :
146 52 : CPLFree( pszVRTPath );
147 :
148 : /* -------------------------------------------------------------------- */
149 : /* Write to disk. */
150 : /* -------------------------------------------------------------------- */
151 52 : VSIFWriteL( pszXML, 1, strlen(pszXML), fpVRT );
152 52 : VSIFCloseL( fpVRT );
153 :
154 52 : CPLFree( pszXML );
155 : }
156 :
157 : /************************************************************************/
158 : /* VRTFlushCache() */
159 : /************************************************************************/
160 :
161 : /**
162 : * @see VRTDataset::FlushCache()
163 : */
164 :
165 0 : void CPL_STDCALL VRTFlushCache( VRTDatasetH hDataset )
166 : {
167 0 : VALIDATE_POINTER0( hDataset, "VRTFlushCache" );
168 :
169 0 : ((VRTDataset *)hDataset)->FlushCache();
170 : }
171 :
172 : /************************************************************************/
173 : /* SerializeToXML() */
174 : /************************************************************************/
175 :
176 54 : CPLXMLNode *VRTDataset::SerializeToXML( const char *pszVRTPath )
177 :
178 : {
179 : /* -------------------------------------------------------------------- */
180 : /* Setup root node and attributes. */
181 : /* -------------------------------------------------------------------- */
182 54 : CPLXMLNode *psDSTree = NULL;
183 54 : CPLXMLNode *psMD = NULL;
184 : char szNumber[128];
185 :
186 54 : psDSTree = CPLCreateXMLNode( NULL, CXT_Element, "VRTDataset" );
187 :
188 54 : sprintf( szNumber, "%d", GetRasterXSize() );
189 54 : CPLSetXMLValue( psDSTree, "#rasterXSize", szNumber );
190 :
191 54 : sprintf( szNumber, "%d", GetRasterYSize() );
192 54 : CPLSetXMLValue( psDSTree, "#rasterYSize", szNumber );
193 :
194 : /* -------------------------------------------------------------------- */
195 : /* SRS */
196 : /* -------------------------------------------------------------------- */
197 54 : if( pszProjection != NULL && strlen(pszProjection) > 0 )
198 32 : CPLSetXMLValue( psDSTree, "SRS", pszProjection );
199 :
200 : /* -------------------------------------------------------------------- */
201 : /* Geotransform. */
202 : /* -------------------------------------------------------------------- */
203 54 : if( bGeoTransformSet )
204 : {
205 : CPLSetXMLValue( psDSTree, "GeoTransform",
206 : CPLSPrintf( "%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
207 : adfGeoTransform[0],
208 : adfGeoTransform[1],
209 : adfGeoTransform[2],
210 : adfGeoTransform[3],
211 : adfGeoTransform[4],
212 35 : adfGeoTransform[5] ) );
213 : }
214 :
215 : /* -------------------------------------------------------------------- */
216 : /* Metadata */
217 : /* -------------------------------------------------------------------- */
218 54 : psMD = oMDMD.Serialize();
219 54 : if( psMD != NULL )
220 20 : CPLAddXMLChild( psDSTree, psMD );
221 :
222 : /* -------------------------------------------------------------------- */
223 : /* GCPs */
224 : /* -------------------------------------------------------------------- */
225 54 : if( nGCPCount > 0 )
226 : {
227 : CPLXMLNode *psGCPList = CPLCreateXMLNode( psDSTree, CXT_Element,
228 0 : "GCPList" );
229 :
230 0 : if( pszGCPProjection != NULL && strlen(pszGCPProjection) > 0 )
231 0 : CPLSetXMLValue( psGCPList, "#Projection", pszGCPProjection );
232 :
233 0 : for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
234 : {
235 : CPLXMLNode *psXMLGCP;
236 0 : GDAL_GCP *psGCP = pasGCPList + iGCP;
237 :
238 0 : psXMLGCP = CPLCreateXMLNode( psGCPList, CXT_Element, "GCP" );
239 :
240 0 : CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );
241 :
242 0 : if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
243 0 : CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );
244 :
245 : CPLSetXMLValue( psXMLGCP, "#Pixel",
246 0 : CPLSPrintf( "%.4f", psGCP->dfGCPPixel ) );
247 :
248 : CPLSetXMLValue( psXMLGCP, "#Line",
249 0 : CPLSPrintf( "%.4f", psGCP->dfGCPLine ) );
250 :
251 : CPLSetXMLValue( psXMLGCP, "#X",
252 0 : CPLSPrintf( "%.12E", psGCP->dfGCPX ) );
253 :
254 : CPLSetXMLValue( psXMLGCP, "#Y",
255 0 : CPLSPrintf( "%.12E", psGCP->dfGCPY ) );
256 :
257 0 : if( psGCP->dfGCPZ != 0.0 )
258 : CPLSetXMLValue( psXMLGCP, "#GCPZ",
259 0 : CPLSPrintf( "%.12E", psGCP->dfGCPZ ) );
260 : }
261 : }
262 :
263 : /* -------------------------------------------------------------------- */
264 : /* Serialize bands. */
265 : /* -------------------------------------------------------------------- */
266 139 : for( int iBand = 0; iBand < nBands; iBand++ )
267 : {
268 : CPLXMLNode *psBandTree =
269 85 : ((VRTRasterBand *) papoBands[iBand])->SerializeToXML(pszVRTPath);
270 :
271 85 : if( psBandTree != NULL )
272 85 : CPLAddXMLChild( psDSTree, psBandTree );
273 : }
274 :
275 54 : return psDSTree;
276 : }
277 :
278 : /************************************************************************/
279 : /* VRTSerializeToXML() */
280 : /************************************************************************/
281 :
282 : /**
283 : * @see VRTDataset::SerializeToXML()
284 : */
285 :
286 0 : CPLXMLNode * CPL_STDCALL VRTSerializeToXML( VRTDatasetH hDataset,
287 : const char *pszVRTPath )
288 : {
289 0 : VALIDATE_POINTER1( hDataset, "VRTSerializeToXML", NULL );
290 :
291 0 : return ((VRTDataset *)hDataset)->SerializeToXML(pszVRTPath);
292 : }
293 :
294 : /************************************************************************/
295 : /* XMLInit() */
296 : /************************************************************************/
297 :
298 126 : CPLErr VRTDataset::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
299 :
300 : {
301 126 : if( pszVRTPath != NULL )
302 126 : this->pszVRTPath = CPLStrdup(pszVRTPath);
303 :
304 : /* -------------------------------------------------------------------- */
305 : /* Check for an SRS node. */
306 : /* -------------------------------------------------------------------- */
307 126 : if( strlen(CPLGetXMLValue(psTree, "SRS", "")) > 0 )
308 : {
309 94 : OGRSpatialReference oSRS;
310 :
311 94 : CPLFree( pszProjection );
312 94 : pszProjection = NULL;
313 :
314 94 : if( oSRS.SetFromUserInput( CPLGetXMLValue(psTree, "SRS", "") )
315 : == OGRERR_NONE )
316 93 : oSRS.exportToWkt( &pszProjection );
317 : }
318 :
319 : /* -------------------------------------------------------------------- */
320 : /* Check for a GeoTransform node. */
321 : /* -------------------------------------------------------------------- */
322 126 : if( strlen(CPLGetXMLValue(psTree, "GeoTransform", "")) > 0 )
323 : {
324 101 : const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
325 : char **papszTokens;
326 :
327 101 : papszTokens = CSLTokenizeStringComplex( pszGT, ",", FALSE, FALSE );
328 101 : if( CSLCount(papszTokens) != 6 )
329 : {
330 : CPLError( CE_Warning, CPLE_AppDefined,
331 0 : "GeoTransform node does not have expected six values.");
332 : }
333 : else
334 : {
335 707 : for( int iTA = 0; iTA < 6; iTA++ )
336 606 : adfGeoTransform[iTA] = atof(papszTokens[iTA]);
337 101 : bGeoTransformSet = TRUE;
338 : }
339 :
340 101 : CSLDestroy( papszTokens );
341 : }
342 :
343 : /* -------------------------------------------------------------------- */
344 : /* Check for GCPs. */
345 : /* -------------------------------------------------------------------- */
346 126 : CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
347 :
348 126 : if( psGCPList != NULL )
349 : {
350 : CPLXMLNode *psXMLGCP;
351 7 : OGRSpatialReference oSRS;
352 7 : const char *pszRawProj = CPLGetXMLValue(psGCPList, "Projection", "");
353 :
354 7 : CPLFree( pszGCPProjection );
355 :
356 7 : if( strlen(pszRawProj) > 0
357 : && oSRS.SetFromUserInput( pszRawProj ) == OGRERR_NONE )
358 7 : oSRS.exportToWkt( &pszGCPProjection );
359 : else
360 0 : pszGCPProjection = CPLStrdup("");
361 :
362 : // Count GCPs.
363 7 : int nGCPMax = 0;
364 :
365 42 : for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL;
366 : psXMLGCP = psXMLGCP->psNext )
367 35 : nGCPMax++;
368 :
369 7 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax);
370 :
371 42 : for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL;
372 : psXMLGCP = psXMLGCP->psNext )
373 : {
374 35 : GDAL_GCP *psGCP = pasGCPList + nGCPCount;
375 :
376 35 : if( !EQUAL(psXMLGCP->pszValue,"GCP") ||
377 : psXMLGCP->eType != CXT_Element )
378 7 : continue;
379 :
380 28 : GDALInitGCPs( 1, psGCP );
381 :
382 28 : CPLFree( psGCP->pszId );
383 28 : psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
384 :
385 28 : CPLFree( psGCP->pszInfo );
386 28 : psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
387 :
388 28 : psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
389 28 : psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
390 :
391 28 : psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
392 28 : psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
393 28 : psGCP->dfGCPZ = atof(CPLGetXMLValue(psXMLGCP,"Z","0.0"));
394 :
395 28 : nGCPCount++;
396 7 : }
397 : }
398 :
399 : /* -------------------------------------------------------------------- */
400 : /* Apply any dataset level metadata. */
401 : /* -------------------------------------------------------------------- */
402 126 : oMDMD.XMLInit( psTree, TRUE );
403 :
404 : /* -------------------------------------------------------------------- */
405 : /* Create band information objects. */
406 : /* -------------------------------------------------------------------- */
407 126 : int nBands = 0;
408 : CPLXMLNode *psChild;
409 :
410 969 : for( psChild=psTree->psChild; psChild != NULL; psChild=psChild->psNext )
411 : {
412 844 : if( psChild->eType == CXT_Element
413 : && EQUAL(psChild->pszValue,"VRTRasterBand") )
414 : {
415 216 : VRTRasterBand *poBand = NULL;
416 : const char *pszSubclass = CPLGetXMLValue( psChild, "subclass",
417 216 : "VRTSourcedRasterBand" );
418 :
419 216 : if( EQUAL(pszSubclass,"VRTSourcedRasterBand") )
420 143 : poBand = new VRTSourcedRasterBand( this, nBands+1 );
421 73 : else if( EQUAL(pszSubclass, "VRTDerivedRasterBand") )
422 0 : poBand = new VRTDerivedRasterBand( this, nBands+1 );
423 73 : else if( EQUAL(pszSubclass, "VRTRawRasterBand") )
424 11 : poBand = new VRTRawRasterBand( this, nBands+1 );
425 62 : else if( EQUAL(pszSubclass, "VRTWarpedRasterBand") )
426 62 : poBand = new VRTWarpedRasterBand( this, nBands+1 );
427 : else
428 : CPLError( CE_Failure, CPLE_AppDefined,
429 : "VRTRasterBand of unrecognised subclass '%s'.",
430 0 : pszSubclass );
431 :
432 432 : if( poBand != NULL
433 216 : && poBand->XMLInit( psChild, pszVRTPath ) == CE_None )
434 : {
435 215 : SetBand( ++nBands, poBand );
436 : }
437 : else
438 : {
439 1 : if( poBand )
440 1 : delete poBand;
441 1 : return CE_Failure;
442 : }
443 : }
444 : }
445 :
446 125 : return CE_None;
447 : }
448 :
449 : /************************************************************************/
450 : /* GetGCPCount() */
451 : /************************************************************************/
452 :
453 85 : int VRTDataset::GetGCPCount()
454 :
455 : {
456 85 : return nGCPCount;
457 : }
458 :
459 : /************************************************************************/
460 : /* GetGCPProjection() */
461 : /************************************************************************/
462 :
463 9 : const char *VRTDataset::GetGCPProjection()
464 :
465 : {
466 9 : return pszGCPProjection;
467 : }
468 :
469 : /************************************************************************/
470 : /* GetGCPs() */
471 : /************************************************************************/
472 :
473 10 : const GDAL_GCP *VRTDataset::GetGCPs()
474 :
475 : {
476 10 : return pasGCPList;
477 : }
478 :
479 : /************************************************************************/
480 : /* SetGCPs() */
481 : /************************************************************************/
482 :
483 2 : CPLErr VRTDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
484 : const char *pszGCPProjection )
485 :
486 : {
487 2 : CPLFree( this->pszGCPProjection );
488 2 : if( this->nGCPCount > 0 )
489 : {
490 0 : GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
491 0 : CPLFree( this->pasGCPList );
492 : }
493 :
494 2 : this->pszGCPProjection = CPLStrdup(pszGCPProjection);
495 :
496 2 : this->nGCPCount = nGCPCount;
497 :
498 2 : this->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
499 :
500 2 : this->bNeedsFlush = TRUE;
501 :
502 2 : return CE_None;
503 : }
504 :
505 : /************************************************************************/
506 : /* SetProjection() */
507 : /************************************************************************/
508 :
509 51 : CPLErr VRTDataset::SetProjection( const char *pszWKT )
510 :
511 : {
512 51 : CPLFree( pszProjection );
513 51 : pszProjection = NULL;
514 :
515 51 : if( pszWKT != NULL )
516 51 : pszProjection = CPLStrdup(pszWKT);
517 :
518 51 : bNeedsFlush = TRUE;
519 :
520 51 : return CE_None;
521 : }
522 :
523 : /************************************************************************/
524 : /* GetProjectionRef() */
525 : /************************************************************************/
526 :
527 102 : const char *VRTDataset::GetProjectionRef()
528 :
529 : {
530 102 : if( pszProjection == NULL )
531 21 : return "";
532 : else
533 81 : return pszProjection;
534 : }
535 :
536 : /************************************************************************/
537 : /* SetGeoTransform() */
538 : /************************************************************************/
539 :
540 52 : CPLErr VRTDataset::SetGeoTransform( double *padfGeoTransformIn )
541 :
542 : {
543 52 : memcpy( adfGeoTransform, padfGeoTransformIn, sizeof(double) * 6 );
544 52 : bGeoTransformSet = TRUE;
545 :
546 52 : bNeedsFlush = TRUE;
547 :
548 52 : return CE_None;
549 : }
550 :
551 : /************************************************************************/
552 : /* GetGeoTransform() */
553 : /************************************************************************/
554 :
555 100 : CPLErr VRTDataset::GetGeoTransform( double * padfGeoTransform )
556 :
557 : {
558 100 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
559 :
560 100 : if( bGeoTransformSet )
561 84 : return CE_None;
562 : else
563 16 : return CE_Failure;
564 : }
565 :
566 : /************************************************************************/
567 : /* SetMetadata() */
568 : /************************************************************************/
569 :
570 33 : CPLErr VRTDataset::SetMetadata( char **papszMetadata,
571 : const char *pszDomain )
572 :
573 : {
574 33 : SetNeedsFlush();
575 :
576 33 : return GDALDataset::SetMetadata( papszMetadata, pszDomain );
577 : }
578 :
579 : /************************************************************************/
580 : /* SetMetadataItem() */
581 : /************************************************************************/
582 :
583 33 : CPLErr VRTDataset::SetMetadataItem( const char *pszName,
584 : const char *pszValue,
585 : const char *pszDomain )
586 :
587 : {
588 33 : SetNeedsFlush();
589 :
590 33 : return GDALDataset::SetMetadataItem( pszName, pszValue, pszDomain );
591 : }
592 :
593 : /************************************************************************/
594 : /* Identify() */
595 : /************************************************************************/
596 :
597 13361 : int VRTDataset::Identify( GDALOpenInfo * poOpenInfo )
598 :
599 : {
600 13361 : if( (poOpenInfo->nHeaderBytes > 20
601 : && EQUALN((const char *)poOpenInfo->pabyHeader,"<VRTDataset",11)) )
602 138 : return TRUE;
603 :
604 13223 : if( EQUALN(poOpenInfo->pszFilename,"<VRTDataset",11) )
605 0 : return TRUE;
606 :
607 13223 : return FALSE;
608 : }
609 :
610 : /************************************************************************/
611 : /* Open() */
612 : /************************************************************************/
613 :
614 5609 : GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
615 :
616 : {
617 5609 : char *pszVRTPath = NULL;
618 :
619 : /* -------------------------------------------------------------------- */
620 : /* Does this appear to be a virtual dataset definition XML */
621 : /* file? */
622 : /* -------------------------------------------------------------------- */
623 5609 : if( !Identify( poOpenInfo ) )
624 5483 : return NULL;
625 :
626 : /* -------------------------------------------------------------------- */
627 : /* Try to read the whole file into memory. */
628 : /* -------------------------------------------------------------------- */
629 : char *pszXML;
630 :
631 126 : FILE *fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
632 126 : if( fp != NULL )
633 : {
634 : unsigned int nLength;
635 :
636 126 : VSIFSeekL( fp, 0, SEEK_END );
637 126 : nLength = (int) VSIFTellL( fp );
638 126 : VSIFSeekL( fp, 0, SEEK_SET );
639 :
640 126 : nLength = MAX(0,nLength);
641 126 : pszXML = (char *) VSIMalloc(nLength+1);
642 :
643 126 : if( pszXML == NULL )
644 : {
645 0 : VSIFCloseL(fp);
646 : CPLError( CE_Failure, CPLE_OutOfMemory,
647 : "Failed to allocate %d byte buffer to hold VRT xml file.",
648 0 : nLength );
649 0 : return NULL;
650 : }
651 :
652 126 : if( VSIFReadL( pszXML, 1, nLength, fp ) != nLength )
653 : {
654 0 : VSIFCloseL(fp);
655 0 : CPLFree( pszXML );
656 : CPLError( CE_Failure, CPLE_FileIO,
657 : "Failed to read %d bytes from VRT xml file.",
658 0 : nLength );
659 0 : return NULL;
660 : }
661 :
662 126 : pszXML[nLength] = '\0';
663 126 : pszVRTPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
664 :
665 126 : VSIFCloseL(fp);
666 : }
667 : /* -------------------------------------------------------------------- */
668 : /* Or use the filename as the XML input. */
669 : /* -------------------------------------------------------------------- */
670 : else
671 : {
672 0 : pszXML = CPLStrdup( poOpenInfo->pszFilename );
673 : }
674 :
675 : /* -------------------------------------------------------------------- */
676 : /* Turn the XML representation into a VRTDataset. */
677 : /* -------------------------------------------------------------------- */
678 126 : VRTDataset *poDS = (VRTDataset *) OpenXML( pszXML, pszVRTPath, poOpenInfo->eAccess );
679 :
680 126 : if( poDS != NULL )
681 125 : poDS->bNeedsFlush = FALSE;
682 :
683 126 : CPLFree( pszXML );
684 126 : CPLFree( pszVRTPath );
685 :
686 : /* -------------------------------------------------------------------- */
687 : /* Open overviews. */
688 : /* -------------------------------------------------------------------- */
689 126 : if( fp != NULL && poDS != NULL )
690 125 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
691 :
692 126 : return poDS;
693 : }
694 :
695 : /************************************************************************/
696 : /* OpenXML() */
697 : /* */
698 : /* Create an open VRTDataset from a supplied XML representation */
699 : /* of the dataset. */
700 : /************************************************************************/
701 :
702 126 : GDALDataset *VRTDataset::OpenXML( const char *pszXML, const char *pszVRTPath,
703 : GDALAccess eAccess)
704 :
705 : {
706 : /* -------------------------------------------------------------------- */
707 : /* Parse the XML. */
708 : /* -------------------------------------------------------------------- */
709 : CPLXMLNode *psTree;
710 :
711 126 : psTree = CPLParseXMLString( pszXML );
712 :
713 126 : if( psTree == NULL )
714 0 : return NULL;
715 :
716 126 : if( CPLGetXMLNode( psTree, "rasterXSize" ) == NULL
717 : || CPLGetXMLNode( psTree, "rasterYSize" ) == NULL
718 : || CPLGetXMLNode( psTree, "VRTRasterBand" ) == NULL )
719 : {
720 : CPLError( CE_Failure, CPLE_AppDefined,
721 : "Missing one of rasterXSize, rasterYSize or bands on"
722 0 : " VRTDataset." );
723 0 : CPLDestroyXMLNode( psTree );
724 0 : return NULL;
725 : }
726 :
727 : /* -------------------------------------------------------------------- */
728 : /* Create the new virtual dataset object. */
729 : /* -------------------------------------------------------------------- */
730 : VRTDataset *poDS;
731 126 : int nXSize = atoi(CPLGetXMLValue(psTree,"rasterXSize","0"));
732 126 : int nYSize = atoi(CPLGetXMLValue(psTree,"rasterYSize","0"));
733 :
734 126 : if ( !GDALCheckDatasetDimensions(nXSize, nYSize) )
735 : {
736 0 : CPLDestroyXMLNode( psTree );
737 0 : return NULL;
738 : }
739 :
740 126 : if( strstr(pszXML,"VRTWarpedDataset") != NULL )
741 34 : poDS = new VRTWarpedDataset( nXSize, nYSize );
742 : else
743 : {
744 92 : poDS = new VRTDataset( nXSize, nYSize );
745 92 : poDS->eAccess = eAccess;
746 : }
747 :
748 126 : if( poDS->XMLInit( psTree, pszVRTPath ) != CE_None )
749 : {
750 1 : delete poDS;
751 1 : poDS = NULL;
752 : }
753 :
754 : /* -------------------------------------------------------------------- */
755 : /* Try to return a regular handle on the file. */
756 : /* -------------------------------------------------------------------- */
757 126 : CPLDestroyXMLNode( psTree );
758 :
759 126 : return poDS;
760 : }
761 :
762 : /************************************************************************/
763 : /* AddBand() */
764 : /************************************************************************/
765 :
766 116 : CPLErr VRTDataset::AddBand( GDALDataType eType, char **papszOptions )
767 :
768 : {
769 : int i;
770 :
771 116 : const char *pszSubClass = CSLFetchNameValue(papszOptions, "subclass");
772 :
773 116 : bNeedsFlush = 1;
774 :
775 : /* ==================================================================== */
776 : /* Handle a new raw band. */
777 : /* ==================================================================== */
778 116 : if( pszSubClass != NULL && EQUAL(pszSubClass,"VRTRawRasterBand") )
779 : {
780 2 : int nWordDataSize = GDALGetDataTypeSize( eType ) / 8;
781 2 : vsi_l_offset nImageOffset = 0;
782 2 : int nPixelOffset = nWordDataSize;
783 2 : int nLineOffset = nWordDataSize * GetRasterXSize();
784 : const char *pszFilename;
785 2 : const char *pszByteOrder = NULL;
786 2 : int bRelativeToVRT = FALSE;
787 :
788 : /* -------------------------------------------------------------------- */
789 : /* Collect required information. */
790 : /* -------------------------------------------------------------------- */
791 2 : if( CSLFetchNameValue(papszOptions, "ImageOffset") != NULL )
792 1 : nImageOffset = atoi(CSLFetchNameValue(papszOptions, "ImageOffset"));
793 :
794 2 : if( CSLFetchNameValue(papszOptions, "PixelOffset") != NULL )
795 1 : nPixelOffset = atoi(CSLFetchNameValue(papszOptions,"PixelOffset"));
796 :
797 2 : if( CSLFetchNameValue(papszOptions, "LineOffset") != NULL )
798 1 : nLineOffset = atoi(CSLFetchNameValue(papszOptions, "LineOffset"));
799 :
800 2 : if( CSLFetchNameValue(papszOptions, "ByteOrder") != NULL )
801 1 : pszByteOrder = CSLFetchNameValue(papszOptions, "ByteOrder");
802 :
803 2 : if( CSLFetchNameValue(papszOptions, "SourceFilename") != NULL )
804 2 : pszFilename = CSLFetchNameValue(papszOptions, "SourceFilename");
805 : else
806 : {
807 : CPLError( CE_Failure, CPLE_AppDefined,
808 0 : "AddBand() requires a SourceFilename option for VRTRawRasterBands." );
809 0 : return CE_Failure;
810 : }
811 :
812 : bRelativeToVRT =
813 2 : CSLFetchBoolean( papszOptions, "RelativeToVRT", FALSE );
814 :
815 : /* -------------------------------------------------------------------- */
816 : /* Create and initialize the band. */
817 : /* -------------------------------------------------------------------- */
818 : CPLErr eErr;
819 :
820 : VRTRawRasterBand *poBand =
821 4 : new VRTRawRasterBand( this, GetRasterCount() + 1, eType );
822 :
823 : eErr =
824 : poBand->SetRawLink( pszFilename, NULL, FALSE,
825 : nImageOffset, nPixelOffset, nLineOffset,
826 2 : pszByteOrder );
827 2 : if( eErr != CE_None )
828 : {
829 0 : delete poBand;
830 0 : return eErr;
831 : }
832 :
833 2 : SetBand( GetRasterCount() + 1, poBand );
834 :
835 2 : return CE_None;
836 : }
837 :
838 : /* ==================================================================== */
839 : /* Handle a new "sourced" band. */
840 : /* ==================================================================== */
841 : else
842 : {
843 : VRTSourcedRasterBand *poBand;
844 :
845 : /* ---- Check for our sourced band 'derived' subclass ---- */
846 114 : if(pszSubClass != NULL && EQUAL(pszSubClass,"VRTDerivedRasterBand")) {
847 : poBand = new VRTDerivedRasterBand
848 : (this, GetRasterCount() + 1, eType,
849 0 : GetRasterXSize(), GetRasterYSize());
850 : }
851 : else {
852 :
853 : /* ---- Standard sourced band ---- */
854 : poBand = new VRTSourcedRasterBand
855 : (this, GetRasterCount() + 1, eType,
856 114 : GetRasterXSize(), GetRasterYSize());
857 : }
858 :
859 114 : SetBand( GetRasterCount() + 1, poBand );
860 :
861 114 : for( i=0; papszOptions != NULL && papszOptions[i] != NULL; i++ )
862 : {
863 0 : if( EQUALN(papszOptions[i],"AddFuncSource=", 14) )
864 : {
865 0 : VRTImageReadFunc pfnReadFunc = NULL;
866 0 : void *pCBData = NULL;
867 0 : double dfNoDataValue = VRT_NODATA_UNSET;
868 :
869 0 : char **papszTokens = CSLTokenizeStringComplex( papszOptions[i]+14,
870 0 : ",", TRUE, FALSE );
871 :
872 0 : if( CSLCount(papszTokens) < 1 )
873 : {
874 : CPLError( CE_Failure, CPLE_AppDefined,
875 0 : "AddFuncSource() ... required argument missing." );
876 : }
877 :
878 0 : sscanf( papszTokens[0], "%p", &pfnReadFunc );
879 0 : if( CSLCount(papszTokens) > 1 )
880 0 : sscanf( papszTokens[1], "%p", &pCBData );
881 0 : if( CSLCount(papszTokens) > 2 )
882 0 : dfNoDataValue = atof( papszTokens[2] );
883 :
884 0 : poBand->AddFuncSource( pfnReadFunc, pCBData, dfNoDataValue );
885 : }
886 : }
887 :
888 114 : return CE_None;
889 : }
890 : }
891 :
892 : /************************************************************************/
893 : /* VRTAddBand() */
894 : /************************************************************************/
895 :
896 : /**
897 : * @see VRTDataset::VRTAddBand().
898 : */
899 :
900 0 : int CPL_STDCALL VRTAddBand( VRTDatasetH hDataset, GDALDataType eType,
901 : char **papszOptions )
902 :
903 : {
904 0 : VALIDATE_POINTER1( hDataset, "VRTAddBand", 0 );
905 :
906 0 : return ((VRTDataset *) hDataset)->AddBand(eType, papszOptions);
907 : }
908 :
909 : /************************************************************************/
910 : /* Create() */
911 : /************************************************************************/
912 :
913 : GDALDataset *
914 40 : VRTDataset::Create( const char * pszName,
915 : int nXSize, int nYSize, int nBands,
916 : GDALDataType eType, char ** papszOptions )
917 :
918 : {
919 40 : VRTDataset *poDS = NULL;
920 40 : int iBand = 0;
921 :
922 : (void) papszOptions;
923 :
924 40 : if( EQUALN(pszName,"<VRTDataset",11) )
925 : {
926 0 : GDALDataset *poDS = OpenXML( pszName, NULL, GA_Update );
927 0 : poDS->SetDescription( "<FromXML>" );
928 0 : return poDS;
929 : }
930 : else
931 : {
932 : const char *pszSubclass = CSLFetchNameValue( papszOptions,
933 40 : "SUBCLASS" );
934 :
935 78 : if( pszSubclass == NULL || EQUAL(pszSubclass,"VRTDataset") )
936 38 : poDS = new VRTDataset( nXSize, nYSize );
937 2 : else if( EQUAL(pszSubclass,"VRTWarpedDataset") )
938 : {
939 2 : poDS = new VRTWarpedDataset( nXSize, nYSize );
940 : }
941 : else
942 : {
943 : CPLError( CE_Failure, CPLE_AppDefined,
944 : "SUBCLASS=%s not recognised.",
945 0 : pszSubclass );
946 0 : return NULL;
947 : }
948 40 : poDS->eAccess = GA_Update;
949 :
950 40 : poDS->SetDescription( pszName );
951 :
952 69 : for( iBand = 0; iBand < nBands; iBand++ )
953 29 : poDS->AddBand( eType, NULL );
954 :
955 40 : poDS->bNeedsFlush = 1;
956 :
957 40 : poDS->oOvManager.Initialize( poDS, pszName );
958 :
959 40 : return poDS;
960 : }
961 : }
962 :
963 : /************************************************************************/
964 : /* GetFileList() */
965 : /************************************************************************/
966 :
967 0 : char** VRTDataset::GetFileList()
968 : {
969 0 : char** papszFileList = GDALDataset::GetFileList();
970 :
971 0 : int nSize = CSLCount(papszFileList);
972 0 : int nMaxSize = nSize;
973 :
974 : /* Don't need an element desallocator as each string points to an */
975 : /* element of the papszFileList */
976 : CPLHashSet* hSetFiles = CPLHashSetNew(CPLHashSetHashStr,
977 : CPLHashSetEqualStr,
978 0 : NULL);
979 :
980 0 : for( int iBand = 0; iBand < nBands; iBand++ )
981 : {
982 0 : ((VRTRasterBand *) papoBands[iBand])->GetFileList(
983 0 : &papszFileList, &nSize, &nMaxSize, hSetFiles);
984 : }
985 :
986 0 : CPLHashSetDestroy(hSetFiles);
987 :
988 0 : return papszFileList;
989 : }
990 :
991 : /************************************************************************/
992 : /* Delete() */
993 : /************************************************************************/
994 :
995 : /* We implement Delete() to avoid that the default implementation */
996 : /* in GDALDriver::Delete() destroys the source files listed by GetFileList(),*/
997 : /* which would be an undesired effect... */
998 6 : CPLErr VRTDataset::Delete( const char * pszFilename )
999 : {
1000 6 : GDALDriverH hDriver = GDALIdentifyDriver(pszFilename, NULL);
1001 6 : if (hDriver && EQUAL(GDALGetDriverShortName(hDriver), "VRT"))
1002 : {
1003 6 : if( VSIUnlink( pszFilename ) != 0 )
1004 : {
1005 : CPLError( CE_Failure, CPLE_AppDefined,
1006 : "Deleting %s failed:\n%s",
1007 : pszFilename,
1008 0 : VSIStrerror(errno) );
1009 0 : return CE_Failure;
1010 : }
1011 :
1012 6 : return CE_None;
1013 : }
1014 : else
1015 0 : return CE_Failure;
1016 : }
|