1 : /******************************************************************************
2 : * $Id: vrtdataset.cpp 25769 2013-03-19 07:50:17Z antonio $
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 25769 2013-03-19 07:50:17Z antonio $");
36 :
37 : /************************************************************************/
38 : /* VRTDataset() */
39 : /************************************************************************/
40 :
41 1016 : VRTDataset::VRTDataset( int nXSize, int nYSize )
42 :
43 : {
44 1016 : nRasterXSize = nXSize;
45 1016 : nRasterYSize = nYSize;
46 1016 : pszProjection = NULL;
47 :
48 1016 : bNeedsFlush = FALSE;
49 1016 : bWritable = TRUE;
50 :
51 1016 : bGeoTransformSet = FALSE;
52 1016 : adfGeoTransform[0] = 0.0;
53 1016 : adfGeoTransform[1] = 1.0;
54 1016 : adfGeoTransform[2] = 0.0;
55 1016 : adfGeoTransform[3] = 0.0;
56 1016 : adfGeoTransform[4] = 0.0;
57 1016 : adfGeoTransform[5] = 1.0;
58 :
59 1016 : nGCPCount = 0;
60 1016 : pasGCPList = NULL;
61 1016 : pszGCPProjection = CPLStrdup("");
62 :
63 1016 : pszVRTPath = NULL;
64 :
65 1016 : poMaskBand = NULL;
66 :
67 1016 : GDALRegister_VRT();
68 1016 : poDriver = (GDALDriver *) GDALGetDriverByName( "VRT" );
69 :
70 1016 : bCompatibleForDatasetIO = -1;
71 1016 : }
72 :
73 : /************************************************************************/
74 : /* VRTCreate() */
75 : /************************************************************************/
76 :
77 : /**
78 : * @see VRTDataset::VRTDataset()
79 : */
80 :
81 68 : VRTDatasetH CPL_STDCALL VRTCreate(int nXSize, int nYSize)
82 :
83 : {
84 68 : return ( new VRTDataset(nXSize, nYSize) );
85 : }
86 :
87 : /************************************************************************/
88 : /* ~VRTDataset() */
89 : /************************************************************************/
90 :
91 1016 : VRTDataset::~VRTDataset()
92 :
93 : {
94 1016 : FlushCache();
95 1016 : CPLFree( pszProjection );
96 :
97 1016 : CPLFree( pszGCPProjection );
98 1016 : if( nGCPCount > 0 )
99 : {
100 25 : GDALDeinitGCPs( nGCPCount, pasGCPList );
101 25 : CPLFree( pasGCPList );
102 : }
103 1016 : CPLFree( pszVRTPath );
104 :
105 1016 : delete poMaskBand;
106 1016 : }
107 :
108 : /************************************************************************/
109 : /* FlushCache() */
110 : /************************************************************************/
111 :
112 1251 : void VRTDataset::FlushCache()
113 :
114 : {
115 1251 : GDALDataset::FlushCache();
116 :
117 1251 : if( !bNeedsFlush || bWritable == FALSE)
118 523 : return;
119 :
120 728 : bNeedsFlush = FALSE;
121 :
122 : // We don't write to disk if there is no filename. This is a
123 : // memory only dataset.
124 883 : if( strlen(GetDescription()) == 0
125 155 : || EQUALN(GetDescription(),"<VRTDataset",11) )
126 573 : return;
127 :
128 : /* -------------------------------------------------------------------- */
129 : /* Create the output file. */
130 : /* -------------------------------------------------------------------- */
131 : VSILFILE *fpVRT;
132 :
133 155 : fpVRT = VSIFOpenL( GetDescription(), "w" );
134 155 : if( fpVRT == NULL )
135 : {
136 : CPLError( CE_Failure, CPLE_AppDefined,
137 1 : "Failed to write .vrt file in FlushCache()." );
138 1 : return;
139 : }
140 :
141 : /* -------------------------------------------------------------------- */
142 : /* Convert tree to a single block of XML text. */
143 : /* -------------------------------------------------------------------- */
144 154 : char *pszVRTPath = CPLStrdup(CPLGetPath(GetDescription()));
145 154 : CPLXMLNode *psDSTree = SerializeToXML( pszVRTPath );
146 : char *pszXML;
147 :
148 154 : pszXML = CPLSerializeXMLTree( psDSTree );
149 :
150 154 : CPLDestroyXMLNode( psDSTree );
151 :
152 154 : CPLFree( pszVRTPath );
153 :
154 : /* -------------------------------------------------------------------- */
155 : /* Write to disk. */
156 : /* -------------------------------------------------------------------- */
157 154 : VSIFWriteL( pszXML, 1, strlen(pszXML), fpVRT );
158 154 : VSIFCloseL( fpVRT );
159 :
160 154 : CPLFree( pszXML );
161 : }
162 :
163 : /************************************************************************/
164 : /* VRTFlushCache() */
165 : /************************************************************************/
166 :
167 : /**
168 : * @see VRTDataset::FlushCache()
169 : */
170 :
171 0 : void CPL_STDCALL VRTFlushCache( VRTDatasetH hDataset )
172 : {
173 0 : VALIDATE_POINTER0( hDataset, "VRTFlushCache" );
174 :
175 0 : ((VRTDataset *)hDataset)->FlushCache();
176 : }
177 :
178 : /************************************************************************/
179 : /* SerializeToXML() */
180 : /************************************************************************/
181 :
182 162 : CPLXMLNode *VRTDataset::SerializeToXML( const char *pszVRTPath )
183 :
184 : {
185 : /* -------------------------------------------------------------------- */
186 : /* Setup root node and attributes. */
187 : /* -------------------------------------------------------------------- */
188 162 : CPLXMLNode *psDSTree = NULL;
189 162 : CPLXMLNode *psMD = NULL;
190 : char szNumber[128];
191 :
192 162 : psDSTree = CPLCreateXMLNode( NULL, CXT_Element, "VRTDataset" );
193 :
194 162 : sprintf( szNumber, "%d", GetRasterXSize() );
195 162 : CPLSetXMLValue( psDSTree, "#rasterXSize", szNumber );
196 :
197 162 : sprintf( szNumber, "%d", GetRasterYSize() );
198 162 : CPLSetXMLValue( psDSTree, "#rasterYSize", szNumber );
199 :
200 : /* -------------------------------------------------------------------- */
201 : /* SRS */
202 : /* -------------------------------------------------------------------- */
203 162 : if( pszProjection != NULL && strlen(pszProjection) > 0 )
204 143 : CPLSetXMLValue( psDSTree, "SRS", pszProjection );
205 :
206 : /* -------------------------------------------------------------------- */
207 : /* Geotransform. */
208 : /* -------------------------------------------------------------------- */
209 162 : if( bGeoTransformSet )
210 : {
211 : CPLSetXMLValue( psDSTree, "GeoTransform",
212 : CPLSPrintf( "%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
213 : adfGeoTransform[0],
214 : adfGeoTransform[1],
215 : adfGeoTransform[2],
216 : adfGeoTransform[3],
217 : adfGeoTransform[4],
218 149 : adfGeoTransform[5] ) );
219 : }
220 :
221 : /* -------------------------------------------------------------------- */
222 : /* Metadata */
223 : /* -------------------------------------------------------------------- */
224 162 : psMD = oMDMD.Serialize();
225 162 : if( psMD != NULL )
226 109 : CPLAddXMLChild( psDSTree, psMD );
227 :
228 : /* -------------------------------------------------------------------- */
229 : /* GCPs */
230 : /* -------------------------------------------------------------------- */
231 162 : if( nGCPCount > 0 )
232 : {
233 : CPLXMLNode *psGCPList = CPLCreateXMLNode( psDSTree, CXT_Element,
234 2 : "GCPList" );
235 :
236 2 : CPLXMLNode* psLastChild = NULL;
237 :
238 2 : if( pszGCPProjection != NULL && strlen(pszGCPProjection) > 0 )
239 : {
240 1 : CPLSetXMLValue( psGCPList, "#Projection", pszGCPProjection );
241 1 : psLastChild = psGCPList->psChild;
242 : }
243 :
244 8 : for( int iGCP = 0; iGCP < nGCPCount; iGCP++ )
245 : {
246 : CPLXMLNode *psXMLGCP;
247 6 : GDAL_GCP *psGCP = pasGCPList + iGCP;
248 :
249 6 : psXMLGCP = CPLCreateXMLNode( NULL, CXT_Element, "GCP" );
250 :
251 6 : if( psLastChild == NULL )
252 1 : psGCPList->psChild = psXMLGCP;
253 : else
254 5 : psLastChild->psNext = psXMLGCP;
255 6 : psLastChild = psXMLGCP;
256 :
257 6 : CPLSetXMLValue( psXMLGCP, "#Id", psGCP->pszId );
258 :
259 6 : if( psGCP->pszInfo != NULL && strlen(psGCP->pszInfo) > 0 )
260 0 : CPLSetXMLValue( psXMLGCP, "Info", psGCP->pszInfo );
261 :
262 : CPLSetXMLValue( psXMLGCP, "#Pixel",
263 6 : CPLSPrintf( "%.4f", psGCP->dfGCPPixel ) );
264 :
265 : CPLSetXMLValue( psXMLGCP, "#Line",
266 6 : CPLSPrintf( "%.4f", psGCP->dfGCPLine ) );
267 :
268 : CPLSetXMLValue( psXMLGCP, "#X",
269 6 : CPLSPrintf( "%.12E", psGCP->dfGCPX ) );
270 :
271 : CPLSetXMLValue( psXMLGCP, "#Y",
272 6 : CPLSPrintf( "%.12E", psGCP->dfGCPY ) );
273 :
274 6 : if( psGCP->dfGCPZ != 0.0 )
275 : CPLSetXMLValue( psXMLGCP, "#GCPZ",
276 0 : CPLSPrintf( "%.12E", psGCP->dfGCPZ ) );
277 : }
278 : }
279 :
280 : /* -------------------------------------------------------------------- */
281 : /* Serialize bands. */
282 : /* -------------------------------------------------------------------- */
283 400 : for( int iBand = 0; iBand < nBands; iBand++ )
284 : {
285 : CPLXMLNode *psBandTree =
286 238 : ((VRTRasterBand *) papoBands[iBand])->SerializeToXML(pszVRTPath);
287 :
288 238 : if( psBandTree != NULL )
289 238 : CPLAddXMLChild( psDSTree, psBandTree );
290 : }
291 :
292 : /* -------------------------------------------------------------------- */
293 : /* Serialize dataset mask band. */
294 : /* -------------------------------------------------------------------- */
295 162 : if (poMaskBand)
296 : {
297 : CPLXMLNode *psBandTree =
298 6 : poMaskBand->SerializeToXML(pszVRTPath);
299 :
300 6 : if( psBandTree != NULL )
301 : {
302 : CPLXMLNode *psMaskBandElement = CPLCreateXMLNode( psDSTree, CXT_Element,
303 6 : "MaskBand" );
304 6 : CPLAddXMLChild( psMaskBandElement, psBandTree );
305 : }
306 : }
307 :
308 162 : return psDSTree;
309 : }
310 :
311 : /************************************************************************/
312 : /* VRTSerializeToXML() */
313 : /************************************************************************/
314 :
315 : /**
316 : * @see VRTDataset::SerializeToXML()
317 : */
318 :
319 0 : CPLXMLNode * CPL_STDCALL VRTSerializeToXML( VRTDatasetH hDataset,
320 : const char *pszVRTPath )
321 : {
322 0 : VALIDATE_POINTER1( hDataset, "VRTSerializeToXML", NULL );
323 :
324 0 : return ((VRTDataset *)hDataset)->SerializeToXML(pszVRTPath);
325 : }
326 :
327 : /************************************************************************/
328 : /* XMLInit() */
329 : /************************************************************************/
330 :
331 384 : CPLErr VRTDataset::XMLInit( CPLXMLNode *psTree, const char *pszVRTPath )
332 :
333 : {
334 384 : if( pszVRTPath != NULL )
335 370 : this->pszVRTPath = CPLStrdup(pszVRTPath);
336 :
337 : /* -------------------------------------------------------------------- */
338 : /* Check for an SRS node. */
339 : /* -------------------------------------------------------------------- */
340 384 : if( strlen(CPLGetXMLValue(psTree, "SRS", "")) > 0 )
341 : {
342 221 : OGRSpatialReference oSRS;
343 :
344 221 : CPLFree( pszProjection );
345 221 : pszProjection = NULL;
346 :
347 221 : if( oSRS.SetFromUserInput( CPLGetXMLValue(psTree, "SRS", "") )
348 : == OGRERR_NONE )
349 220 : oSRS.exportToWkt( &pszProjection );
350 : }
351 :
352 : /* -------------------------------------------------------------------- */
353 : /* Check for a GeoTransform node. */
354 : /* -------------------------------------------------------------------- */
355 384 : if( strlen(CPLGetXMLValue(psTree, "GeoTransform", "")) > 0 )
356 : {
357 232 : const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
358 : char **papszTokens;
359 :
360 232 : papszTokens = CSLTokenizeStringComplex( pszGT, ",", FALSE, FALSE );
361 232 : if( CSLCount(papszTokens) != 6 )
362 : {
363 : CPLError( CE_Warning, CPLE_AppDefined,
364 0 : "GeoTransform node does not have expected six values.");
365 : }
366 : else
367 : {
368 1624 : for( int iTA = 0; iTA < 6; iTA++ )
369 1392 : adfGeoTransform[iTA] = atof(papszTokens[iTA]);
370 232 : bGeoTransformSet = TRUE;
371 : }
372 :
373 232 : CSLDestroy( papszTokens );
374 : }
375 :
376 : /* -------------------------------------------------------------------- */
377 : /* Check for GCPs. */
378 : /* -------------------------------------------------------------------- */
379 384 : CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
380 :
381 384 : if( psGCPList != NULL )
382 : {
383 : CPLXMLNode *psXMLGCP;
384 21 : OGRSpatialReference oSRS;
385 21 : const char *pszRawProj = CPLGetXMLValue(psGCPList, "Projection", "");
386 :
387 21 : CPLFree( pszGCPProjection );
388 :
389 21 : if( strlen(pszRawProj) > 0
390 : && oSRS.SetFromUserInput( pszRawProj ) == OGRERR_NONE )
391 16 : oSRS.exportToWkt( &pszGCPProjection );
392 : else
393 5 : pszGCPProjection = CPLStrdup("");
394 :
395 : // Count GCPs.
396 21 : int nGCPMax = 0;
397 :
398 122 : for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL;
399 : psXMLGCP = psXMLGCP->psNext )
400 101 : nGCPMax++;
401 :
402 21 : pasGCPList = (GDAL_GCP *) CPLCalloc(sizeof(GDAL_GCP),nGCPMax);
403 :
404 122 : for( psXMLGCP = psGCPList->psChild; psXMLGCP != NULL;
405 : psXMLGCP = psXMLGCP->psNext )
406 : {
407 101 : GDAL_GCP *psGCP = pasGCPList + nGCPCount;
408 :
409 101 : if( !EQUAL(psXMLGCP->pszValue,"GCP") ||
410 : psXMLGCP->eType != CXT_Element )
411 18 : continue;
412 :
413 83 : GDALInitGCPs( 1, psGCP );
414 :
415 83 : CPLFree( psGCP->pszId );
416 83 : psGCP->pszId = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Id",""));
417 :
418 83 : CPLFree( psGCP->pszInfo );
419 83 : psGCP->pszInfo = CPLStrdup(CPLGetXMLValue(psXMLGCP,"Info",""));
420 :
421 83 : psGCP->dfGCPPixel = atof(CPLGetXMLValue(psXMLGCP,"Pixel","0.0"));
422 83 : psGCP->dfGCPLine = atof(CPLGetXMLValue(psXMLGCP,"Line","0.0"));
423 :
424 83 : psGCP->dfGCPX = atof(CPLGetXMLValue(psXMLGCP,"X","0.0"));
425 83 : psGCP->dfGCPY = atof(CPLGetXMLValue(psXMLGCP,"Y","0.0"));
426 83 : psGCP->dfGCPZ = atof(CPLGetXMLValue(psXMLGCP,"Z","0.0"));
427 :
428 83 : nGCPCount++;
429 21 : }
430 : }
431 :
432 : /* -------------------------------------------------------------------- */
433 : /* Apply any dataset level metadata. */
434 : /* -------------------------------------------------------------------- */
435 384 : oMDMD.XMLInit( psTree, TRUE );
436 :
437 : /* -------------------------------------------------------------------- */
438 : /* Create dataset mask band. */
439 : /* -------------------------------------------------------------------- */
440 : CPLXMLNode *psChild;
441 :
442 : /* Parse dataset mask band first */
443 384 : CPLXMLNode* psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
444 384 : if (psMaskBandNode)
445 10 : psChild = psMaskBandNode->psChild;
446 : else
447 374 : psChild = NULL;
448 384 : for( ; psChild != NULL; psChild=psChild->psNext )
449 : {
450 10 : if( psChild->eType == CXT_Element
451 : && EQUAL(psChild->pszValue,"VRTRasterBand") )
452 : {
453 10 : VRTRasterBand *poBand = NULL;
454 : const char *pszSubclass = CPLGetXMLValue( psChild, "subclass",
455 10 : "VRTSourcedRasterBand" );
456 :
457 10 : if( EQUAL(pszSubclass,"VRTSourcedRasterBand") )
458 10 : poBand = new VRTSourcedRasterBand( this, 0 );
459 0 : else if( EQUAL(pszSubclass, "VRTDerivedRasterBand") )
460 0 : poBand = new VRTDerivedRasterBand( this, 0 );
461 0 : else if( EQUAL(pszSubclass, "VRTRawRasterBand") )
462 0 : poBand = new VRTRawRasterBand( this, 0 );
463 0 : else if( EQUAL(pszSubclass, "VRTWarpedRasterBand") )
464 0 : poBand = new VRTWarpedRasterBand( this, 0 );
465 : else
466 : CPLError( CE_Failure, CPLE_AppDefined,
467 : "VRTRasterBand of unrecognised subclass '%s'.",
468 0 : pszSubclass );
469 :
470 20 : if( poBand != NULL
471 10 : && poBand->XMLInit( psChild, pszVRTPath ) == CE_None )
472 : {
473 10 : SetMaskBand(poBand);
474 10 : break;
475 : }
476 : else
477 : {
478 0 : if( poBand )
479 0 : delete poBand;
480 0 : return CE_Failure;
481 : }
482 : }
483 : }
484 :
485 : /* -------------------------------------------------------------------- */
486 : /* Create band information objects. */
487 : /* -------------------------------------------------------------------- */
488 384 : int nBands = 0;
489 2417 : for( psChild=psTree->psChild; psChild != NULL; psChild=psChild->psNext )
490 : {
491 2134 : if( psChild->eType == CXT_Element
492 : && EQUAL(psChild->pszValue,"VRTRasterBand") )
493 : {
494 553 : VRTRasterBand *poBand = NULL;
495 : const char *pszSubclass = CPLGetXMLValue( psChild, "subclass",
496 553 : "VRTSourcedRasterBand" );
497 :
498 553 : if( EQUAL(pszSubclass,"VRTSourcedRasterBand") )
499 460 : poBand = new VRTSourcedRasterBand( this, nBands+1 );
500 93 : else if( EQUAL(pszSubclass, "VRTDerivedRasterBand") )
501 1 : poBand = new VRTDerivedRasterBand( this, nBands+1 );
502 92 : else if( EQUAL(pszSubclass, "VRTRawRasterBand") )
503 11 : poBand = new VRTRawRasterBand( this, nBands+1 );
504 81 : else if( EQUAL(pszSubclass, "VRTWarpedRasterBand") )
505 81 : poBand = new VRTWarpedRasterBand( this, nBands+1 );
506 : else
507 : CPLError( CE_Failure, CPLE_AppDefined,
508 : "VRTRasterBand of unrecognised subclass '%s'.",
509 0 : pszSubclass );
510 :
511 1106 : if( poBand != NULL
512 553 : && poBand->XMLInit( psChild, pszVRTPath ) == CE_None )
513 : {
514 452 : SetBand( ++nBands, poBand );
515 : }
516 : else
517 : {
518 101 : if( poBand )
519 101 : delete poBand;
520 101 : return CE_Failure;
521 : }
522 : }
523 : }
524 :
525 283 : return CE_None;
526 : }
527 :
528 : /************************************************************************/
529 : /* GetGCPCount() */
530 : /************************************************************************/
531 :
532 182 : int VRTDataset::GetGCPCount()
533 :
534 : {
535 182 : return nGCPCount;
536 : }
537 :
538 : /************************************************************************/
539 : /* GetGCPProjection() */
540 : /************************************************************************/
541 :
542 24 : const char *VRTDataset::GetGCPProjection()
543 :
544 : {
545 24 : return pszGCPProjection;
546 : }
547 :
548 : /************************************************************************/
549 : /* GetGCPs() */
550 : /************************************************************************/
551 :
552 28 : const GDAL_GCP *VRTDataset::GetGCPs()
553 :
554 : {
555 28 : return pasGCPList;
556 : }
557 :
558 : /************************************************************************/
559 : /* SetGCPs() */
560 : /************************************************************************/
561 :
562 4 : CPLErr VRTDataset::SetGCPs( int nGCPCount, const GDAL_GCP *pasGCPList,
563 : const char *pszGCPProjection )
564 :
565 : {
566 4 : CPLFree( this->pszGCPProjection );
567 4 : if( this->nGCPCount > 0 )
568 : {
569 0 : GDALDeinitGCPs( this->nGCPCount, this->pasGCPList );
570 0 : CPLFree( this->pasGCPList );
571 : }
572 :
573 4 : this->pszGCPProjection = CPLStrdup(pszGCPProjection);
574 :
575 4 : this->nGCPCount = nGCPCount;
576 :
577 4 : this->pasGCPList = GDALDuplicateGCPs( nGCPCount, pasGCPList );
578 :
579 4 : this->bNeedsFlush = TRUE;
580 :
581 4 : return CE_None;
582 : }
583 :
584 : /************************************************************************/
585 : /* SetProjection() */
586 : /************************************************************************/
587 :
588 211 : CPLErr VRTDataset::SetProjection( const char *pszWKT )
589 :
590 : {
591 211 : CPLFree( pszProjection );
592 211 : pszProjection = NULL;
593 :
594 211 : if( pszWKT != NULL )
595 211 : pszProjection = CPLStrdup(pszWKT);
596 :
597 211 : bNeedsFlush = TRUE;
598 :
599 211 : return CE_None;
600 : }
601 :
602 : /************************************************************************/
603 : /* GetProjectionRef() */
604 : /************************************************************************/
605 :
606 248 : const char *VRTDataset::GetProjectionRef()
607 :
608 : {
609 248 : if( pszProjection == NULL )
610 53 : return "";
611 : else
612 195 : return pszProjection;
613 : }
614 :
615 : /************************************************************************/
616 : /* SetGeoTransform() */
617 : /************************************************************************/
618 :
619 211 : CPLErr VRTDataset::SetGeoTransform( double *padfGeoTransformIn )
620 :
621 : {
622 211 : memcpy( adfGeoTransform, padfGeoTransformIn, sizeof(double) * 6 );
623 211 : bGeoTransformSet = TRUE;
624 :
625 211 : bNeedsFlush = TRUE;
626 :
627 211 : return CE_None;
628 : }
629 :
630 : /************************************************************************/
631 : /* GetGeoTransform() */
632 : /************************************************************************/
633 :
634 286 : CPLErr VRTDataset::GetGeoTransform( double * padfGeoTransform )
635 :
636 : {
637 286 : memcpy( padfGeoTransform, adfGeoTransform, sizeof(double) * 6 );
638 :
639 286 : if( bGeoTransformSet )
640 227 : return CE_None;
641 : else
642 59 : return CE_Failure;
643 : }
644 :
645 : /************************************************************************/
646 : /* SetMetadata() */
647 : /************************************************************************/
648 :
649 152 : CPLErr VRTDataset::SetMetadata( char **papszMetadata,
650 : const char *pszDomain )
651 :
652 : {
653 152 : SetNeedsFlush();
654 :
655 152 : return GDALDataset::SetMetadata( papszMetadata, pszDomain );
656 : }
657 :
658 : /************************************************************************/
659 : /* SetMetadataItem() */
660 : /************************************************************************/
661 :
662 107 : CPLErr VRTDataset::SetMetadataItem( const char *pszName,
663 : const char *pszValue,
664 : const char *pszDomain )
665 :
666 : {
667 107 : SetNeedsFlush();
668 :
669 107 : return GDALDataset::SetMetadataItem( pszName, pszValue, pszDomain );
670 : }
671 :
672 : /************************************************************************/
673 : /* Identify() */
674 : /************************************************************************/
675 :
676 19366 : int VRTDataset::Identify( GDALOpenInfo * poOpenInfo )
677 :
678 : {
679 19366 : if( poOpenInfo->nHeaderBytes > 20
680 : && strstr((const char *)poOpenInfo->pabyHeader,"<VRTDataset") != NULL )
681 391 : return TRUE;
682 :
683 18975 : if( strstr(poOpenInfo->pszFilename,"<VRTDataset") != NULL )
684 15 : return TRUE;
685 :
686 18960 : return FALSE;
687 : }
688 :
689 : /************************************************************************/
690 : /* Open() */
691 : /************************************************************************/
692 :
693 8981 : GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
694 :
695 : {
696 8981 : char *pszVRTPath = NULL;
697 :
698 : /* -------------------------------------------------------------------- */
699 : /* Does this appear to be a virtual dataset definition XML */
700 : /* file? */
701 : /* -------------------------------------------------------------------- */
702 8981 : if( !Identify( poOpenInfo ) )
703 8596 : return NULL;
704 :
705 : /* -------------------------------------------------------------------- */
706 : /* Try to read the whole file into memory. */
707 : /* -------------------------------------------------------------------- */
708 : char *pszXML;
709 :
710 385 : VSILFILE *fp = VSIFOpenL(poOpenInfo->pszFilename, "rb");
711 385 : if( fp != NULL )
712 : {
713 : unsigned int nLength;
714 :
715 371 : VSIFSeekL( fp, 0, SEEK_END );
716 371 : nLength = (int) VSIFTellL( fp );
717 371 : VSIFSeekL( fp, 0, SEEK_SET );
718 :
719 371 : nLength = MAX(0,nLength);
720 371 : pszXML = (char *) VSIMalloc(nLength+1);
721 :
722 371 : if( pszXML == NULL )
723 : {
724 0 : VSIFCloseL(fp);
725 : CPLError( CE_Failure, CPLE_OutOfMemory,
726 : "Failed to allocate %d byte buffer to hold VRT xml file.",
727 0 : nLength );
728 0 : return NULL;
729 : }
730 :
731 371 : if( VSIFReadL( pszXML, 1, nLength, fp ) != nLength )
732 : {
733 0 : VSIFCloseL(fp);
734 0 : CPLFree( pszXML );
735 : CPLError( CE_Failure, CPLE_FileIO,
736 : "Failed to read %d bytes from VRT xml file.",
737 0 : nLength );
738 0 : return NULL;
739 : }
740 :
741 371 : pszXML[nLength] = '\0';
742 :
743 371 : char* pszCurDir = CPLGetCurrentDir();
744 371 : const char *currentVrtFilename = CPLProjectRelativeFilename(pszCurDir, poOpenInfo->pszFilename);
745 371 : CPLFree(pszCurDir);
746 : #if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
747 : VSIStatBuf statBuffer;
748 : char filenameBuffer[2048];
749 :
750 4 : while( true ) {
751 375 : int lstatCode = lstat( currentVrtFilename, &statBuffer );
752 375 : if ( lstatCode == -1 ) {
753 104 : if (errno == ENOENT) {
754 : // The file could be a virtual file, let later checks handle it.
755 104 : break;
756 : } else {
757 0 : VSIFCloseL(fp);
758 0 : CPLFree( pszXML );
759 : CPLError( CE_Failure, CPLE_FileIO,
760 : "Failed to lstat %s: %s",
761 : currentVrtFilename,
762 0 : VSIStrerror(errno) );
763 0 : return NULL;
764 : }
765 : }
766 :
767 271 : if ( !VSI_ISLNK(statBuffer.st_mode) ) {
768 267 : break;
769 : }
770 :
771 4 : int bufferSize = readlink(currentVrtFilename, filenameBuffer, sizeof(filenameBuffer));
772 4 : if (bufferSize != -1) {
773 4 : filenameBuffer[MIN(bufferSize, (int) sizeof(filenameBuffer) - 1)] = 0;
774 : // The filename in filenameBuffer might be a relative path from the linkfile resolve it before looping
775 4 : currentVrtFilename = CPLProjectRelativeFilename(CPLGetDirname(currentVrtFilename), filenameBuffer);
776 : } else {
777 0 : VSIFCloseL(fp);
778 0 : CPLFree( pszXML );
779 : CPLError( CE_Failure, CPLE_FileIO,
780 : "Failed to read filename from symlink %s: %s",
781 : currentVrtFilename,
782 0 : VSIStrerror(errno) );
783 0 : return NULL;
784 : }
785 : }
786 : #endif
787 :
788 371 : pszVRTPath = CPLStrdup(CPLGetPath(currentVrtFilename));
789 :
790 371 : VSIFCloseL(fp);
791 : }
792 : /* -------------------------------------------------------------------- */
793 : /* Or use the filename as the XML input. */
794 : /* -------------------------------------------------------------------- */
795 : else
796 : {
797 14 : pszXML = CPLStrdup( poOpenInfo->pszFilename );
798 : }
799 :
800 : /* -------------------------------------------------------------------- */
801 : /* Turn the XML representation into a VRTDataset. */
802 : /* -------------------------------------------------------------------- */
803 385 : VRTDataset *poDS = (VRTDataset *) OpenXML( pszXML, pszVRTPath, poOpenInfo->eAccess );
804 :
805 385 : if( poDS != NULL )
806 283 : poDS->bNeedsFlush = FALSE;
807 :
808 385 : CPLFree( pszXML );
809 385 : CPLFree( pszVRTPath );
810 :
811 : /* -------------------------------------------------------------------- */
812 : /* Open overviews. */
813 : /* -------------------------------------------------------------------- */
814 385 : if( fp != NULL && poDS != NULL )
815 269 : poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
816 :
817 385 : return poDS;
818 : }
819 :
820 : /************************************************************************/
821 : /* OpenXML() */
822 : /* */
823 : /* Create an open VRTDataset from a supplied XML representation */
824 : /* of the dataset. */
825 : /************************************************************************/
826 :
827 385 : GDALDataset *VRTDataset::OpenXML( const char *pszXML, const char *pszVRTPath,
828 : GDALAccess eAccess)
829 :
830 : {
831 : /* -------------------------------------------------------------------- */
832 : /* Parse the XML. */
833 : /* -------------------------------------------------------------------- */
834 : CPLXMLNode *psTree;
835 :
836 385 : psTree = CPLParseXMLString( pszXML );
837 :
838 385 : if( psTree == NULL )
839 0 : return NULL;
840 :
841 385 : CPLXMLNode *psRoot = CPLGetXMLNode( psTree, "=VRTDataset" );
842 385 : if (psRoot == NULL)
843 : {
844 : CPLError( CE_Failure, CPLE_AppDefined,
845 0 : "Missing VRTDataset element." );
846 0 : CPLDestroyXMLNode( psTree );
847 0 : return NULL;
848 : }
849 :
850 385 : if( CPLGetXMLNode( psRoot, "rasterXSize" ) == NULL
851 : || CPLGetXMLNode( psRoot, "rasterYSize" ) == NULL
852 : || CPLGetXMLNode( psRoot, "VRTRasterBand" ) == NULL )
853 : {
854 : CPLError( CE_Failure, CPLE_AppDefined,
855 : "Missing one of rasterXSize, rasterYSize or bands on"
856 1 : " VRTDataset." );
857 1 : CPLDestroyXMLNode( psTree );
858 1 : return NULL;
859 : }
860 :
861 : /* -------------------------------------------------------------------- */
862 : /* Create the new virtual dataset object. */
863 : /* -------------------------------------------------------------------- */
864 : VRTDataset *poDS;
865 384 : int nXSize = atoi(CPLGetXMLValue(psRoot,"rasterXSize","0"));
866 384 : int nYSize = atoi(CPLGetXMLValue(psRoot,"rasterYSize","0"));
867 :
868 384 : if ( !GDALCheckDatasetDimensions(nXSize, nYSize) )
869 : {
870 0 : CPLDestroyXMLNode( psTree );
871 0 : return NULL;
872 : }
873 :
874 384 : if( strstr(pszXML,"VRTWarpedDataset") != NULL )
875 45 : poDS = new VRTWarpedDataset( nXSize, nYSize );
876 : else
877 : {
878 339 : poDS = new VRTDataset( nXSize, nYSize );
879 339 : poDS->eAccess = eAccess;
880 : }
881 :
882 384 : if( poDS->XMLInit( psRoot, pszVRTPath ) != CE_None )
883 : {
884 101 : delete poDS;
885 101 : poDS = NULL;
886 : }
887 :
888 : /* -------------------------------------------------------------------- */
889 : /* Try to return a regular handle on the file. */
890 : /* -------------------------------------------------------------------- */
891 384 : CPLDestroyXMLNode( psTree );
892 :
893 384 : return poDS;
894 : }
895 :
896 : /************************************************************************/
897 : /* AddBand() */
898 : /************************************************************************/
899 :
900 1913 : CPLErr VRTDataset::AddBand( GDALDataType eType, char **papszOptions )
901 :
902 : {
903 : int i;
904 :
905 1913 : const char *pszSubClass = CSLFetchNameValue(papszOptions, "subclass");
906 :
907 1913 : bNeedsFlush = 1;
908 :
909 : /* ==================================================================== */
910 : /* Handle a new raw band. */
911 : /* ==================================================================== */
912 1913 : if( pszSubClass != NULL && EQUAL(pszSubClass,"VRTRawRasterBand") )
913 : {
914 3 : int nWordDataSize = GDALGetDataTypeSize( eType ) / 8;
915 3 : vsi_l_offset nImageOffset = 0;
916 3 : int nPixelOffset = nWordDataSize;
917 3 : int nLineOffset = nWordDataSize * GetRasterXSize();
918 : const char *pszFilename;
919 3 : const char *pszByteOrder = NULL;
920 3 : int bRelativeToVRT = FALSE;
921 :
922 : /* -------------------------------------------------------------------- */
923 : /* Collect required information. */
924 : /* -------------------------------------------------------------------- */
925 3 : if( CSLFetchNameValue(papszOptions, "ImageOffset") != NULL )
926 2 : nImageOffset = atoi(CSLFetchNameValue(papszOptions, "ImageOffset"));
927 :
928 3 : if( CSLFetchNameValue(papszOptions, "PixelOffset") != NULL )
929 2 : nPixelOffset = atoi(CSLFetchNameValue(papszOptions,"PixelOffset"));
930 :
931 3 : if( CSLFetchNameValue(papszOptions, "LineOffset") != NULL )
932 2 : nLineOffset = atoi(CSLFetchNameValue(papszOptions, "LineOffset"));
933 :
934 3 : if( CSLFetchNameValue(papszOptions, "ByteOrder") != NULL )
935 2 : pszByteOrder = CSLFetchNameValue(papszOptions, "ByteOrder");
936 :
937 3 : if( CSLFetchNameValue(papszOptions, "SourceFilename") != NULL )
938 3 : pszFilename = CSLFetchNameValue(papszOptions, "SourceFilename");
939 : else
940 : {
941 : CPLError( CE_Failure, CPLE_AppDefined,
942 0 : "AddBand() requires a SourceFilename option for VRTRawRasterBands." );
943 0 : return CE_Failure;
944 : }
945 :
946 : bRelativeToVRT =
947 3 : CSLFetchBoolean( papszOptions, "RelativeToVRT", FALSE );
948 :
949 : /* -------------------------------------------------------------------- */
950 : /* Create and initialize the band. */
951 : /* -------------------------------------------------------------------- */
952 : CPLErr eErr;
953 :
954 : VRTRawRasterBand *poBand =
955 6 : new VRTRawRasterBand( this, GetRasterCount() + 1, eType );
956 :
957 : eErr =
958 : poBand->SetRawLink( pszFilename, NULL, bRelativeToVRT,
959 : nImageOffset, nPixelOffset, nLineOffset,
960 3 : pszByteOrder );
961 3 : if( eErr != CE_None )
962 : {
963 0 : delete poBand;
964 0 : return eErr;
965 : }
966 :
967 3 : SetBand( GetRasterCount() + 1, poBand );
968 :
969 3 : return CE_None;
970 : }
971 :
972 : /* ==================================================================== */
973 : /* Handle a new "sourced" band. */
974 : /* ==================================================================== */
975 : else
976 : {
977 : VRTSourcedRasterBand *poBand;
978 :
979 : /* ---- Check for our sourced band 'derived' subclass ---- */
980 1913 : if(pszSubClass != NULL && EQUAL(pszSubClass,"VRTDerivedRasterBand")) {
981 :
982 : /* We'll need a pointer to the subclass in case we need */
983 : /* to set the new band's pixel function below. */
984 : VRTDerivedRasterBand* poDerivedBand;
985 :
986 : poDerivedBand = new VRTDerivedRasterBand
987 : (this, GetRasterCount() + 1, eType,
988 4 : GetRasterXSize(), GetRasterYSize());
989 :
990 : /* Set the pixel function options it provided. */
991 : const char* pszFuncName =
992 4 : CSLFetchNameValue(papszOptions, "PixelFunctionType");
993 4 : if (pszFuncName != NULL)
994 3 : poDerivedBand->SetPixelFunctionName(pszFuncName);
995 :
996 : const char* pszTransferTypeName =
997 4 : CSLFetchNameValue(papszOptions, "SourceTransferType");
998 4 : if (pszTransferTypeName != NULL) {
999 : GDALDataType eTransferType =
1000 2 : GDALGetDataTypeByName(pszTransferTypeName);
1001 2 : if (eTransferType == GDT_Unknown) {
1002 : CPLError( CE_Failure, CPLE_AppDefined,
1003 : "invalid SourceTransferType: \"%s\".",
1004 1 : pszTransferTypeName);
1005 1 : delete poDerivedBand;
1006 1 : return CE_Failure;
1007 : }
1008 1 : poDerivedBand->SetSourceTransferType(eTransferType);
1009 : }
1010 :
1011 : /* We're done with the derived band specific stuff, so */
1012 : /* we can assigned the base class pointer now. */
1013 3 : poBand = poDerivedBand;
1014 : }
1015 : else {
1016 :
1017 : /* ---- Standard sourced band ---- */
1018 : poBand = new VRTSourcedRasterBand
1019 : (this, GetRasterCount() + 1, eType,
1020 1906 : GetRasterXSize(), GetRasterYSize());
1021 : }
1022 :
1023 1909 : SetBand( GetRasterCount() + 1, poBand );
1024 :
1025 1915 : for( i=0; papszOptions != NULL && papszOptions[i] != NULL; i++ )
1026 : {
1027 6 : if( EQUALN(papszOptions[i],"AddFuncSource=", 14) )
1028 : {
1029 0 : VRTImageReadFunc pfnReadFunc = NULL;
1030 0 : void *pCBData = NULL;
1031 0 : double dfNoDataValue = VRT_NODATA_UNSET;
1032 :
1033 0 : char **papszTokens = CSLTokenizeStringComplex( papszOptions[i]+14,
1034 0 : ",", TRUE, FALSE );
1035 :
1036 0 : if( CSLCount(papszTokens) < 1 )
1037 : {
1038 : CPLError( CE_Failure, CPLE_AppDefined,
1039 0 : "AddFuncSource() ... required argument missing." );
1040 : }
1041 :
1042 0 : sscanf( papszTokens[0], "%p", &pfnReadFunc );
1043 0 : if( CSLCount(papszTokens) > 1 )
1044 0 : sscanf( papszTokens[1], "%p", &pCBData );
1045 0 : if( CSLCount(papszTokens) > 2 )
1046 0 : dfNoDataValue = atof( papszTokens[2] );
1047 :
1048 0 : poBand->AddFuncSource( pfnReadFunc, pCBData, dfNoDataValue );
1049 : }
1050 : }
1051 :
1052 1909 : return CE_None;
1053 : }
1054 : }
1055 :
1056 : /************************************************************************/
1057 : /* VRTAddBand() */
1058 : /************************************************************************/
1059 :
1060 : /**
1061 : * @see VRTDataset::VRTAddBand().
1062 : */
1063 :
1064 1600 : int CPL_STDCALL VRTAddBand( VRTDatasetH hDataset, GDALDataType eType,
1065 : char **papszOptions )
1066 :
1067 : {
1068 1600 : VALIDATE_POINTER1( hDataset, "VRTAddBand", 0 );
1069 :
1070 1600 : return ((VRTDataset *) hDataset)->AddBand(eType, papszOptions);
1071 : }
1072 :
1073 : /************************************************************************/
1074 : /* Create() */
1075 : /************************************************************************/
1076 :
1077 : GDALDataset *
1078 133 : VRTDataset::Create( const char * pszName,
1079 : int nXSize, int nYSize, int nBands,
1080 : GDALDataType eType, char ** papszOptions )
1081 :
1082 : {
1083 133 : VRTDataset *poDS = NULL;
1084 133 : int iBand = 0;
1085 :
1086 : (void) papszOptions;
1087 :
1088 133 : if( EQUALN(pszName,"<VRTDataset",11) )
1089 : {
1090 0 : GDALDataset *poDS = OpenXML( pszName, NULL, GA_Update );
1091 0 : if (poDS)
1092 0 : poDS->SetDescription( "<FromXML>" );
1093 0 : return poDS;
1094 : }
1095 : else
1096 : {
1097 : const char *pszSubclass = CSLFetchNameValue( papszOptions,
1098 133 : "SUBCLASS" );
1099 :
1100 262 : if( pszSubclass == NULL || EQUAL(pszSubclass,"VRTDataset") )
1101 129 : poDS = new VRTDataset( nXSize, nYSize );
1102 4 : else if( EQUAL(pszSubclass,"VRTWarpedDataset") )
1103 : {
1104 4 : poDS = new VRTWarpedDataset( nXSize, nYSize );
1105 : }
1106 : else
1107 : {
1108 : CPLError( CE_Failure, CPLE_AppDefined,
1109 : "SUBCLASS=%s not recognised.",
1110 0 : pszSubclass );
1111 0 : return NULL;
1112 : }
1113 133 : poDS->eAccess = GA_Update;
1114 :
1115 133 : poDS->SetDescription( pszName );
1116 :
1117 201 : for( iBand = 0; iBand < nBands; iBand++ )
1118 68 : poDS->AddBand( eType, NULL );
1119 :
1120 133 : poDS->bNeedsFlush = 1;
1121 :
1122 133 : poDS->oOvManager.Initialize( poDS, pszName );
1123 :
1124 133 : return poDS;
1125 : }
1126 : }
1127 :
1128 : /************************************************************************/
1129 : /* GetFileList() */
1130 : /************************************************************************/
1131 :
1132 5 : char** VRTDataset::GetFileList()
1133 : {
1134 5 : char** papszFileList = GDALDataset::GetFileList();
1135 :
1136 5 : int nSize = CSLCount(papszFileList);
1137 5 : int nMaxSize = nSize;
1138 :
1139 : /* Don't need an element desallocator as each string points to an */
1140 : /* element of the papszFileList */
1141 : CPLHashSet* hSetFiles = CPLHashSetNew(CPLHashSetHashStr,
1142 : CPLHashSetEqualStr,
1143 5 : NULL);
1144 :
1145 10 : for( int iBand = 0; iBand < nBands; iBand++ )
1146 : {
1147 15 : ((VRTRasterBand *) papoBands[iBand])->GetFileList(
1148 15 : &papszFileList, &nSize, &nMaxSize, hSetFiles);
1149 : }
1150 :
1151 5 : CPLHashSetDestroy(hSetFiles);
1152 :
1153 5 : return papszFileList;
1154 : }
1155 :
1156 : /************************************************************************/
1157 : /* Delete() */
1158 : /************************************************************************/
1159 :
1160 : /* We implement Delete() to avoid that the default implementation */
1161 : /* in GDALDriver::Delete() destroys the source files listed by GetFileList(),*/
1162 : /* which would be an undesired effect... */
1163 15 : CPLErr VRTDataset::Delete( const char * pszFilename )
1164 : {
1165 15 : GDALDriverH hDriver = GDALIdentifyDriver(pszFilename, NULL);
1166 15 : if (hDriver && EQUAL(GDALGetDriverShortName(hDriver), "VRT"))
1167 : {
1168 15 : if( strstr(pszFilename, "<VRTDataset") == NULL &&
1169 : VSIUnlink( pszFilename ) != 0 )
1170 : {
1171 : CPLError( CE_Failure, CPLE_AppDefined,
1172 : "Deleting %s failed:\n%s",
1173 : pszFilename,
1174 0 : VSIStrerror(errno) );
1175 0 : return CE_Failure;
1176 : }
1177 :
1178 15 : return CE_None;
1179 : }
1180 : else
1181 0 : return CE_Failure;
1182 : }
1183 :
1184 : /************************************************************************/
1185 : /* CreateMaskBand() */
1186 : /************************************************************************/
1187 :
1188 4 : CPLErr VRTDataset::CreateMaskBand( int nFlags )
1189 : {
1190 4 : if (poMaskBand != NULL)
1191 : {
1192 : CPLError(CE_Failure, CPLE_AppDefined,
1193 0 : "This VRT dataset has already a mask band");
1194 0 : return CE_Failure;
1195 : }
1196 :
1197 4 : SetMaskBand(new VRTSourcedRasterBand( this, 0 ));
1198 :
1199 4 : return CE_None;
1200 : }
1201 :
1202 : /************************************************************************/
1203 : /* SetMaskBand() */
1204 : /************************************************************************/
1205 :
1206 15 : void VRTDataset::SetMaskBand(VRTRasterBand* poMaskBand)
1207 : {
1208 15 : delete this->poMaskBand;
1209 15 : this->poMaskBand = poMaskBand;
1210 15 : poMaskBand->SetIsMaskBand();
1211 15 : }
1212 :
1213 : /************************************************************************/
1214 : /* CloseDependentDatasets() */
1215 : /************************************************************************/
1216 :
1217 65 : int VRTDataset::CloseDependentDatasets()
1218 : {
1219 : /* We need to call it before removing the sources, otherwise */
1220 : /* we would remove them from the serizalized VRT */
1221 65 : FlushCache();
1222 :
1223 65 : int bHasDroppedRef = GDALDataset::CloseDependentDatasets();
1224 :
1225 175 : for( int iBand = 0; iBand < nBands; iBand++ )
1226 : {
1227 330 : bHasDroppedRef |= ((VRTRasterBand *) papoBands[iBand])->
1228 330 : CloseDependentDatasets();
1229 : }
1230 65 : return bHasDroppedRef;
1231 : }
1232 :
1233 : /************************************************************************/
1234 : /* CheckCompatibleForDatasetIO() */
1235 : /************************************************************************/
1236 :
1237 : /* We will return TRUE only if all the bands are VRTSourcedRasterBands */
1238 : /* made of identical sources, that are strictly VRTSimpleSource, and that */
1239 : /* the band number of each source is the band number of the VRTSouredRasterBand */
1240 :
1241 587 : int VRTDataset::CheckCompatibleForDatasetIO()
1242 : {
1243 : int iBand;
1244 587 : int nSources = 0;
1245 587 : VRTSource **papoSources = NULL;
1246 2358 : for(iBand = 0; iBand < nBands; iBand++)
1247 : {
1248 1839 : if (!((VRTRasterBand *) papoBands[iBand])->IsSourcedRasterBand())
1249 25 : return FALSE;
1250 :
1251 1814 : VRTSourcedRasterBand* poBand = (VRTSourcedRasterBand* )papoBands[iBand];
1252 :
1253 : /* If there are overviews, let's VRTSourcedRasterBand::IRasterIO() */
1254 : /* do the job */
1255 1814 : if (poBand->GetOverviewCount() != 0)
1256 0 : return FALSE;
1257 :
1258 1814 : if (iBand == 0)
1259 : {
1260 562 : nSources = poBand->nSources;
1261 562 : papoSources = poBand->papoSources;
1262 1911 : for(int iSource = 0; iSource < nSources; iSource++)
1263 : {
1264 1362 : if (!papoSources[iSource]->IsSimpleSource())
1265 0 : return FALSE;
1266 :
1267 1362 : VRTSimpleSource* poSource = (VRTSimpleSource* )papoSources[iSource];
1268 1362 : if (!EQUAL(poSource->GetType(), "SimpleSource"))
1269 9 : return FALSE;
1270 1353 : if (poSource->GetBand() == NULL)
1271 0 : return FALSE;
1272 1353 : if (poSource->GetBand()->GetBand() != iBand + 1)
1273 4 : return FALSE;
1274 : }
1275 : }
1276 1252 : else if (nSources != poBand->nSources)
1277 : {
1278 0 : return FALSE;
1279 : }
1280 : else
1281 : {
1282 4874 : for(int iSource = 0; iSource < nSources; iSource++)
1283 : {
1284 3652 : VRTSimpleSource* poRefSource = (VRTSimpleSource* )papoSources[iSource];
1285 3652 : VRTSimpleSource* poSource = (VRTSimpleSource* )poBand->papoSources[iSource];
1286 3652 : if (!EQUAL(poSource->GetType(), "SimpleSource"))
1287 0 : return FALSE;
1288 3652 : if (!poSource->IsSameExceptBandNumber(poRefSource))
1289 2 : return FALSE;
1290 3650 : if (poSource->GetBand() == NULL)
1291 0 : return FALSE;
1292 3650 : if (poSource->GetBand()->GetBand() != iBand + 1)
1293 28 : return FALSE;
1294 : }
1295 : }
1296 : }
1297 :
1298 519 : return nSources != 0;
1299 : }
1300 :
1301 : /************************************************************************/
1302 : /* GetSingleSimpleSource() */
1303 : /* */
1304 : /* Returns a non-NULL dataset if the VRT is made of a single source */
1305 : /* that is a simple source, in its full extent, and with all of its */
1306 : /* bands. Basically something produced by : */
1307 : /* gdal_translate src dst.vrt -of VRT (-a_srs / -a_ullr) */
1308 : /************************************************************************/
1309 :
1310 83 : GDALDataset* VRTDataset::GetSingleSimpleSource()
1311 : {
1312 83 : if (!CheckCompatibleForDatasetIO())
1313 30 : return NULL;
1314 :
1315 53 : VRTSourcedRasterBand* poVRTBand = (VRTSourcedRasterBand* )papoBands[0];
1316 53 : VRTSimpleSource* poSource = (VRTSimpleSource* )poVRTBand->papoSources[0];
1317 53 : GDALRasterBand* poBand = poSource->GetBand();
1318 53 : if (poBand == NULL)
1319 0 : return NULL;
1320 53 : GDALDataset* poSrcDS = poBand->GetDataset();
1321 53 : if (poSrcDS == NULL)
1322 0 : return NULL;
1323 :
1324 : /* Check that it uses the full source dataset */
1325 : int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1326 : int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1327 : poSource->GetSrcDstWindow( 0, 0,
1328 : poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
1329 : poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
1330 : &nReqXOff, &nReqYOff,
1331 : &nReqXSize, &nReqYSize,
1332 : &nOutXOff, &nOutYOff,
1333 53 : &nOutXSize, &nOutYSize );
1334 :
1335 53 : if (nReqXOff != 0 || nReqYOff != 0 ||
1336 : nReqXSize != poSrcDS->GetRasterXSize() ||
1337 : nReqYSize != poSrcDS->GetRasterYSize())
1338 8 : return NULL;
1339 :
1340 45 : if (nOutXOff != 0 || nOutYOff != 0 ||
1341 : nOutXSize != poSrcDS->GetRasterXSize() ||
1342 : nOutYSize != poSrcDS->GetRasterYSize())
1343 0 : return NULL;
1344 :
1345 45 : return poSrcDS;
1346 : }
1347 :
1348 : /************************************************************************/
1349 : /* IRasterIO() */
1350 : /************************************************************************/
1351 :
1352 696 : CPLErr VRTDataset::IRasterIO( GDALRWFlag eRWFlag,
1353 : int nXOff, int nYOff, int nXSize, int nYSize,
1354 : void * pData, int nBufXSize, int nBufYSize,
1355 : GDALDataType eBufType,
1356 : int nBandCount, int *panBandMap,
1357 : int nPixelSpace, int nLineSpace, int nBandSpace)
1358 : {
1359 696 : if (bCompatibleForDatasetIO < 0)
1360 : {
1361 504 : bCompatibleForDatasetIO = CheckCompatibleForDatasetIO();
1362 : }
1363 696 : if (bCompatibleForDatasetIO && eRWFlag == GF_Read && nBandCount > 1)
1364 : {
1365 224 : for(int iBandIndex=0; iBandIndex<nBandCount; iBandIndex++)
1366 : {
1367 : VRTSourcedRasterBand* poBand =
1368 168 : (VRTSourcedRasterBand*)GetRasterBand(panBandMap[iBandIndex]);
1369 :
1370 : /* Dirty little trick to initialize the buffer without doing */
1371 : /* any real I/O */
1372 168 : int nSavedSources = poBand->nSources;
1373 168 : poBand->nSources = 0;
1374 :
1375 168 : GByte *pabyBandData = ((GByte *) pData) + iBandIndex * nBandSpace;
1376 : poBand->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
1377 : pabyBandData, nBufXSize, nBufYSize,
1378 : eBufType,
1379 168 : nPixelSpace, nLineSpace);
1380 :
1381 168 : poBand->nSources = nSavedSources;
1382 : }
1383 :
1384 56 : CPLErr eErr = CE_None;
1385 : /* Use the last band, because when sources reference a GDALProxyDataset, they */
1386 : /* don't necessary instanciate all underlying rasterbands */
1387 56 : VRTSourcedRasterBand* poBand = (VRTSourcedRasterBand* )papoBands[nBands - 1];
1388 112 : for(int iSource = 0; eErr == CE_None && iSource < poBand->nSources; iSource++)
1389 : {
1390 56 : VRTSimpleSource* poSource = (VRTSimpleSource* )poBand->papoSources[iSource];
1391 : eErr = poSource->DatasetRasterIO( nXOff, nYOff, nXSize, nYSize,
1392 : pData, nBufXSize, nBufYSize,
1393 : eBufType,
1394 : nBandCount, panBandMap,
1395 56 : nPixelSpace, nLineSpace, nBandSpace);
1396 : }
1397 56 : return eErr;
1398 : }
1399 :
1400 : return GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1401 : pData, nBufXSize, nBufYSize,
1402 : eBufType,
1403 : nBandCount, panBandMap,
1404 640 : nPixelSpace, nLineSpace, nBandSpace);
1405 : }
|