1 /******************************************************************************
2 *
3 * Project: Virtual GDAL Datasets
4 * Purpose: Implementation of VRTDataset
5 * Author: Frank Warmerdam <warmerdam@pobox.com>
6 *
7 ******************************************************************************
8 * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
9 * Copyright (c) 2007-2014, Even Rouault <even dot rouault at spatialys.com>
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a
12 * copy of this software and associated documentation files (the "Software"),
13 * to deal in the Software without restriction, including without limitation
14 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
15 * and/or sell copies of the Software, and to permit persons to whom the
16 * Software is furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included
19 * in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
24 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 * DEALINGS IN THE SOFTWARE.
28 ****************************************************************************/
29
30 #include "vrtdataset.h"
31
32 #include "cpl_minixml.h"
33 #include "cpl_string.h"
34 #include "gdal_frmts.h"
35 #include "ogr_spatialref.h"
36 #include "gdal_utils.h"
37
38 #include <algorithm>
39 #include <typeinfo>
40 #include "gdal_proxy.h"
41
42 /*! @cond Doxygen_Suppress */
43
44 CPL_CVSID("$Id: vrtdataset.cpp 9c76f54836aeca57bc60bfd7ef7f75664317bb15 2020-11-13 17:04:02 +0100 Even Rouault $")
45
46 #define VRT_PROTOCOL_PREFIX "vrt://"
47
48 /************************************************************************/
49 /* VRTDataset() */
50 /************************************************************************/
51
VRTDataset(int nXSize,int nYSize)52 VRTDataset::VRTDataset( int nXSize, int nYSize )
53 {
54 nRasterXSize = nXSize;
55 nRasterYSize = nYSize;
56
57 m_adfGeoTransform[0] = 0.0;
58 m_adfGeoTransform[1] = 1.0;
59 m_adfGeoTransform[2] = 0.0;
60 m_adfGeoTransform[3] = 0.0;
61 m_adfGeoTransform[4] = 0.0;
62 m_adfGeoTransform[5] = 1.0;
63
64 GDALRegister_VRT();
65
66 poDriver = static_cast<GDALDriver *>( GDALGetDriverByName( "VRT" ) );
67 }
68
69 /*! @endcond */
70
71 /************************************************************************/
72 /* VRTCreate() */
73 /************************************************************************/
74
75 /**
76 * @see VRTDataset::VRTDataset()
77 */
78
VRTCreate(int nXSize,int nYSize)79 VRTDatasetH CPL_STDCALL VRTCreate(int nXSize, int nYSize)
80
81 {
82 auto poDS = new VRTDataset(nXSize, nYSize);
83 poDS->eAccess = GA_Update;
84 return poDS;
85 }
86
87 /*! @cond Doxygen_Suppress */
88
89 /************************************************************************/
90 /* ~VRTDataset() */
91 /************************************************************************/
92
~VRTDataset()93 VRTDataset::~VRTDataset()
94
95 {
96 VRTDataset::FlushCache();
97 if( m_poSRS )
98 m_poSRS->Release();
99 if( m_poGCP_SRS )
100 m_poGCP_SRS->Release();
101 if( m_nGCPCount > 0 )
102 {
103 GDALDeinitGCPs( m_nGCPCount, m_pasGCPList );
104 CPLFree( m_pasGCPList );
105 }
106 CPLFree( m_pszVRTPath );
107
108 delete m_poMaskBand;
109
110 for(size_t i=0;i<m_apoOverviews.size();i++)
111 delete m_apoOverviews[i];
112 for(size_t i=0;i<m_apoOverviewsBak.size();i++)
113 delete m_apoOverviewsBak[i];
114 CSLDestroy( m_papszXMLVRTMetadata );
115 }
116
117 /************************************************************************/
118 /* FlushCache() */
119 /************************************************************************/
120
FlushCache()121 void VRTDataset::FlushCache()
122
123 {
124 if( m_poRootGroup )
125 m_poRootGroup->Serialize();
126 else
127 VRTFlushCacheStruct<VRTDataset>::FlushCache(*this);
128 }
129
130 /************************************************************************/
131 /* FlushCache() */
132 /************************************************************************/
133
FlushCache()134 void VRTWarpedDataset::FlushCache()
135
136 {
137 VRTFlushCacheStruct<VRTWarpedDataset>::FlushCache(*this);
138 }
139
140 /************************************************************************/
141 /* FlushCache() */
142 /************************************************************************/
143
FlushCache()144 void VRTPansharpenedDataset::FlushCache()
145
146 {
147 VRTFlushCacheStruct<VRTPansharpenedDataset>::FlushCache(*this);
148 }
149
150 /************************************************************************/
151 /* FlushCache() */
152 /************************************************************************/
153
FlushCache(T & obj)154 template<class T> void VRTFlushCacheStruct<T>::FlushCache(T& obj)
155 {
156 obj.GDALDataset::FlushCache();
157
158 if( !obj.m_bNeedsFlush || !obj.m_bWritable )
159 return;
160
161 obj.m_bNeedsFlush = false;
162
163 // We don't write to disk if there is no filename. This is a
164 // memory only dataset.
165 if( strlen(obj.GetDescription()) == 0
166 || STARTS_WITH_CI(obj.GetDescription(), "<VRTDataset") )
167 return;
168
169 /* -------------------------------------------------------------------- */
170 /* Create the output file. */
171 /* -------------------------------------------------------------------- */
172 VSILFILE *fpVRT = VSIFOpenL( obj.GetDescription(), "w" );
173 if( fpVRT == nullptr )
174 {
175 CPLError( CE_Failure, CPLE_AppDefined,
176 "Failed to write .vrt file in FlushCache()." );
177 return;
178 }
179
180 /* -------------------------------------------------------------------- */
181 /* Convert tree to a single block of XML text. */
182 /* -------------------------------------------------------------------- */
183 const char* pszDescription = obj.GetDescription();
184 char *l_pszVRTPath = CPLStrdup(
185 pszDescription[0] && !STARTS_WITH(pszDescription, "<VRTDataset") ?
186 CPLGetPath(pszDescription): "" );
187 CPLXMLNode *psDSTree = obj.T::SerializeToXML( l_pszVRTPath );
188 char *pszXML = CPLSerializeXMLTree( psDSTree );
189
190 CPLDestroyXMLNode( psDSTree );
191
192 CPLFree( l_pszVRTPath );
193 bool bOK = true;
194 if( pszXML )
195 {
196 /* ------------------------------------------------------------------ */
197 /* Write to disk. */
198 /* ------------------------------------------------------------------ */
199 bOK &=
200 VSIFWriteL( pszXML, 1, strlen(pszXML), fpVRT )
201 == strlen(pszXML);
202 CPLFree(pszXML);
203 }
204 if( VSIFCloseL( fpVRT ) != 0 )
205 bOK = false;
206 if( !bOK )
207 {
208 CPLError( CE_Failure, CPLE_AppDefined,
209 "Failed to write .vrt file in FlushCache()." );
210 return;
211 }
212 }
213
214 /************************************************************************/
215 /* GetMetadata() */
216 /************************************************************************/
217
GetMetadata(const char * pszDomain)218 char** VRTDataset::GetMetadata( const char *pszDomain )
219 {
220 if( pszDomain != nullptr && EQUAL(pszDomain, "xml:VRT") )
221 {
222 /* ------------------------------------------------------------------ */
223 /* Convert tree to a single block of XML text. */
224 /* ------------------------------------------------------------------ */
225 const char* pszDescription = GetDescription();
226 char *l_pszVRTPath = CPLStrdup(
227 pszDescription[0] && !STARTS_WITH(pszDescription, "<VRTDataset") ?
228 CPLGetPath(pszDescription): "" );
229 CPLXMLNode *psDSTree = SerializeToXML( l_pszVRTPath );
230 char *pszXML = CPLSerializeXMLTree( psDSTree );
231
232 CPLDestroyXMLNode( psDSTree );
233
234 CPLFree( l_pszVRTPath );
235
236 CSLDestroy(m_papszXMLVRTMetadata);
237 m_papszXMLVRTMetadata = static_cast<char**>(CPLMalloc(2 * sizeof(char*)));
238 m_papszXMLVRTMetadata[0] = pszXML;
239 m_papszXMLVRTMetadata[1] = nullptr;
240 return m_papszXMLVRTMetadata;
241 }
242
243 return GDALDataset::GetMetadata(pszDomain);
244 }
245
246 /*! @endcond */
247
248 /************************************************************************/
249 /* VRTFlushCache() */
250 /************************************************************************/
251
252 /**
253 * @see VRTDataset::FlushCache()
254 */
255
VRTFlushCache(VRTDatasetH hDataset)256 void CPL_STDCALL VRTFlushCache( VRTDatasetH hDataset )
257 {
258 VALIDATE_POINTER0( hDataset, "VRTFlushCache" );
259
260 static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))->FlushCache();
261 }
262
263 /*! @cond Doxygen_Suppress */
264
265 /************************************************************************/
266 /* SerializeToXML() */
267 /************************************************************************/
268
SerializeToXML(const char * pszVRTPathIn)269 CPLXMLNode *VRTDataset::SerializeToXML( const char *pszVRTPathIn )
270
271 {
272 if( m_poRootGroup )
273 return m_poRootGroup->SerializeToXML(pszVRTPathIn);
274
275 /* -------------------------------------------------------------------- */
276 /* Setup root node and attributes. */
277 /* -------------------------------------------------------------------- */
278 CPLXMLNode *psDSTree = CPLCreateXMLNode( nullptr, CXT_Element, "VRTDataset" );
279
280 char szNumber[128] = { '\0' };
281 snprintf( szNumber, sizeof(szNumber), "%d", GetRasterXSize() );
282 CPLSetXMLValue( psDSTree, "#rasterXSize", szNumber );
283
284 snprintf( szNumber, sizeof(szNumber), "%d", GetRasterYSize() );
285 CPLSetXMLValue( psDSTree, "#rasterYSize", szNumber );
286
287 /* -------------------------------------------------------------------- */
288 /* SRS */
289 /* -------------------------------------------------------------------- */
290 if( m_poSRS && !m_poSRS->IsEmpty() )
291 {
292 char* pszWKT = nullptr;
293 m_poSRS->exportToWkt(&pszWKT);
294 CPLXMLNode* psSRSNode = CPLCreateXMLElementAndValue( psDSTree, "SRS", pszWKT );
295 CPLFree(pszWKT);
296 const auto& mapping = m_poSRS->GetDataAxisToSRSAxisMapping();
297 CPLString osMapping;
298 for( size_t i = 0; i < mapping.size(); ++i )
299 {
300 if( !osMapping.empty() )
301 osMapping += ",";
302 osMapping += CPLSPrintf("%d", mapping[i]);
303 }
304 CPLAddXMLAttributeAndValue(psSRSNode, "dataAxisToSRSAxisMapping",
305 osMapping.c_str());
306 }
307
308 /* -------------------------------------------------------------------- */
309 /* Geotransform. */
310 /* -------------------------------------------------------------------- */
311 if( m_bGeoTransformSet )
312 {
313 CPLSetXMLValue(
314 psDSTree, "GeoTransform",
315 CPLSPrintf( "%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
316 m_adfGeoTransform[0],
317 m_adfGeoTransform[1],
318 m_adfGeoTransform[2],
319 m_adfGeoTransform[3],
320 m_adfGeoTransform[4],
321 m_adfGeoTransform[5] ) );
322 }
323
324 /* -------------------------------------------------------------------- */
325 /* Metadata */
326 /* -------------------------------------------------------------------- */
327 CPLXMLNode *psMD = oMDMD.Serialize();
328 if( psMD != nullptr )
329 {
330 CPLAddXMLChild( psDSTree, psMD );
331 }
332
333 /* -------------------------------------------------------------------- */
334 /* GCPs */
335 /* -------------------------------------------------------------------- */
336 if( m_nGCPCount > 0 )
337 {
338 GDALSerializeGCPListToXML( psDSTree,
339 m_pasGCPList,
340 m_nGCPCount,
341 m_poGCP_SRS );
342 }
343
344 /* -------------------------------------------------------------------- */
345 /* Serialize bands. */
346 /* -------------------------------------------------------------------- */
347 CPLXMLNode* psLastChild = psDSTree->psChild;
348 for( ; psLastChild != nullptr && psLastChild->psNext;
349 psLastChild = psLastChild->psNext )
350 {
351 }
352 CPLAssert(psLastChild); // we have at least rasterXSize
353 for( int iBand = 0; iBand < nBands; iBand++ )
354 {
355 CPLXMLNode *psBandTree =
356 static_cast<VRTRasterBand *>(
357 papoBands[iBand])->SerializeToXML( pszVRTPathIn );
358
359 if( psBandTree != nullptr )
360 {
361 psLastChild->psNext = psBandTree;
362 psLastChild = psBandTree;
363 }
364 }
365
366 /* -------------------------------------------------------------------- */
367 /* Serialize dataset mask band. */
368 /* -------------------------------------------------------------------- */
369 if( m_poMaskBand )
370 {
371 CPLXMLNode *psBandTree =
372 m_poMaskBand->SerializeToXML(pszVRTPathIn);
373
374 if( psBandTree != nullptr )
375 {
376 CPLXMLNode *psMaskBandElement
377 = CPLCreateXMLNode( psDSTree, CXT_Element, "MaskBand" );
378 CPLAddXMLChild( psMaskBandElement, psBandTree );
379 }
380 }
381
382 /* -------------------------------------------------------------------- */
383 /* Overview factors. */
384 /* -------------------------------------------------------------------- */
385 if( !m_anOverviewFactors.empty() )
386 {
387 CPLString osOverviewList;
388 for( int nOvFactor: m_anOverviewFactors )
389 {
390 if( !osOverviewList.empty() )
391 osOverviewList += " ";
392 osOverviewList += CPLSPrintf("%d", nOvFactor);
393 }
394 CPLXMLNode* psOverviewList = CPLCreateXMLElementAndValue(
395 psDSTree, "OverviewList", osOverviewList);
396 if( !m_osOverviewResampling.empty() )
397 {
398 CPLAddXMLAttributeAndValue( psOverviewList,
399 "resampling",
400 m_osOverviewResampling );
401 }
402 }
403
404 return psDSTree;
405 }
406
407 /*! @endcond */
408 /************************************************************************/
409 /* VRTSerializeToXML() */
410 /************************************************************************/
411
412 /**
413 * @see VRTDataset::SerializeToXML()
414 */
415
VRTSerializeToXML(VRTDatasetH hDataset,const char * pszVRTPath)416 CPLXMLNode * CPL_STDCALL VRTSerializeToXML( VRTDatasetH hDataset,
417 const char *pszVRTPath )
418 {
419 VALIDATE_POINTER1( hDataset, "VRTSerializeToXML", nullptr );
420
421 return static_cast<VRTDataset *>(GDALDataset::FromHandle(
422 hDataset))->SerializeToXML(pszVRTPath);
423 }
424 /*! @cond Doxygen_Suppress */
425
426
427 /************************************************************************/
428 /* InitBand() */
429 /************************************************************************/
430
InitBand(const char * pszSubclass,int nBand,bool bAllowPansharpened)431 VRTRasterBand* VRTDataset::InitBand(const char* pszSubclass, int nBand,
432 bool bAllowPansharpened)
433 {
434 VRTRasterBand *poBand = nullptr;
435 if( EQUAL(pszSubclass,"VRTSourcedRasterBand") )
436 poBand = new VRTSourcedRasterBand( this, nBand );
437 else if( EQUAL(pszSubclass, "VRTDerivedRasterBand") )
438 poBand = new VRTDerivedRasterBand( this, nBand );
439 else if( EQUAL(pszSubclass, "VRTRawRasterBand") )
440 poBand = new VRTRawRasterBand( this, nBand );
441 else if( EQUAL(pszSubclass, "VRTWarpedRasterBand") &&
442 dynamic_cast<VRTWarpedDataset*>(this) != nullptr )
443 poBand = new VRTWarpedRasterBand( this, nBand );
444 else if( bAllowPansharpened &&
445 EQUAL(pszSubclass, "VRTPansharpenedRasterBand") &&
446 dynamic_cast<VRTPansharpenedDataset*>(this) != nullptr )
447 poBand = new VRTPansharpenedRasterBand( this, nBand);
448 else
449 CPLError( CE_Failure, CPLE_AppDefined,
450 "VRTRasterBand of unrecognized subclass '%s'.",
451 pszSubclass );
452 return poBand;
453 }
454
455 /************************************************************************/
456 /* XMLInit() */
457 /************************************************************************/
458
XMLInit(CPLXMLNode * psTree,const char * pszVRTPathIn)459 CPLErr VRTDataset::XMLInit( CPLXMLNode *psTree, const char *pszVRTPathIn )
460
461 {
462 if( pszVRTPathIn != nullptr )
463 m_pszVRTPath = CPLStrdup(pszVRTPathIn);
464
465 /* -------------------------------------------------------------------- */
466 /* Check for an SRS node. */
467 /* -------------------------------------------------------------------- */
468 CPLXMLNode* psSRSNode = CPLGetXMLNode(psTree, "SRS");
469 if( psSRSNode )
470 {
471 if( m_poSRS )
472 m_poSRS->Release();
473 m_poSRS = new OGRSpatialReference();
474 m_poSRS->SetFromUserInput( CPLGetXMLValue(psSRSNode, nullptr, "") );
475 const char* pszMapping =
476 CPLGetXMLValue(psSRSNode, "dataAxisToSRSAxisMapping", nullptr);
477 if( pszMapping )
478 {
479 char** papszTokens = CSLTokenizeStringComplex( pszMapping, ",", FALSE, FALSE);
480 std::vector<int> anMapping;
481 for( int i = 0; papszTokens && papszTokens[i]; i++ )
482 {
483 anMapping.push_back(atoi(papszTokens[i]));
484 }
485 CSLDestroy(papszTokens);
486 m_poSRS->SetDataAxisToSRSAxisMapping(anMapping);
487 }
488 else
489 {
490 m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
491 }
492 }
493
494 /* -------------------------------------------------------------------- */
495 /* Check for a GeoTransform node. */
496 /* -------------------------------------------------------------------- */
497 if( strlen(CPLGetXMLValue(psTree, "GeoTransform", "")) > 0 )
498 {
499 const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
500 char **papszTokens
501 = CSLTokenizeStringComplex( pszGT, ",", FALSE, FALSE );
502 if( CSLCount(papszTokens) != 6 )
503 {
504 CPLError( CE_Warning, CPLE_AppDefined,
505 "GeoTransform node does not have expected six values.");
506 }
507 else
508 {
509 for( int iTA = 0; iTA < 6; iTA++ )
510 m_adfGeoTransform[iTA] = CPLAtof(papszTokens[iTA]);
511 m_bGeoTransformSet = TRUE;
512 }
513
514 CSLDestroy( papszTokens );
515 }
516
517 /* -------------------------------------------------------------------- */
518 /* Check for GCPs. */
519 /* -------------------------------------------------------------------- */
520 CPLXMLNode *psGCPList = CPLGetXMLNode( psTree, "GCPList" );
521
522 if( psGCPList != nullptr )
523 {
524 GDALDeserializeGCPListFromXML( psGCPList,
525 &m_pasGCPList,
526 &m_nGCPCount,
527 &m_poGCP_SRS );
528 }
529
530 /* -------------------------------------------------------------------- */
531 /* Apply any dataset level metadata. */
532 /* -------------------------------------------------------------------- */
533 oMDMD.XMLInit( psTree, TRUE );
534
535 /* -------------------------------------------------------------------- */
536 /* Create dataset mask band. */
537 /* -------------------------------------------------------------------- */
538
539 /* Parse dataset mask band first */
540 CPLXMLNode* psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
541
542 CPLXMLNode *psChild = nullptr;
543 if( psMaskBandNode )
544 psChild = psMaskBandNode->psChild;
545 else
546 psChild = nullptr;
547
548 for( ; psChild != nullptr; psChild=psChild->psNext )
549 {
550 if( psChild->eType == CXT_Element
551 && EQUAL(psChild->pszValue,"VRTRasterBand") )
552 {
553 const char *pszSubclass = CPLGetXMLValue( psChild, "subclass",
554 "VRTSourcedRasterBand" );
555
556 VRTRasterBand *poBand = InitBand(pszSubclass, 0, false);
557 if( poBand != nullptr
558 && poBand->XMLInit( psChild, pszVRTPathIn, this,
559 m_oMapSharedSources ) == CE_None )
560 {
561 SetMaskBand(poBand);
562 break;
563 }
564 else
565 {
566 delete poBand;
567 return CE_Failure;
568 }
569 }
570 }
571
572 /* -------------------------------------------------------------------- */
573 /* Create band information objects. */
574 /* -------------------------------------------------------------------- */
575 int l_nBands = 0;
576 for( psChild=psTree->psChild; psChild != nullptr; psChild=psChild->psNext )
577 {
578 if( psChild->eType == CXT_Element
579 && EQUAL(psChild->pszValue,"VRTRasterBand") )
580 {
581 const char *pszSubclass = CPLGetXMLValue( psChild, "subclass",
582 "VRTSourcedRasterBand" );
583
584 VRTRasterBand *poBand = InitBand(pszSubclass, l_nBands+1, true);
585 if( poBand != nullptr
586 && poBand->XMLInit( psChild, pszVRTPathIn, this,
587 m_oMapSharedSources ) == CE_None )
588 {
589 l_nBands ++;
590 SetBand( l_nBands, poBand );
591 }
592 else
593 {
594 delete poBand;
595 return CE_Failure;
596 }
597 }
598 }
599
600 CPLXMLNode* psGroup = CPLGetXMLNode(psTree, "Group");
601 if( psGroup )
602 {
603 const char* pszName = CPLGetXMLValue(psGroup, "name", nullptr);
604 if( pszName == nullptr || !EQUAL(pszName, "/") )
605 {
606 CPLError(CE_Failure, CPLE_AppDefined,
607 "Missing name or not equal to '/'");
608 return CE_Failure;
609 }
610
611 m_poRootGroup = std::make_shared<VRTGroup>(std::string(), "/");
612 m_poRootGroup->SetIsRootGroup();
613 if( !m_poRootGroup->XMLInit( m_poRootGroup, m_poRootGroup,
614 psGroup, pszVRTPathIn ) )
615 {
616 return CE_Failure;
617 }
618 }
619
620 /* -------------------------------------------------------------------- */
621 /* Create virtual overviews. */
622 /* -------------------------------------------------------------------- */
623 const char* pszSubClass = CPLGetXMLValue(psTree, "subClass", "");
624 if( EQUAL(pszSubClass, "") )
625 {
626 CPLStringList aosTokens(CSLTokenizeString(
627 CPLGetXMLValue( psTree, "OverviewList", "" ) ));
628 m_osOverviewResampling =
629 CPLGetXMLValue( psTree, "OverviewList.resampling", "" );
630 for( int iOverview = 0; iOverview < aosTokens.size(); iOverview++ )
631 {
632 const int nOvFactor = atoi(aosTokens[iOverview]);
633 if( nOvFactor <= 1 )
634 {
635 CPLError(CE_Failure, CPLE_AppDefined,
636 "Invalid overview factor");
637 return CE_Failure;
638 }
639
640 AddVirtualOverview(nOvFactor, m_osOverviewResampling.empty() ?
641 "nearest" : m_osOverviewResampling.c_str());
642 }
643 }
644
645 return CE_None;
646 }
647
648 /************************************************************************/
649 /* GetGCPCount() */
650 /************************************************************************/
651
GetGCPCount()652 int VRTDataset::GetGCPCount()
653
654 {
655 return m_nGCPCount;
656 }
657
658 /************************************************************************/
659 /* GetGCPs() */
660 /************************************************************************/
661
GetGCPs()662 const GDAL_GCP *VRTDataset::GetGCPs()
663
664 {
665 return m_pasGCPList;
666 }
667
668 /************************************************************************/
669 /* SetGCPs() */
670 /************************************************************************/
671
SetGCPs(int nGCPCountIn,const GDAL_GCP * pasGCPListIn,const OGRSpatialReference * poGCP_SRS)672 CPLErr VRTDataset::SetGCPs( int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
673 const OGRSpatialReference* poGCP_SRS )
674
675 {
676 if( m_poGCP_SRS )
677 m_poGCP_SRS->Release();
678 if( m_nGCPCount > 0 )
679 {
680 GDALDeinitGCPs( m_nGCPCount, m_pasGCPList );
681 CPLFree( m_pasGCPList );
682 }
683
684 m_poGCP_SRS = poGCP_SRS ? poGCP_SRS->Clone(): nullptr;
685
686 m_nGCPCount = nGCPCountIn;
687
688 m_pasGCPList = GDALDuplicateGCPs( nGCPCountIn, pasGCPListIn );
689
690 SetNeedsFlush();
691
692 return CE_None;
693 }
694
695 /************************************************************************/
696 /* SetSpatialRef() */
697 /************************************************************************/
698
SetSpatialRef(const OGRSpatialReference * poSRS)699 CPLErr VRTDataset::SetSpatialRef(const OGRSpatialReference* poSRS)
700
701 {
702 if( m_poSRS )
703 m_poSRS->Release();
704 if( poSRS )
705 m_poSRS = poSRS->Clone();
706 else
707 m_poSRS = nullptr;
708
709 SetNeedsFlush();
710
711 return CE_None;
712 }
713
714 /************************************************************************/
715 /* SetGeoTransform() */
716 /************************************************************************/
717
SetGeoTransform(double * padfGeoTransformIn)718 CPLErr VRTDataset::SetGeoTransform( double *padfGeoTransformIn )
719
720 {
721 memcpy( m_adfGeoTransform, padfGeoTransformIn, sizeof(double) * 6 );
722 m_bGeoTransformSet = TRUE;
723
724 SetNeedsFlush();
725
726 return CE_None;
727 }
728
729 /************************************************************************/
730 /* GetGeoTransform() */
731 /************************************************************************/
732
GetGeoTransform(double * padfGeoTransform)733 CPLErr VRTDataset::GetGeoTransform( double * padfGeoTransform )
734
735 {
736 memcpy( padfGeoTransform, m_adfGeoTransform, sizeof(double) * 6 );
737
738 return m_bGeoTransformSet ? CE_None : CE_Failure;
739 }
740
741 /************************************************************************/
742 /* SetMetadata() */
743 /************************************************************************/
744
SetMetadata(char ** papszMetadata,const char * pszDomain)745 CPLErr VRTDataset::SetMetadata( char **papszMetadata,
746 const char *pszDomain )
747
748 {
749 SetNeedsFlush();
750
751 return GDALDataset::SetMetadata( papszMetadata, pszDomain );
752 }
753
754 /************************************************************************/
755 /* SetMetadataItem() */
756 /************************************************************************/
757
SetMetadataItem(const char * pszName,const char * pszValue,const char * pszDomain)758 CPLErr VRTDataset::SetMetadataItem( const char *pszName,
759 const char *pszValue,
760 const char *pszDomain )
761
762 {
763 SetNeedsFlush();
764
765 return GDALDataset::SetMetadataItem( pszName, pszValue, pszDomain );
766 }
767
768 /************************************************************************/
769 /* Identify() */
770 /************************************************************************/
771
Identify(GDALOpenInfo * poOpenInfo)772 int VRTDataset::Identify( GDALOpenInfo * poOpenInfo )
773
774 {
775 if( poOpenInfo->nHeaderBytes > 20
776 && strstr(reinterpret_cast<const char*>(poOpenInfo->pabyHeader),"<VRTDataset") != nullptr )
777 return TRUE;
778
779 if( strstr(poOpenInfo->pszFilename,"<VRTDataset") != nullptr )
780 return TRUE;
781
782 if( STARTS_WITH_CI(poOpenInfo->pszFilename, VRT_PROTOCOL_PREFIX) )
783 return TRUE;
784
785 return FALSE;
786 }
787
788 /************************************************************************/
789 /* Open() */
790 /************************************************************************/
791
Open(GDALOpenInfo * poOpenInfo)792 GDALDataset *VRTDataset::Open( GDALOpenInfo * poOpenInfo )
793
794 {
795 /* -------------------------------------------------------------------- */
796 /* Does this appear to be a virtual dataset definition XML */
797 /* file? */
798 /* -------------------------------------------------------------------- */
799 if( !Identify( poOpenInfo ) )
800 return nullptr;
801
802 if( STARTS_WITH_CI(poOpenInfo->pszFilename, VRT_PROTOCOL_PREFIX) )
803 return OpenVRTProtocol(poOpenInfo->pszFilename);
804
805 /* -------------------------------------------------------------------- */
806 /* Try to read the whole file into memory. */
807 /* -------------------------------------------------------------------- */
808 char *pszXML = nullptr;
809 VSILFILE *fp = poOpenInfo->fpL;
810
811 char *pszVRTPath = nullptr;
812 if( fp != nullptr )
813 {
814 poOpenInfo->fpL = nullptr;
815
816 GByte* pabyOut = nullptr;
817 if( !VSIIngestFile( fp, poOpenInfo->pszFilename, &pabyOut,
818 nullptr, INT_MAX - 1 ) )
819 {
820 CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
821 return nullptr;
822 }
823 pszXML = reinterpret_cast<char*>(pabyOut);
824
825 char* pszCurDir = CPLGetCurrentDir();
826 const char *currentVrtFilename
827 = CPLProjectRelativeFilename(pszCurDir, poOpenInfo->pszFilename);
828 CPLString osInitialCurrentVrtFilename(currentVrtFilename);
829 CPLFree(pszCurDir);
830
831 #if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
832 char filenameBuffer[2048];
833
834 while( true ) {
835 VSIStatBuf statBuffer;
836 int lstatCode = lstat( currentVrtFilename, &statBuffer );
837 if( lstatCode == -1 ) {
838 if( errno == ENOENT )
839 {
840 // File could be a virtual file, let later checks handle it.
841 break;
842 }
843 else
844 {
845 CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
846 CPLFree( pszXML );
847 CPLError( CE_Failure, CPLE_FileIO,
848 "Failed to lstat %s: %s",
849 currentVrtFilename,
850 VSIStrerror(errno) );
851 return nullptr;
852 }
853 }
854
855 if( !VSI_ISLNK(statBuffer.st_mode) ) {
856 break;
857 }
858
859 const int bufferSize = static_cast<int>(
860 readlink( currentVrtFilename,
861 filenameBuffer,
862 sizeof(filenameBuffer) ) );
863 if( bufferSize != -1 )
864 {
865 filenameBuffer[std::min(bufferSize, static_cast<int>(
866 sizeof(filenameBuffer) ) - 1)] = 0;
867 // The filename in filenameBuffer might be a relative path
868 // from the linkfile resolve it before looping
869 currentVrtFilename = CPLProjectRelativeFilename(
870 CPLGetDirname( currentVrtFilename ), filenameBuffer);
871 }
872 else
873 {
874 CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
875 CPLFree( pszXML );
876 CPLError( CE_Failure, CPLE_FileIO,
877 "Failed to read filename from symlink %s: %s",
878 currentVrtFilename,
879 VSIStrerror(errno) );
880 return nullptr;
881 }
882 }
883 #endif // HAVE_READLINK && HAVE_LSTAT
884
885 if( osInitialCurrentVrtFilename == currentVrtFilename )
886 pszVRTPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
887 else
888 pszVRTPath = CPLStrdup(CPLGetPath(currentVrtFilename));
889
890 CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
891 }
892 /* -------------------------------------------------------------------- */
893 /* Or use the filename as the XML input. */
894 /* -------------------------------------------------------------------- */
895 else
896 {
897 pszXML = CPLStrdup( poOpenInfo->pszFilename );
898 }
899
900 if( CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH") != nullptr )
901 {
902 CPLFree(pszVRTPath);
903 pszVRTPath = CPLStrdup(
904 CSLFetchNameValue( poOpenInfo->papszOpenOptions, "ROOT_PATH" ) );
905 }
906
907 /* -------------------------------------------------------------------- */
908 /* Turn the XML representation into a VRTDataset. */
909 /* -------------------------------------------------------------------- */
910 VRTDataset *poDS = static_cast<VRTDataset *>(
911 OpenXML( pszXML, pszVRTPath, poOpenInfo->eAccess ) );
912
913 if( poDS != nullptr )
914 poDS->m_bNeedsFlush =false;
915
916 if( poDS != nullptr )
917 {
918 if( poDS->GetRasterCount() == 0 &&
919 (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) == 0 &&
920 strstr(pszXML, "VRTPansharpenedDataset") == nullptr )
921 {
922 delete poDS;
923 poDS = nullptr;
924 }
925 else if( poDS->GetRootGroup() == nullptr &&
926 (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
927 (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0 )
928 {
929 delete poDS;
930 poDS = nullptr;
931 }
932 }
933
934 CPLFree( pszXML );
935 CPLFree( pszVRTPath );
936
937 /* -------------------------------------------------------------------- */
938 /* Initialize info for later overview discovery. */
939 /* -------------------------------------------------------------------- */
940
941 if( poDS != nullptr )
942 {
943 if( fp != nullptr )
944 {
945 poDS->oOvManager.Initialize( poDS, poOpenInfo->pszFilename );
946 if( poOpenInfo->AreSiblingFilesLoaded() )
947 poDS->oOvManager.TransferSiblingFiles(
948 poOpenInfo->StealSiblingFiles() );
949 }
950
951 if (poDS->eAccess == GA_Update &&
952 poDS->m_poRootGroup && !STARTS_WITH_CI(poOpenInfo->pszFilename, "<VRT") )
953 {
954 poDS->m_poRootGroup->SetFilename(poOpenInfo->pszFilename);
955 }
956 }
957
958 return poDS;
959 }
960
961 /************************************************************************/
962 /* OpenVRTProtocol() */
963 /* */
964 /* Create an open VRTDataset from a vrt:// string. */
965 /************************************************************************/
966
OpenVRTProtocol(const char * pszSpec)967 GDALDataset *VRTDataset::OpenVRTProtocol( const char* pszSpec )
968
969 {
970 CPLAssert( STARTS_WITH_CI(pszSpec, VRT_PROTOCOL_PREFIX) );
971 CPLString osFilename(pszSpec + strlen(VRT_PROTOCOL_PREFIX) );
972 const auto nPosQuotationMark = osFilename.find('?');
973 CPLString osQueryString;
974 if( nPosQuotationMark != std::string::npos )
975 {
976 osQueryString = osFilename.substr(nPosQuotationMark+1);
977 osFilename.resize(nPosQuotationMark);
978 }
979 auto poSrcDS =
980 GDALDataset::Open(osFilename, GDAL_OF_RASTER | GDAL_OF_SHARED,
981 nullptr, nullptr, nullptr);
982 if( poSrcDS == nullptr )
983 {
984 return nullptr;
985 }
986
987 // Parse query string
988 CPLStringList aosTokens(CSLTokenizeString2(osQueryString, "&", 0));
989 std::vector<int> anBands;
990 for( int i = 0; i < aosTokens.size(); i++ )
991 {
992 char* pszKey = nullptr;
993 const char* pszValue = CPLParseNameValue(aosTokens[i], &pszKey);
994 if( pszKey && pszValue )
995 {
996 if( EQUAL(pszKey, "bands") )
997 {
998 CPLStringList aosBands(CSLTokenizeString2(pszValue, ",", 0));
999 for( int j = 0; j < aosBands.size(); j++ )
1000 {
1001 if( EQUAL(aosBands[j], "mask") )
1002 {
1003 anBands.push_back(0);
1004 }
1005 else
1006 {
1007 const int nBand = atoi(aosBands[j]);
1008 if( nBand <= 0 || nBand > poSrcDS->GetRasterCount() )
1009 {
1010 CPLError(CE_Failure, CPLE_IllegalArg,
1011 "Invalid band number: %s", aosBands[j]);
1012 poSrcDS->ReleaseRef();
1013 CPLFree(pszKey);
1014 return nullptr;
1015 }
1016 anBands.push_back(nBand);
1017 }
1018 }
1019 }
1020 else
1021 {
1022 CPLError(CE_Failure, CPLE_NotSupported,
1023 "Unknown option: %s", pszKey);
1024 poSrcDS->ReleaseRef();
1025 CPLFree(pszKey);
1026 return nullptr;
1027 }
1028 }
1029 CPLFree(pszKey);
1030 }
1031
1032 CPLStringList argv;
1033 argv.AddString("-of");
1034 argv.AddString("VRT");
1035
1036 for( const int nBand: anBands )
1037 {
1038 argv.AddString("-b");
1039 argv.AddString(nBand == 0 ? "mask" : CPLSPrintf("%d", nBand));
1040 }
1041
1042 GDALTranslateOptions* psOptions = GDALTranslateOptionsNew(argv.List(), nullptr);
1043
1044 auto hRet = GDALTranslate("", GDALDataset::ToHandle(poSrcDS),
1045 psOptions, nullptr);
1046
1047 GDALTranslateOptionsFree( psOptions );
1048
1049 poSrcDS->ReleaseRef();
1050
1051 auto poDS = cpl::down_cast<VRTDataset*>(GDALDataset::FromHandle(hRet));
1052 if( poDS )
1053 {
1054 poDS->SetDescription(pszSpec);
1055 poDS->SetWritable(false);
1056 }
1057 return poDS;
1058 }
1059
1060 /************************************************************************/
1061 /* OpenXML() */
1062 /* */
1063 /* Create an open VRTDataset from a supplied XML representation */
1064 /* of the dataset. */
1065 /************************************************************************/
1066
OpenXML(const char * pszXML,const char * pszVRTPath,GDALAccess eAccess)1067 GDALDataset *VRTDataset::OpenXML( const char *pszXML, const char *pszVRTPath,
1068 GDALAccess eAccess)
1069
1070 {
1071 /* -------------------------------------------------------------------- */
1072 /* Parse the XML. */
1073 /* -------------------------------------------------------------------- */
1074 CPLXMLTreeCloser psTree(CPLParseXMLString( pszXML ));
1075 if( psTree == nullptr )
1076 return nullptr;
1077
1078 CPLXMLNode *psRoot = CPLGetXMLNode( psTree.get(), "=VRTDataset" );
1079 if( psRoot == nullptr )
1080 {
1081 CPLError( CE_Failure, CPLE_AppDefined,
1082 "Missing VRTDataset element." );
1083 return nullptr;
1084 }
1085
1086 const char* pszSubClass = CPLGetXMLValue(psRoot, "subClass", "");
1087
1088 const bool bIsPansharpened =
1089 strcmp(pszSubClass, "VRTPansharpenedDataset" ) == 0;
1090
1091 if( !bIsPansharpened &&
1092 CPLGetXMLNode( psRoot, "Group" ) == nullptr &&
1093 (CPLGetXMLNode( psRoot, "rasterXSize" ) == nullptr
1094 || CPLGetXMLNode( psRoot, "rasterYSize" ) == nullptr
1095 || CPLGetXMLNode( psRoot, "VRTRasterBand" ) == nullptr) )
1096 {
1097 CPLError( CE_Failure, CPLE_AppDefined,
1098 "Missing one of rasterXSize, rasterYSize or bands on"
1099 " VRTDataset." );
1100 return nullptr;
1101 }
1102
1103 /* -------------------------------------------------------------------- */
1104 /* Create the new virtual dataset object. */
1105 /* -------------------------------------------------------------------- */
1106 const int nXSize = atoi(CPLGetXMLValue(psRoot, "rasterXSize","0"));
1107 const int nYSize = atoi(CPLGetXMLValue(psRoot, "rasterYSize","0"));
1108
1109 if( !bIsPansharpened &&
1110 CPLGetXMLNode( psRoot, "VRTRasterBand" ) != nullptr &&
1111 !GDALCheckDatasetDimensions( nXSize, nYSize ) )
1112 {
1113 return nullptr;
1114 }
1115
1116 VRTDataset *poDS = nullptr;
1117 if( strcmp(pszSubClass, "VRTWarpedDataset") == 0 )
1118 poDS = new VRTWarpedDataset( nXSize, nYSize );
1119 else if( bIsPansharpened )
1120 poDS = new VRTPansharpenedDataset( nXSize, nYSize );
1121 else
1122 {
1123 poDS = new VRTDataset( nXSize, nYSize );
1124 poDS->eAccess = eAccess;
1125 }
1126
1127 if( poDS->XMLInit( psRoot, pszVRTPath ) != CE_None )
1128 {
1129 delete poDS;
1130 poDS = nullptr;
1131 }
1132
1133 /* -------------------------------------------------------------------- */
1134 /* Try to return a regular handle on the file. */
1135 /* -------------------------------------------------------------------- */
1136
1137 return poDS;
1138 }
1139
1140 /************************************************************************/
1141 /* AddBand() */
1142 /************************************************************************/
1143
AddBand(GDALDataType eType,char ** papszOptions)1144 CPLErr VRTDataset::AddBand( GDALDataType eType, char **papszOptions )
1145
1146 {
1147 SetNeedsFlush();
1148
1149 /* ==================================================================== */
1150 /* Handle a new raw band. */
1151 /* ==================================================================== */
1152 const char *pszSubClass = CSLFetchNameValue(papszOptions, "subclass");
1153
1154 if( pszSubClass != nullptr && EQUAL(pszSubClass,"VRTRawRasterBand") )
1155 {
1156 const int nWordDataSize = GDALGetDataTypeSizeBytes( eType );
1157
1158 /* -------------------------------------------------------------------- */
1159 /* Collect required information. */
1160 /* -------------------------------------------------------------------- */
1161 const char* pszImageOffset =
1162 CSLFetchNameValueDef(papszOptions, "ImageOffset", "0");
1163 vsi_l_offset nImageOffset = CPLScanUIntBig(
1164 pszImageOffset, static_cast<int>(strlen(pszImageOffset)) );
1165
1166 int nPixelOffset = nWordDataSize;
1167 const char* pszPixelOffset =
1168 CSLFetchNameValue(papszOptions, "PixelOffset");
1169 if( pszPixelOffset != nullptr )
1170 nPixelOffset = atoi(pszPixelOffset);
1171
1172 int nLineOffset;
1173 const char* pszLineOffset =
1174 CSLFetchNameValue(papszOptions, "LineOffset");
1175 if( pszLineOffset != nullptr )
1176 nLineOffset = atoi(pszLineOffset);
1177 else
1178 {
1179 if( nPixelOffset > INT_MAX / GetRasterXSize() ||
1180 nPixelOffset < INT_MIN / GetRasterXSize() )
1181 {
1182 CPLError( CE_Failure, CPLE_AppDefined, "Int overflow");
1183 return CE_Failure;
1184 }
1185 nLineOffset = nPixelOffset * GetRasterXSize();
1186 }
1187
1188 const char *pszByteOrder =
1189 CSLFetchNameValue(papszOptions, "ByteOrder");
1190
1191 const char *pszFilename =
1192 CSLFetchNameValue(papszOptions, "SourceFilename");
1193 if( pszFilename == nullptr )
1194 {
1195 CPLError( CE_Failure, CPLE_AppDefined,
1196 "AddBand() requires a SourceFilename option for "
1197 "VRTRawRasterBands." );
1198 return CE_Failure;
1199 }
1200
1201 const bool bRelativeToVRT =
1202 CPLFetchBool( papszOptions, "relativeToVRT", false );
1203
1204 /* -------------------------------------------------------------------- */
1205 /* Create and initialize the band. */
1206 /* -------------------------------------------------------------------- */
1207
1208 VRTRawRasterBand *poBand =
1209 new VRTRawRasterBand( this, GetRasterCount() + 1, eType );
1210
1211 char* l_pszVRTPath = CPLStrdup(CPLGetPath(GetDescription()));
1212 if( EQUAL(l_pszVRTPath, "") )
1213 {
1214 CPLFree(l_pszVRTPath);
1215 l_pszVRTPath = nullptr;
1216 }
1217
1218 const CPLErr eErr =
1219 poBand->SetRawLink( pszFilename, l_pszVRTPath, bRelativeToVRT,
1220 nImageOffset, nPixelOffset, nLineOffset,
1221 pszByteOrder );
1222 CPLFree(l_pszVRTPath);
1223 if( eErr != CE_None )
1224 {
1225 delete poBand;
1226 return eErr;
1227 }
1228
1229 SetBand( GetRasterCount() + 1, poBand );
1230
1231 return CE_None;
1232 }
1233
1234 /* ==================================================================== */
1235 /* Handle a new "sourced" band. */
1236 /* ==================================================================== */
1237 else
1238 {
1239 VRTSourcedRasterBand *poBand = nullptr;
1240
1241 /* ---- Check for our sourced band 'derived' subclass ---- */
1242 if(pszSubClass != nullptr && EQUAL(pszSubClass,"VRTDerivedRasterBand")) {
1243
1244 /* We'll need a pointer to the subclass in case we need */
1245 /* to set the new band's pixel function below. */
1246 VRTDerivedRasterBand* poDerivedBand = new VRTDerivedRasterBand(
1247 this, GetRasterCount() + 1, eType,
1248 GetRasterXSize(), GetRasterYSize());
1249
1250 /* Set the pixel function options it provided. */
1251 const char* pszFuncName =
1252 CSLFetchNameValue(papszOptions, "PixelFunctionType");
1253 if( pszFuncName != nullptr )
1254 poDerivedBand->SetPixelFunctionName(pszFuncName);
1255
1256 const char* pszLanguage =
1257 CSLFetchNameValue(papszOptions, "PixelFunctionLanguage");
1258 if( pszLanguage != nullptr )
1259 poDerivedBand->SetPixelFunctionLanguage(pszLanguage);
1260
1261 const char* pszTransferTypeName =
1262 CSLFetchNameValue(papszOptions, "SourceTransferType");
1263 if( pszTransferTypeName != nullptr )
1264 {
1265 const GDALDataType eTransferType =
1266 GDALGetDataTypeByName(pszTransferTypeName);
1267 if( eTransferType == GDT_Unknown )
1268 {
1269 CPLError( CE_Failure, CPLE_AppDefined,
1270 "invalid SourceTransferType: \"%s\".",
1271 pszTransferTypeName);
1272 delete poDerivedBand;
1273 return CE_Failure;
1274 }
1275 poDerivedBand->SetSourceTransferType(eTransferType);
1276 }
1277
1278 /* We're done with the derived band specific stuff, so */
1279 /* we can assigned the base class pointer now. */
1280 poBand = poDerivedBand;
1281 }
1282 else {
1283 int nBlockXSizeIn = atoi(
1284 CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "0"));
1285 int nBlockYSizeIn = atoi(
1286 CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "0"));
1287 /* ---- Standard sourced band ---- */
1288 poBand = new VRTSourcedRasterBand(
1289 this, GetRasterCount() + 1, eType,
1290 GetRasterXSize(), GetRasterYSize(),
1291 nBlockXSizeIn, nBlockYSizeIn);
1292 }
1293
1294 SetBand( GetRasterCount() + 1, poBand );
1295
1296 for( int i=0; papszOptions != nullptr && papszOptions[i] != nullptr; i++ )
1297 {
1298 if( STARTS_WITH_CI(papszOptions[i], "AddFuncSource=") )
1299 {
1300 char **papszTokens
1301 = CSLTokenizeStringComplex( papszOptions[i]+14,
1302 ",", TRUE, FALSE );
1303 if( CSLCount(papszTokens) < 1 )
1304 {
1305 CPLError( CE_Failure, CPLE_AppDefined,
1306 "AddFuncSource(): required argument missing." );
1307 // TODO: How should this error be handled? Return
1308 // CE_Failure?
1309 }
1310
1311 VRTImageReadFunc pfnReadFunc = nullptr;
1312 sscanf( papszTokens[0], "%p", &pfnReadFunc );
1313
1314 void *pCBData = nullptr;
1315 if( CSLCount(papszTokens) > 1 )
1316 sscanf( papszTokens[1], "%p", &pCBData );
1317
1318 const double dfNoDataValue =
1319 ( CSLCount(papszTokens) > 2 ) ?
1320 CPLAtof( papszTokens[2] ) : VRT_NODATA_UNSET;
1321
1322 poBand->AddFuncSource( pfnReadFunc, pCBData, dfNoDataValue );
1323
1324 CSLDestroy( papszTokens );
1325 }
1326 }
1327
1328 return CE_None;
1329 }
1330 }
1331 /*! @endcond */
1332 /************************************************************************/
1333 /* VRTAddBand() */
1334 /************************************************************************/
1335
1336 /**
1337 * @see VRTDataset::VRTAddBand().
1338 *
1339 * @note The return type of this function is int, but the actual values
1340 * returned are of type CPLErr.
1341 */
1342
VRTAddBand(VRTDatasetH hDataset,GDALDataType eType,char ** papszOptions)1343 int CPL_STDCALL VRTAddBand( VRTDatasetH hDataset, GDALDataType eType,
1344 char **papszOptions )
1345
1346 {
1347 VALIDATE_POINTER1( hDataset, "VRTAddBand", 0 );
1348
1349 return static_cast<VRTDataset *>(GDALDataset::FromHandle(
1350 hDataset))->AddBand( eType, papszOptions );
1351 }
1352 /*! @cond Doxygen_Suppress */
1353 /************************************************************************/
1354 /* Create() */
1355 /************************************************************************/
1356
1357 GDALDataset *
Create(const char * pszName,int nXSize,int nYSize,int nBands,GDALDataType eType,char ** papszOptions)1358 VRTDataset::Create( const char * pszName,
1359 int nXSize, int nYSize, int nBands,
1360 GDALDataType eType, char ** papszOptions )
1361
1362 {
1363 if( STARTS_WITH_CI(pszName, "<VRTDataset") )
1364 {
1365 GDALDataset *poDS = OpenXML( pszName, nullptr, GA_Update );
1366 if( poDS != nullptr )
1367 poDS->SetDescription( "<FromXML>" );
1368 return poDS;
1369 }
1370
1371 const char *pszSubclass = CSLFetchNameValue( papszOptions,
1372 "SUBCLASS" );
1373
1374 VRTDataset *poDS = nullptr;
1375
1376 if( pszSubclass == nullptr || EQUAL(pszSubclass,"VRTDataset") )
1377 poDS = new VRTDataset( nXSize, nYSize );
1378 else if( EQUAL(pszSubclass,"VRTWarpedDataset") )
1379 {
1380 poDS = new VRTWarpedDataset( nXSize, nYSize );
1381 }
1382 else
1383 {
1384 CPLError( CE_Failure, CPLE_AppDefined,
1385 "SUBCLASS=%s not recognised.",
1386 pszSubclass );
1387 return nullptr;
1388 }
1389 poDS->eAccess = GA_Update;
1390
1391 poDS->SetDescription( pszName );
1392
1393 for( int iBand = 0; iBand < nBands; iBand++ )
1394 poDS->AddBand( eType, nullptr );
1395
1396 poDS->SetNeedsFlush();
1397
1398 poDS->oOvManager.Initialize( poDS, pszName );
1399
1400 return poDS;
1401 }
1402
1403
1404 /************************************************************************/
1405 /* CreateMultiDimensional() */
1406 /************************************************************************/
1407
CreateMultiDimensional(const char * pszFilename,CSLConstList,CSLConstList)1408 GDALDataset * VRTDataset::CreateMultiDimensional( const char * pszFilename,
1409 CSLConstList /*papszRootGroupOptions*/,
1410 CSLConstList /*papszOptions*/ )
1411 {
1412 VRTDataset *poDS = new VRTDataset( 0, 0 );
1413 poDS->eAccess = GA_Update;
1414 poDS->SetDescription(pszFilename);
1415 poDS->m_poRootGroup = std::make_shared<VRTGroup>(std::string(), "/");
1416 poDS->m_poRootGroup->SetIsRootGroup();
1417 poDS->m_poRootGroup->SetFilename(pszFilename);
1418 poDS->m_poRootGroup->SetDirty();
1419
1420 return poDS;
1421 }
1422
1423
1424 /************************************************************************/
1425 /* GetFileList() */
1426 /************************************************************************/
1427
GetFileList()1428 char** VRTDataset::GetFileList()
1429 {
1430 char** papszFileList = GDALDataset::GetFileList();
1431
1432 int nSize = CSLCount(papszFileList);
1433 int nMaxSize = nSize;
1434
1435 // Do not need an element deallocator as each string points to an
1436 // element of the papszFileList.
1437 CPLHashSet* hSetFiles = CPLHashSetNew(CPLHashSetHashStr,
1438 CPLHashSetEqualStr,
1439 nullptr);
1440
1441 for( int iBand = 0; iBand < nBands; iBand++ )
1442 {
1443 static_cast<VRTRasterBand *>(
1444 papoBands[iBand])->GetFileList(
1445 &papszFileList, &nSize, &nMaxSize, hSetFiles );
1446 }
1447
1448 CPLHashSetDestroy(hSetFiles);
1449
1450 return papszFileList;
1451 }
1452
1453 /************************************************************************/
1454 /* Delete() */
1455 /************************************************************************/
1456
1457 /* We implement Delete() to avoid that the default implementation */
1458 /* in GDALDriver::Delete() destroys the source files listed by GetFileList(),*/
1459 /* which would be an undesired effect... */
Delete(const char * pszFilename)1460 CPLErr VRTDataset::Delete( const char * pszFilename )
1461 {
1462 GDALDriverH hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1463
1464 if( !hDriver || !EQUAL( GDALGetDriverShortName(hDriver), "VRT" ) )
1465 return CE_Failure;
1466
1467 if( strstr(pszFilename, "<VRTDataset") == nullptr &&
1468 VSIUnlink( pszFilename ) != 0 )
1469 {
1470 CPLError( CE_Failure, CPLE_AppDefined,
1471 "Deleting %s failed:\n%s",
1472 pszFilename,
1473 VSIStrerror(errno) );
1474 return CE_Failure;
1475 }
1476
1477 return CE_None;
1478 }
1479
1480 /************************************************************************/
1481 /* CreateMaskBand() */
1482 /************************************************************************/
1483
CreateMaskBand(int)1484 CPLErr VRTDataset::CreateMaskBand( int )
1485 {
1486 if( m_poMaskBand != nullptr )
1487 {
1488 CPLError(CE_Failure, CPLE_AppDefined,
1489 "This VRT dataset has already a mask band");
1490 return CE_Failure;
1491 }
1492
1493 SetMaskBand(new VRTSourcedRasterBand( this, 0 ));
1494
1495 return CE_None;
1496 }
1497
1498 /************************************************************************/
1499 /* SetMaskBand() */
1500 /************************************************************************/
1501
SetMaskBand(VRTRasterBand * poMaskBandIn)1502 void VRTDataset::SetMaskBand(VRTRasterBand* poMaskBandIn)
1503 {
1504 delete m_poMaskBand;
1505 m_poMaskBand = poMaskBandIn;
1506 m_poMaskBand->SetIsMaskBand();
1507 }
1508
1509 /************************************************************************/
1510 /* CloseDependentDatasets() */
1511 /************************************************************************/
1512
CloseDependentDatasets()1513 int VRTDataset::CloseDependentDatasets()
1514 {
1515 /* We need to call it before removing the sources, otherwise */
1516 /* we would remove them from the serizalized VRT */
1517 FlushCache();
1518
1519 int bHasDroppedRef = GDALDataset::CloseDependentDatasets();
1520
1521 for( int iBand = 0; iBand < nBands; iBand++ )
1522 {
1523 bHasDroppedRef |= static_cast<VRTRasterBand *>(
1524 papoBands[iBand] )->CloseDependentDatasets();
1525 }
1526
1527 return bHasDroppedRef;
1528 }
1529
1530 /************************************************************************/
1531 /* CheckCompatibleForDatasetIO() */
1532 /************************************************************************/
1533
1534 /* We will return TRUE only if all the bands are VRTSourcedRasterBands */
1535 /* made of identical sources, that are strictly VRTSimpleSource, and that */
1536 /* the band number of each source is the band number of the */
1537 /* VRTSourcedRasterBand. */
1538
CheckCompatibleForDatasetIO()1539 int VRTDataset::CheckCompatibleForDatasetIO()
1540 {
1541 int nSources = 0;
1542 VRTSource **papoSources = nullptr;
1543 CPLString osResampling;
1544
1545 if( m_bCompatibleForDatasetIO >= 0 )
1546 {
1547 return m_bCompatibleForDatasetIO;
1548 }
1549
1550 for(int iBand = 0; iBand < nBands; iBand++)
1551 {
1552 if( !static_cast<VRTRasterBand *>(
1553 papoBands[iBand] )->IsSourcedRasterBand() )
1554 return FALSE;
1555
1556 VRTSourcedRasterBand* poBand
1557 = static_cast<VRTSourcedRasterBand*>( papoBands[iBand] );
1558
1559 // Do not allow VRTDerivedRasterBand for example
1560 if( typeid(*poBand) != typeid(VRTSourcedRasterBand) )
1561 return FALSE;
1562
1563 if( iBand == 0 )
1564 {
1565 nSources = poBand->nSources;
1566 papoSources = poBand->papoSources;
1567 for(int iSource = 0; iSource < nSources; iSource++)
1568 {
1569 if( !papoSources[iSource]->IsSimpleSource() )
1570 return FALSE;
1571
1572 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(
1573 papoSources[iSource] );
1574 if( !EQUAL(poSource->GetType(), "SimpleSource") )
1575 return FALSE;
1576
1577 GDALRasterBand *srcband = poSource->GetBand();
1578 if( srcband == nullptr )
1579 return FALSE;
1580 if( srcband->GetDataset() == nullptr )
1581 return FALSE;
1582 if( srcband->GetDataset()->GetRasterCount() <= iBand )
1583 return FALSE;
1584 if( srcband->GetDataset()->GetRasterBand(iBand + 1) != srcband )
1585 return FALSE;
1586 osResampling = poSource->GetResampling();
1587 }
1588 }
1589 else if( nSources != poBand->nSources )
1590 {
1591 return FALSE;
1592 }
1593 else
1594 {
1595 for(int iSource = 0; iSource < nSources; iSource++)
1596 {
1597 if( !poBand->papoSources[iSource]->IsSimpleSource() )
1598 return FALSE;
1599 VRTSimpleSource* poRefSource
1600 = static_cast<VRTSimpleSource *>(
1601 papoSources[iSource] );
1602
1603 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(
1604 poBand->papoSources[iSource] );
1605 if( !EQUAL(poSource->GetType(), "SimpleSource") )
1606 return FALSE;
1607 if( !poSource->IsSameExceptBandNumber(poRefSource) )
1608 return FALSE;
1609
1610 GDALRasterBand *srcband = poSource->GetBand();
1611 if( srcband == nullptr )
1612 return FALSE;
1613 if( srcband->GetDataset() == nullptr )
1614 return FALSE;
1615 if( srcband->GetDataset()->GetRasterCount() <= iBand )
1616 return FALSE;
1617 if( srcband->GetDataset()->GetRasterBand(iBand + 1) != srcband )
1618 return FALSE;
1619 if( osResampling.compare(poSource->GetResampling()) != 0 )
1620 return FALSE;
1621 }
1622 }
1623 }
1624
1625 return nSources != 0;
1626 }
1627
1628
1629 /************************************************************************/
1630 /* ExpandProxyBands() */
1631 /************************************************************************/
1632 /* In ProxyPoolDatasets, by default only one band is initialized. When using
1633 * VRTDataset::IRasterIO and CheckCompatibleForDatasetIO is True, we need to have
1634 * all bands initialized (but only for the last band in the VRTDataset). This function
1635 * assumes CheckCompatibleForDatasetIO() has already been run and returned successful.
1636 */
ExpandProxyBands()1637 void VRTDataset::ExpandProxyBands()
1638 {
1639 VRTSourcedRasterBand * poLastBand = static_cast<VRTSourcedRasterBand*>(papoBands[nBands - 1]);
1640
1641 CPLAssert(poLastBand != nullptr); // CheckCompatibleForDatasetIO()
1642
1643 int nSources = poLastBand->nSources;
1644
1645 for (int iSource = 0; iSource < nSources; iSource++)
1646 {
1647 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(poLastBand->papoSources[iSource]);
1648
1649 CPLAssert(poSource != nullptr); // CheckCompatibleForDatasetIO()
1650
1651 GDALProxyPoolDataset * dataset = dynamic_cast<GDALProxyPoolDataset *>(poSource->GetBand()->GetDataset());
1652
1653 if (dataset == nullptr)
1654 {
1655 continue; // only GDALProxyPoolDataset needs to be expanded
1656 }
1657
1658 if (dataset->GetBands()[0] != nullptr)
1659 {
1660 continue; // first band already set, so just assume all the others are set as well
1661 }
1662
1663 for (int iBand = 1; iBand <= nBands - 1; iBand++ )
1664 {
1665 VRTSourcedRasterBand * srcband = static_cast<VRTSourcedRasterBand *>(papoBands[iBand - 1]);
1666 VRTSimpleSource* src = static_cast<VRTSimpleSource *>(srcband->papoSources[iSource]);
1667 GDALRasterBand * rasterband = src->GetBand();
1668
1669 int nBlockXSize, nBlockYSize;
1670
1671 rasterband->GetBlockSize(&nBlockXSize, &nBlockYSize);
1672
1673 dataset->AddSrcBand(iBand, rasterband->GetRasterDataType(), nBlockXSize, nBlockYSize);
1674 }
1675 }
1676 }
1677
1678
1679
1680
1681 /************************************************************************/
1682 /* GetSingleSimpleSource() */
1683 /* */
1684 /* Returns a non-NULL dataset if the VRT is made of a single source */
1685 /* that is a simple source, in its full extent, and with all of its */
1686 /* bands. Basically something produced by : */
1687 /* gdal_translate src dst.vrt -of VRT (-a_srs / -a_ullr) */
1688 /************************************************************************/
1689
GetSingleSimpleSource()1690 GDALDataset* VRTDataset::GetSingleSimpleSource()
1691 {
1692 if( !CheckCompatibleForDatasetIO() )
1693 return nullptr;
1694
1695 VRTSourcedRasterBand* poVRTBand
1696 = static_cast<VRTSourcedRasterBand *>( papoBands[0] );
1697 if( poVRTBand->nSources != 1 )
1698 return nullptr;
1699
1700 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(
1701 poVRTBand->papoSources[0] );
1702
1703 GDALRasterBand* poBand = poSource->GetBand();
1704 if( poBand == nullptr )
1705 return nullptr;
1706
1707 GDALDataset* poSrcDS = poBand->GetDataset();
1708 if( poSrcDS == nullptr )
1709 return nullptr;
1710
1711 /* Check that it uses the full source dataset */
1712 double dfReqXOff = 0.0;
1713 double dfReqYOff = 0.0;
1714 double dfReqXSize = 0.0;
1715 double dfReqYSize = 0.0;
1716 int nReqXOff = 0;
1717 int nReqYOff = 0;
1718 int nReqXSize = 0;
1719 int nReqYSize = 0;
1720 int nOutXOff = 0;
1721 int nOutYOff = 0;
1722 int nOutXSize = 0;
1723 int nOutYSize = 0;
1724 if( !poSource->GetSrcDstWindow(
1725 0, 0,
1726 poSrcDS->GetRasterXSize(),
1727 poSrcDS->GetRasterYSize(),
1728 poSrcDS->GetRasterXSize(),
1729 poSrcDS->GetRasterYSize(),
1730 &dfReqXOff, &dfReqYOff,
1731 &dfReqXSize, &dfReqYSize,
1732 &nReqXOff, &nReqYOff,
1733 &nReqXSize, &nReqYSize,
1734 &nOutXOff, &nOutYOff,
1735 &nOutXSize, &nOutYSize ) )
1736 return nullptr;
1737
1738 if( nReqXOff != 0 || nReqYOff != 0 ||
1739 nReqXSize != poSrcDS->GetRasterXSize() ||
1740 nReqYSize != poSrcDS->GetRasterYSize() )
1741 return nullptr;
1742
1743 if( nOutXOff != 0 || nOutYOff != 0 ||
1744 nOutXSize != poSrcDS->GetRasterXSize() ||
1745 nOutYSize != poSrcDS->GetRasterYSize() )
1746 return nullptr;
1747
1748 return poSrcDS;
1749 }
1750
1751 /************************************************************************/
1752 /* AdviseRead() */
1753 /************************************************************************/
1754
AdviseRead(int nXOff,int nYOff,int nXSize,int nYSize,int nBufXSize,int nBufYSize,GDALDataType eDT,int nBandCount,int * panBandList,char ** papszOptions)1755 CPLErr VRTDataset::AdviseRead( int nXOff, int nYOff, int nXSize, int nYSize,
1756 int nBufXSize, int nBufYSize,
1757 GDALDataType eDT,
1758 int nBandCount, int *panBandList,
1759 char **papszOptions )
1760 {
1761 if( !CheckCompatibleForDatasetIO() )
1762 return CE_None;
1763
1764 VRTSourcedRasterBand* poVRTBand
1765 = static_cast<VRTSourcedRasterBand *>( papoBands[0] );
1766 if( poVRTBand->nSources != 1 )
1767 return CE_None;
1768
1769 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(
1770 poVRTBand->papoSources[0] );
1771
1772 GDALRasterBand* poBand = poSource->GetBand();
1773 if( poBand == nullptr )
1774 return CE_None;
1775
1776 GDALDataset* poSrcDS = poBand->GetDataset();
1777 if( poSrcDS == nullptr )
1778 return CE_None;
1779
1780 /* Find source window and buffer size */
1781 double dfReqXOff = 0.0;
1782 double dfReqYOff = 0.0;
1783 double dfReqXSize = 0.0;
1784 double dfReqYSize = 0.0;
1785 int nReqXOff = 0;
1786 int nReqYOff = 0;
1787 int nReqXSize = 0;
1788 int nReqYSize = 0;
1789 int nOutXOff = 0;
1790 int nOutYOff = 0;
1791 int nOutXSize = 0;
1792 int nOutYSize = 0;
1793 if( !poSource->GetSrcDstWindow(
1794 nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1795 &dfReqXOff, &dfReqYOff,
1796 &dfReqXSize, &dfReqYSize,
1797 &nReqXOff, &nReqYOff,
1798 &nReqXSize, &nReqYSize,
1799 &nOutXOff, &nOutYOff,
1800 &nOutXSize, &nOutYSize ) )
1801 return CE_None;
1802
1803 return poSrcDS->AdviseRead(nReqXOff, nReqYOff, nReqXSize, nReqYSize,
1804 nOutXSize, nOutYSize,
1805 eDT, nBandCount, panBandList, papszOptions);
1806 }
1807
1808 /************************************************************************/
1809 /* IRasterIO() */
1810 /************************************************************************/
1811
IRasterIO(GDALRWFlag eRWFlag,int nXOff,int nYOff,int nXSize,int nYSize,void * pData,int nBufXSize,int nBufYSize,GDALDataType eBufType,int nBandCount,int * panBandMap,GSpacing nPixelSpace,GSpacing nLineSpace,GSpacing nBandSpace,GDALRasterIOExtraArg * psExtraArg)1812 CPLErr VRTDataset::IRasterIO( GDALRWFlag eRWFlag,
1813 int nXOff, int nYOff, int nXSize, int nYSize,
1814 void * pData, int nBufXSize, int nBufYSize,
1815 GDALDataType eBufType,
1816 int nBandCount, int *panBandMap,
1817 GSpacing nPixelSpace, GSpacing nLineSpace,
1818 GSpacing nBandSpace,
1819 GDALRasterIOExtraArg* psExtraArg )
1820 {
1821 // It may be valid to recurse one when dealing with a subsampled request
1822 if( m_nRecursionCounter > 1 )
1823 {
1824 CPLError(
1825 CE_Failure, CPLE_AppDefined,
1826 "VRTDataset::IRasterIO() called recursively on the "
1827 "same dataset. It looks like the VRT is referencing itself." );
1828 return CE_Failure;
1829 }
1830
1831 m_nRecursionCounter ++;
1832
1833 bool bLocalCompatibleForDatasetIO = CPL_TO_BOOL(CheckCompatibleForDatasetIO());
1834 if( bLocalCompatibleForDatasetIO && eRWFlag == GF_Read &&
1835 (nBufXSize < nXSize || nBufYSize < nYSize) && m_apoOverviews.empty() )
1836 {
1837 int bTried = FALSE;
1838 const CPLErr eErr = TryOverviewRasterIO( eRWFlag,
1839 nXOff, nYOff, nXSize, nYSize,
1840 pData, nBufXSize, nBufYSize,
1841 eBufType,
1842 nBandCount, panBandMap,
1843 nPixelSpace, nLineSpace,
1844 nBandSpace,
1845 psExtraArg,
1846 &bTried );
1847
1848 if( bTried )
1849 {
1850 m_nRecursionCounter --;
1851 return eErr;
1852 }
1853
1854 for(int iBand = 0; iBand < nBands; iBand++)
1855 {
1856 VRTSourcedRasterBand* poBand
1857 = static_cast<VRTSourcedRasterBand *>( papoBands[iBand] );
1858
1859 // If there are overviews, let VRTSourcedRasterBand::IRasterIO()
1860 // do the job.
1861 if( poBand->GetOverviewCount() != 0 )
1862 {
1863 bLocalCompatibleForDatasetIO = false;
1864 break;
1865 }
1866 }
1867 }
1868
1869 // If resampling with non-nearest neighbour, we need to be careful
1870 // if the VRT band exposes a nodata value, but the sources do not have it
1871 if( bLocalCompatibleForDatasetIO && eRWFlag == GF_Read &&
1872 (nXSize != nBufXSize || nYSize != nBufYSize) &&
1873 psExtraArg->eResampleAlg != GRIORA_NearestNeighbour )
1874 {
1875 for( int iBandIndex=0; iBandIndex<nBandCount; iBandIndex++ )
1876 {
1877 VRTSourcedRasterBand* poBand =
1878 static_cast<VRTSourcedRasterBand*>(
1879 GetRasterBand(panBandMap[iBandIndex]) );
1880 int bHasNoData = FALSE;
1881 const double dfNoDataValue = poBand->GetNoDataValue(&bHasNoData);
1882 if( bHasNoData )
1883 {
1884 for( int i = 0; i < poBand->nSources; i++ )
1885 {
1886 VRTSimpleSource* poSource
1887 = static_cast<VRTSimpleSource *>(
1888 poBand->papoSources[i] );
1889 int bSrcHasNoData = FALSE;
1890 const double dfSrcNoData
1891 = poSource->GetBand()->GetNoDataValue(&bSrcHasNoData);
1892 if( !bSrcHasNoData || dfSrcNoData != dfNoDataValue )
1893 {
1894 bLocalCompatibleForDatasetIO = false;
1895 break;
1896 }
1897 }
1898 if( !bLocalCompatibleForDatasetIO )
1899 break;
1900 }
1901 }
1902 }
1903
1904 if( bLocalCompatibleForDatasetIO && eRWFlag == GF_Read )
1905 {
1906
1907 // Make sure the expand the last band before using them below
1908 ExpandProxyBands();
1909
1910 for(int iBandIndex=0; iBandIndex<nBandCount; iBandIndex++)
1911 {
1912 VRTSourcedRasterBand* poBand
1913 = static_cast<VRTSourcedRasterBand *>(
1914 GetRasterBand( panBandMap[iBandIndex] ) );
1915
1916 /* Dirty little trick to initialize the buffer without doing */
1917 /* any real I/O */
1918 const int nSavedSources = poBand->nSources;
1919 poBand->nSources = 0;
1920
1921 GByte *pabyBandData
1922 = static_cast<GByte *>( pData ) + iBandIndex * nBandSpace;
1923
1924 poBand->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
1925 pabyBandData, nBufXSize, nBufYSize,
1926 eBufType,
1927 nPixelSpace, nLineSpace, psExtraArg);
1928
1929 poBand->nSources = nSavedSources;
1930 }
1931
1932 CPLErr eErr = CE_None;
1933 GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
1934 void *pProgressDataGlobal = psExtraArg->pProgressData;
1935
1936 // Use the last band, because when sources reference a GDALProxyDataset,
1937 // they don't necessary instantiate all underlying rasterbands.
1938 VRTSourcedRasterBand* poBand = static_cast<VRTSourcedRasterBand *>(
1939 papoBands[nBands - 1] );
1940 for( int iSource = 0;
1941 eErr == CE_None && iSource < poBand->nSources;
1942 iSource++ )
1943 {
1944 psExtraArg->pfnProgress = GDALScaledProgress;
1945 psExtraArg->pProgressData =
1946 GDALCreateScaledProgress(
1947 1.0 * iSource / poBand->nSources,
1948 1.0 * (iSource + 1) / poBand->nSources,
1949 pfnProgressGlobal,
1950 pProgressDataGlobal );
1951
1952 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(
1953 poBand->papoSources[iSource] );
1954
1955 eErr = poSource->DatasetRasterIO( poBand->GetRasterDataType(),
1956 nXOff, nYOff, nXSize, nYSize,
1957 pData, nBufXSize, nBufYSize,
1958 eBufType,
1959 nBandCount, panBandMap,
1960 nPixelSpace, nLineSpace,
1961 nBandSpace,
1962 psExtraArg );
1963
1964 GDALDestroyScaledProgress( psExtraArg->pProgressData );
1965 }
1966
1967 psExtraArg->pfnProgress = pfnProgressGlobal;
1968 psExtraArg->pProgressData = pProgressDataGlobal;
1969
1970 m_nRecursionCounter --;
1971 return eErr;
1972 }
1973
1974 CPLErr eErr;
1975 if( eRWFlag == GF_Read &&
1976 psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
1977 nBufXSize < nXSize && nBufYSize < nYSize && nBandCount > 1 )
1978 {
1979 // Force going through VRTSourcedRasterBand::IRasterIO(), otherwise
1980 // GDALDataset::IRasterIOResampled() would be used without source
1981 // overviews being potentially used.
1982 eErr = GDALDataset::BandBasedRasterIO(
1983 eRWFlag, nXOff, nYOff, nXSize, nYSize,
1984 pData, nBufXSize, nBufYSize,
1985 eBufType,
1986 nBandCount, panBandMap,
1987 nPixelSpace, nLineSpace, nBandSpace,
1988 psExtraArg );
1989 }
1990 else
1991 {
1992 eErr = GDALDataset::IRasterIO( eRWFlag, nXOff, nYOff, nXSize, nYSize,
1993 pData, nBufXSize, nBufYSize,
1994 eBufType,
1995 nBandCount, panBandMap,
1996 nPixelSpace, nLineSpace, nBandSpace,
1997 psExtraArg );
1998 }
1999 m_nRecursionCounter --;
2000 return eErr;
2001 }
2002
2003 /************************************************************************/
2004 /* UnsetPreservedRelativeFilenames() */
2005 /************************************************************************/
2006
UnsetPreservedRelativeFilenames()2007 void VRTDataset::UnsetPreservedRelativeFilenames()
2008 {
2009 for(int iBand = 0; iBand < nBands; iBand++)
2010 {
2011 if( !static_cast<VRTRasterBand *>(
2012 papoBands[iBand] )->IsSourcedRasterBand() )
2013 continue;
2014
2015 VRTSourcedRasterBand* poBand
2016 = static_cast<VRTSourcedRasterBand *>( papoBands[iBand] );
2017 const int nSources = poBand->nSources;
2018 VRTSource** papoSources = poBand->papoSources;
2019 for(int iSource = 0; iSource < nSources; iSource++)
2020 {
2021 if( !papoSources[iSource]->IsSimpleSource() )
2022 continue;
2023
2024 VRTSimpleSource* poSource = static_cast<VRTSimpleSource *>(
2025 papoSources[iSource] );
2026 poSource->UnsetPreservedRelativeFilenames();
2027 }
2028 }
2029 }
2030
2031 /************************************************************************/
2032 /* BuildVirtualOverviews() */
2033 /************************************************************************/
2034
CheckBandForOverview(GDALRasterBand * poBand,GDALRasterBand * & poFirstBand,int & nOverviews,std::vector<GDALDataset * > & apoOverviewsBak)2035 static bool CheckBandForOverview(GDALRasterBand* poBand,
2036 GDALRasterBand*& poFirstBand,
2037 int& nOverviews,
2038 std::vector<GDALDataset*>& apoOverviewsBak)
2039 {
2040 if( !cpl::down_cast<VRTRasterBand *>(poBand)->IsSourcedRasterBand())
2041 return false;
2042
2043 VRTSourcedRasterBand* poVRTBand
2044 = cpl::down_cast<VRTSourcedRasterBand *>(poBand);
2045 if( poVRTBand->nSources != 1 )
2046 return false;
2047 if( !poVRTBand->papoSources[0]->IsSimpleSource() )
2048 return false;
2049
2050 VRTSimpleSource* poSource
2051 = cpl::down_cast<VRTSimpleSource *>( poVRTBand->papoSources[0] );
2052 if( !EQUAL(poSource->GetType(), "SimpleSource") &&
2053 !EQUAL(poSource->GetType(), "ComplexSource") )
2054 return false;
2055 GDALRasterBand* poSrcBand =
2056 poBand->GetBand() == 0 ? poSource->GetMaskBandMainBand() : poSource->GetBand();
2057 if( poSrcBand == nullptr )
2058 return false;
2059
2060 // To prevent recursion
2061 apoOverviewsBak.push_back(nullptr);
2062 const int nOvrCount = poSrcBand->GetOverviewCount();
2063 apoOverviewsBak.resize(0);
2064
2065 if( nOvrCount == 0 )
2066 return false;
2067 if( poFirstBand == nullptr )
2068 {
2069 if( poSrcBand->GetXSize() == 0 || poSrcBand->GetYSize() == 0 )
2070 return false;
2071 poFirstBand = poSrcBand;
2072 nOverviews = nOvrCount;
2073 }
2074 else if( nOvrCount < nOverviews )
2075 nOverviews = nOvrCount;
2076 return true;
2077 }
2078
2079
BuildVirtualOverviews()2080 void VRTDataset::BuildVirtualOverviews()
2081 {
2082 // Currently we expose virtual overviews only if the dataset is made of
2083 // a single SimpleSource/ComplexSource, in each band.
2084 // And if the underlying sources have overviews of course
2085 if( !m_apoOverviews.empty() || !m_apoOverviewsBak.empty() )
2086 return;
2087
2088 int nOverviews = 0;
2089 GDALRasterBand* poFirstBand = nullptr;
2090
2091 for( int iBand = 0; iBand < nBands; iBand++ )
2092 {
2093 if( !CheckBandForOverview(papoBands[iBand], poFirstBand, nOverviews, m_apoOverviewsBak) )
2094 return;
2095 }
2096
2097 if( m_poMaskBand )
2098 {
2099 if( !CheckBandForOverview(m_poMaskBand, poFirstBand, nOverviews, m_apoOverviewsBak) )
2100 return;
2101 }
2102 if( poFirstBand == nullptr )
2103 {
2104 // to make cppcheck happy
2105 CPLAssert(false);
2106 return;
2107 }
2108
2109 VRTSourcedRasterBand* l_poVRTBand
2110 = cpl::down_cast<VRTSourcedRasterBand *>(papoBands[0]);
2111 VRTSimpleSource* poSource
2112 = cpl::down_cast<VRTSimpleSource *>( l_poVRTBand->papoSources[0] );
2113 const double dfDstToSrcXRatio = poSource->m_dfDstXSize / poSource->m_dfSrcXSize;
2114 const double dfDstToSrcYRatio = poSource->m_dfDstYSize / poSource->m_dfSrcYSize;
2115
2116 for( int j = 0; j < nOverviews; j++)
2117 {
2118 auto poOvrBand = poFirstBand->GetOverview(j);
2119 if( !poOvrBand )
2120 return;
2121 const double dfXRatio = static_cast<double>(
2122 poOvrBand->GetXSize() ) / poFirstBand->GetXSize();
2123 const double dfYRatio = static_cast<double>(
2124 poOvrBand->GetYSize() ) / poFirstBand->GetYSize();
2125 if( dfXRatio >= dfDstToSrcXRatio ||
2126 dfYRatio >= dfDstToSrcYRatio )
2127 {
2128 continue;
2129 }
2130 const int nOvrXSize = static_cast<int>(0.5 + nRasterXSize * dfXRatio);
2131 const int nOvrYSize = static_cast<int>(0.5 + nRasterYSize * dfYRatio);
2132 if( nOvrXSize < 128 || nOvrYSize < 128 )
2133 break;
2134 VRTDataset* poOvrVDS = new VRTDataset(nOvrXSize, nOvrYSize);
2135 m_apoOverviews.push_back(poOvrVDS);
2136
2137 const auto CreateOverviewBand =
2138 [&poOvrVDS, nOvrXSize, nOvrYSize, dfXRatio, dfYRatio]
2139 (VRTSourcedRasterBand* poVRTBand)
2140 {
2141 VRTSourcedRasterBand* poOvrVRTBand = new VRTSourcedRasterBand(
2142 poOvrVDS,
2143 poVRTBand->GetBand(),
2144 poVRTBand->GetRasterDataType(),
2145 nOvrXSize, nOvrYSize);
2146 poOvrVRTBand->CopyCommonInfoFrom(poVRTBand);
2147 poOvrVRTBand->m_bNoDataValueSet = poVRTBand->m_bNoDataValueSet;
2148 poOvrVRTBand->m_dfNoDataValue = poVRTBand->m_dfNoDataValue;
2149 poOvrVRTBand->m_bHideNoDataValue = poVRTBand->m_bHideNoDataValue;
2150
2151 VRTSimpleSource* poSrcSource = cpl::down_cast<VRTSimpleSource *>(
2152 poVRTBand->papoSources[0] );
2153 VRTSimpleSource* poNewSource = nullptr;
2154 if( EQUAL(poSrcSource->GetType(), "SimpleSource") )
2155 {
2156 poNewSource =
2157 new VRTSimpleSource(poSrcSource, dfXRatio, dfYRatio);
2158 }
2159 else if( EQUAL(poSrcSource->GetType(), "ComplexSource") )
2160 {
2161 poNewSource = new VRTComplexSource(
2162 cpl::down_cast<VRTComplexSource *>( poSrcSource ),
2163 dfXRatio, dfYRatio );
2164 }
2165 else
2166 {
2167 CPLAssert(false);
2168 }
2169 if( poNewSource )
2170 {
2171 auto poNewSourceBand = poVRTBand->GetBand() == 0 ?
2172 poNewSource->GetMaskBandMainBand() :
2173 poNewSource->GetBand();
2174 CPLAssert(poNewSourceBand);
2175 auto poNewSourceBandDS = poNewSourceBand->GetDataset();
2176 if( poNewSourceBandDS )
2177 poNewSourceBandDS->Reference();
2178 poOvrVRTBand->AddSource(poNewSource);
2179 }
2180
2181 return poOvrVRTBand;
2182 };
2183
2184 for( int i = 0; i < nBands; i++ )
2185 {
2186 VRTSourcedRasterBand* poSrcBand
2187 = cpl::down_cast<VRTSourcedRasterBand *>(GetRasterBand(i+1));
2188 auto poOvrVRTBand = CreateOverviewBand(poSrcBand);
2189 poOvrVDS->SetBand( poOvrVDS->GetRasterCount() + 1, poOvrVRTBand );
2190
2191 }
2192
2193 if( m_poMaskBand )
2194 {
2195 VRTSourcedRasterBand* poSrcBand
2196 = cpl::down_cast<VRTSourcedRasterBand *>(m_poMaskBand);
2197 auto poOvrVRTBand = CreateOverviewBand(poSrcBand);
2198 poOvrVDS->SetMaskBand(poOvrVRTBand);
2199 }
2200 }
2201 }
2202
2203 /************************************************************************/
2204 /* AddVirtualOverview() */
2205 /************************************************************************/
2206
AddVirtualOverview(int nOvFactor,const char * pszResampling)2207 bool VRTDataset::AddVirtualOverview(int nOvFactor, const char* pszResampling)
2208 {
2209 if( nRasterXSize / nOvFactor == 0 ||
2210 nRasterYSize / nOvFactor == 0 )
2211 {
2212 return false;
2213 }
2214
2215 CPLStringList argv;
2216 argv.AddString("-of");
2217 argv.AddString("VRT");
2218 argv.AddString("-outsize");
2219 argv.AddString(CPLSPrintf("%d", nRasterXSize / nOvFactor));
2220 argv.AddString(CPLSPrintf("%d", nRasterYSize / nOvFactor));
2221 argv.AddString("-r");
2222 argv.AddString(pszResampling);
2223
2224 GDALTranslateOptions* psOptions = GDALTranslateOptionsNew(argv.List(), nullptr);
2225
2226 // Add a dummy overview so that BuildVirtualOverviews() doesn't trigger
2227 m_apoOverviews.push_back(nullptr);
2228 CPLAssert(m_bCanTakeRef);
2229 m_bCanTakeRef = false; // we don't want hOverviewDS to take a reference on ourselves.
2230 GDALDatasetH hOverviewDS = GDALTranslate("", GDALDataset::ToHandle(this),
2231 psOptions, nullptr);
2232 m_bCanTakeRef = true;
2233 m_apoOverviews.resize(m_apoOverviews.size() - 1);
2234
2235 GDALTranslateOptionsFree( psOptions );
2236 if( hOverviewDS == nullptr )
2237 return false;
2238
2239 m_anOverviewFactors.push_back(nOvFactor);
2240 m_apoOverviews.push_back(GDALDataset::FromHandle(hOverviewDS));
2241 return true;
2242 }
2243
2244 /************************************************************************/
2245 /* IBuildOverviews() */
2246 /************************************************************************/
2247
2248 CPLErr
IBuildOverviews(const char * pszResampling,int nOverviews,int * panOverviewList,int nListBands,int * panBandList,GDALProgressFunc pfnProgress,void * pProgressData)2249 VRTDataset::IBuildOverviews( const char *pszResampling,
2250 int nOverviews,
2251 int *panOverviewList,
2252 int nListBands,
2253 int *panBandList,
2254 GDALProgressFunc pfnProgress,
2255 void * pProgressData )
2256 {
2257 if( CPLTestBool(CPLGetConfigOption("VRT_VIRTUAL_OVERVIEWS", "NO")) )
2258 {
2259 SetNeedsFlush();
2260 if( nOverviews == 0 ||
2261 (!m_apoOverviews.empty() && m_anOverviewFactors.empty()) )
2262 {
2263 m_anOverviewFactors.clear();
2264 m_apoOverviewsBak.insert(m_apoOverviewsBak.end(),
2265 m_apoOverviews.begin(),
2266 m_apoOverviews.end());
2267 m_apoOverviews.clear();
2268 }
2269 m_osOverviewResampling = pszResampling;
2270 for(int i = 0; i < nOverviews; i++ )
2271 {
2272 if( std::find(m_anOverviewFactors.begin(),
2273 m_anOverviewFactors.end(),
2274 panOverviewList[i]) == m_anOverviewFactors.end() )
2275 {
2276 AddVirtualOverview(panOverviewList[i], pszResampling);
2277 }
2278 }
2279 return CE_None;
2280 }
2281
2282 if( !oOvManager.IsInitialized() )
2283 {
2284 const char* pszDesc = GetDescription();
2285 if( pszDesc[0] )
2286 {
2287 oOvManager.Initialize( this, pszDesc );
2288 }
2289 }
2290
2291 // Make implicit overviews invisible, but do not destroy them in case they
2292 // are already used. Should the client do that? Behavior might undefined
2293 // in GDAL API?
2294 if( !m_apoOverviews.empty() )
2295 {
2296 m_apoOverviewsBak.insert(m_apoOverviewsBak.end(),
2297 m_apoOverviews.begin(),
2298 m_apoOverviews.end());
2299 m_apoOverviews.clear();
2300 }
2301 else
2302 {
2303 // Add a dummy overview so that GDALDataset::IBuildOverviews()
2304 // doesn't manage to get a virtual implicit overview.
2305 m_apoOverviews.push_back(nullptr);
2306 }
2307
2308 CPLErr eErr = GDALDataset::IBuildOverviews( pszResampling,
2309 nOverviews,
2310 panOverviewList,
2311 nListBands,
2312 panBandList,
2313 pfnProgress,
2314 pProgressData );
2315
2316 m_apoOverviews.clear();
2317 return eErr;
2318 }
2319
2320 /*! @endcond */
2321