Line data Source code
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 <cmath>
40 : #include <set>
41 : #include <typeinfo>
42 : #include "gdal_proxy.h"
43 :
44 : /*! @cond Doxygen_Suppress */
45 :
46 : #define VRT_PROTOCOL_PREFIX "vrt://"
47 :
48 : /************************************************************************/
49 : /* VRTDataset() */
50 : /************************************************************************/
51 :
52 3202 : VRTDataset::VRTDataset(int nXSize, int nYSize, int nBlockXSize, int nBlockYSize)
53 : {
54 3202 : nRasterXSize = nXSize;
55 3202 : nRasterYSize = nYSize;
56 :
57 3202 : m_adfGeoTransform[0] = 0.0;
58 3202 : m_adfGeoTransform[1] = 1.0;
59 3202 : m_adfGeoTransform[2] = 0.0;
60 3202 : m_adfGeoTransform[3] = 0.0;
61 3202 : m_adfGeoTransform[4] = 0.0;
62 3202 : m_adfGeoTransform[5] = 1.0;
63 3202 : m_bBlockSizeSpecified = nBlockXSize > 0 && nBlockYSize > 0;
64 3202 : m_nBlockXSize = nBlockXSize > 0 ? nBlockXSize : std::min(128, nXSize);
65 3202 : m_nBlockYSize = nBlockYSize > 0 ? nBlockYSize : std::min(128, nYSize);
66 :
67 3202 : GDALRegister_VRT();
68 :
69 3202 : poDriver = static_cast<GDALDriver *>(GDALGetDriverByName("VRT"));
70 3202 : }
71 :
72 : /*! @endcond */
73 :
74 : /************************************************************************/
75 : /* VRTCreate() */
76 : /************************************************************************/
77 :
78 : /**
79 : * @see VRTDataset::VRTDataset()
80 : */
81 :
82 1134 : VRTDatasetH CPL_STDCALL VRTCreate(int nXSize, int nYSize)
83 :
84 : {
85 1134 : auto poDS = new VRTDataset(nXSize, nYSize);
86 1134 : poDS->eAccess = GA_Update;
87 1134 : return poDS;
88 : }
89 :
90 : /*! @cond Doxygen_Suppress */
91 :
92 : /************************************************************************/
93 : /* ~VRTDataset() */
94 : /************************************************************************/
95 :
96 5847 : VRTDataset::~VRTDataset()
97 :
98 : {
99 3202 : VRTDataset::FlushCache(true);
100 3202 : CPLFree(m_pszVRTPath);
101 :
102 3202 : delete m_poMaskBand;
103 :
104 3245 : for (size_t i = 0; i < m_apoOverviews.size(); i++)
105 43 : delete m_apoOverviews[i];
106 3209 : for (size_t i = 0; i < m_apoOverviewsBak.size(); i++)
107 7 : delete m_apoOverviewsBak[i];
108 3202 : CSLDestroy(m_papszXMLVRTMetadata);
109 5847 : }
110 :
111 : /************************************************************************/
112 : /* FlushCache() */
113 : /************************************************************************/
114 :
115 3544 : CPLErr VRTDataset::FlushCache(bool bAtClosing)
116 :
117 : {
118 3544 : if (m_poRootGroup)
119 311 : return m_poRootGroup->Serialize() ? CE_None : CE_Failure;
120 : else
121 3233 : return VRTFlushCacheStruct<VRTDataset>::FlushCache(*this, bAtClosing);
122 : }
123 :
124 : /************************************************************************/
125 : /* FlushCache() */
126 : /************************************************************************/
127 :
128 700 : CPLErr VRTWarpedDataset::FlushCache(bool bAtClosing)
129 :
130 : {
131 700 : return VRTFlushCacheStruct<VRTWarpedDataset>::FlushCache(*this, bAtClosing);
132 : }
133 :
134 : /************************************************************************/
135 : /* FlushCache() */
136 : /************************************************************************/
137 :
138 154 : CPLErr VRTPansharpenedDataset::FlushCache(bool bAtClosing)
139 :
140 : {
141 154 : return VRTFlushCacheStruct<VRTPansharpenedDataset>::FlushCache(*this,
142 154 : bAtClosing);
143 : }
144 :
145 : /************************************************************************/
146 : /* FlushCache() */
147 : /************************************************************************/
148 :
149 96 : CPLErr VRTProcessedDataset::FlushCache(bool bAtClosing)
150 :
151 : {
152 96 : return VRTFlushCacheStruct<VRTProcessedDataset>::FlushCache(*this,
153 96 : bAtClosing);
154 : }
155 :
156 : /************************************************************************/
157 : /* FlushCache() */
158 : /************************************************************************/
159 :
160 : template <class T>
161 4183 : CPLErr VRTFlushCacheStruct<T>::FlushCache(T &obj, bool bAtClosing)
162 : {
163 4183 : CPLErr eErr = obj.GDALDataset::FlushCache(bAtClosing);
164 :
165 4183 : if (!obj.m_bNeedsFlush || !obj.m_bWritable)
166 2165 : return eErr;
167 :
168 : // We don't write to disk if there is no filename. This is a
169 : // memory only dataset.
170 2410 : if (strlen(obj.GetDescription()) == 0 ||
171 392 : STARTS_WITH_CI(obj.GetDescription(), "<VRTDataset"))
172 1637 : return eErr;
173 :
174 381 : obj.m_bNeedsFlush = false;
175 :
176 : // Serialize XML representation to disk
177 381 : const std::string osVRTPath(CPLGetPath(obj.GetDescription()));
178 381 : CPLXMLNode *psDSTree = obj.T::SerializeToXML(osVRTPath.c_str());
179 381 : if (!CPLSerializeXMLTreeToFile(psDSTree, obj.GetDescription()))
180 13 : eErr = CE_Failure;
181 381 : CPLDestroyXMLNode(psDSTree);
182 381 : return eErr;
183 : }
184 :
185 : /************************************************************************/
186 : /* GetMetadata() */
187 : /************************************************************************/
188 :
189 6102 : char **VRTDataset::GetMetadata(const char *pszDomain)
190 : {
191 6102 : if (pszDomain != nullptr && EQUAL(pszDomain, "xml:VRT"))
192 : {
193 : /* ------------------------------------------------------------------ */
194 : /* Convert tree to a single block of XML text. */
195 : /* ------------------------------------------------------------------ */
196 40 : const char *pszDescription = GetDescription();
197 40 : char *l_pszVRTPath = CPLStrdup(
198 40 : pszDescription[0] && !STARTS_WITH(pszDescription, "<VRTDataset")
199 14 : ? CPLGetPath(pszDescription)
200 : : "");
201 40 : CPLXMLNode *psDSTree = SerializeToXML(l_pszVRTPath);
202 40 : char *pszXML = CPLSerializeXMLTree(psDSTree);
203 :
204 40 : CPLDestroyXMLNode(psDSTree);
205 :
206 40 : CPLFree(l_pszVRTPath);
207 :
208 40 : CSLDestroy(m_papszXMLVRTMetadata);
209 40 : m_papszXMLVRTMetadata =
210 40 : static_cast<char **>(CPLMalloc(2 * sizeof(char *)));
211 40 : m_papszXMLVRTMetadata[0] = pszXML;
212 40 : m_papszXMLVRTMetadata[1] = nullptr;
213 40 : return m_papszXMLVRTMetadata;
214 : }
215 :
216 6062 : return GDALDataset::GetMetadata(pszDomain);
217 : }
218 :
219 : /*! @endcond */
220 :
221 : /************************************************************************/
222 : /* VRTFlushCache(bool bAtClosing) */
223 : /************************************************************************/
224 :
225 : /**
226 : * @see VRTDataset::FlushCache(bool bAtClosing)
227 : */
228 :
229 0 : void CPL_STDCALL VRTFlushCache(VRTDatasetH hDataset)
230 : {
231 0 : VALIDATE_POINTER0(hDataset, "VRTFlushCache");
232 :
233 0 : static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))
234 0 : ->FlushCache(false);
235 : }
236 :
237 : /*! @cond Doxygen_Suppress */
238 :
239 : /************************************************************************/
240 : /* SerializeToXML() */
241 : /************************************************************************/
242 :
243 524 : CPLXMLNode *VRTDataset::SerializeToXML(const char *pszVRTPathIn)
244 :
245 : {
246 524 : if (m_poRootGroup)
247 71 : return m_poRootGroup->SerializeToXML(pszVRTPathIn);
248 :
249 : /* -------------------------------------------------------------------- */
250 : /* Setup root node and attributes. */
251 : /* -------------------------------------------------------------------- */
252 453 : CPLXMLNode *psDSTree = CPLCreateXMLNode(nullptr, CXT_Element, "VRTDataset");
253 :
254 453 : char szNumber[128] = {'\0'};
255 453 : snprintf(szNumber, sizeof(szNumber), "%d", GetRasterXSize());
256 453 : CPLSetXMLValue(psDSTree, "#rasterXSize", szNumber);
257 :
258 453 : snprintf(szNumber, sizeof(szNumber), "%d", GetRasterYSize());
259 453 : CPLSetXMLValue(psDSTree, "#rasterYSize", szNumber);
260 :
261 : /* -------------------------------------------------------------------- */
262 : /* SRS */
263 : /* -------------------------------------------------------------------- */
264 453 : if (m_poSRS && !m_poSRS->IsEmpty())
265 : {
266 345 : char *pszWKT = nullptr;
267 345 : m_poSRS->exportToWkt(&pszWKT);
268 : CPLXMLNode *psSRSNode =
269 345 : CPLCreateXMLElementAndValue(psDSTree, "SRS", pszWKT);
270 345 : CPLFree(pszWKT);
271 345 : const auto &mapping = m_poSRS->GetDataAxisToSRSAxisMapping();
272 690 : CPLString osMapping;
273 1037 : for (size_t i = 0; i < mapping.size(); ++i)
274 : {
275 692 : if (!osMapping.empty())
276 347 : osMapping += ",";
277 692 : osMapping += CPLSPrintf("%d", mapping[i]);
278 : }
279 345 : CPLAddXMLAttributeAndValue(psSRSNode, "dataAxisToSRSAxisMapping",
280 : osMapping.c_str());
281 345 : const double dfCoordinateEpoch = m_poSRS->GetCoordinateEpoch();
282 345 : if (dfCoordinateEpoch > 0)
283 : {
284 2 : std::string osCoordinateEpoch = CPLSPrintf("%f", dfCoordinateEpoch);
285 1 : if (osCoordinateEpoch.find('.') != std::string::npos)
286 : {
287 6 : while (osCoordinateEpoch.back() == '0')
288 5 : osCoordinateEpoch.resize(osCoordinateEpoch.size() - 1);
289 : }
290 1 : CPLAddXMLAttributeAndValue(psSRSNode, "coordinateEpoch",
291 : osCoordinateEpoch.c_str());
292 : }
293 : }
294 :
295 : /* -------------------------------------------------------------------- */
296 : /* Geotransform. */
297 : /* -------------------------------------------------------------------- */
298 453 : if (m_bGeoTransformSet)
299 : {
300 390 : CPLSetXMLValue(
301 : psDSTree, "GeoTransform",
302 : CPLSPrintf("%24.16e,%24.16e,%24.16e,%24.16e,%24.16e,%24.16e",
303 : m_adfGeoTransform[0], m_adfGeoTransform[1],
304 : m_adfGeoTransform[2], m_adfGeoTransform[3],
305 : m_adfGeoTransform[4], m_adfGeoTransform[5]));
306 : }
307 :
308 : /* -------------------------------------------------------------------- */
309 : /* Metadata */
310 : /* -------------------------------------------------------------------- */
311 453 : CPLXMLNode *psMD = oMDMD.Serialize();
312 453 : if (psMD != nullptr)
313 : {
314 297 : CPLAddXMLChild(psDSTree, psMD);
315 : }
316 :
317 : /* -------------------------------------------------------------------- */
318 : /* GCPs */
319 : /* -------------------------------------------------------------------- */
320 453 : if (!m_asGCPs.empty())
321 : {
322 4 : GDALSerializeGCPListToXML(psDSTree, m_asGCPs, m_poGCP_SRS.get());
323 : }
324 :
325 : /* -------------------------------------------------------------------- */
326 : /* Serialize bands. */
327 : /* -------------------------------------------------------------------- */
328 453 : CPLXMLNode *psLastChild = psDSTree->psChild;
329 2093 : for (; psLastChild != nullptr && psLastChild->psNext;
330 1640 : psLastChild = psLastChild->psNext)
331 : {
332 : }
333 453 : CPLAssert(psLastChild); // we have at least rasterXSize
334 453 : bool bHasWarnedAboutRAMUsage = false;
335 453 : size_t nAccRAMUsage = 0;
336 1177 : for (int iBand = 0; iBand < nBands; iBand++)
337 : {
338 : CPLXMLNode *psBandTree =
339 724 : static_cast<VRTRasterBand *>(papoBands[iBand])
340 1448 : ->SerializeToXML(pszVRTPathIn, bHasWarnedAboutRAMUsage,
341 724 : nAccRAMUsage);
342 :
343 724 : if (psBandTree != nullptr)
344 : {
345 724 : psLastChild->psNext = psBandTree;
346 724 : psLastChild = psBandTree;
347 : }
348 : }
349 :
350 : /* -------------------------------------------------------------------- */
351 : /* Serialize dataset mask band. */
352 : /* -------------------------------------------------------------------- */
353 453 : if (m_poMaskBand)
354 : {
355 32 : CPLXMLNode *psBandTree = m_poMaskBand->SerializeToXML(
356 16 : pszVRTPathIn, bHasWarnedAboutRAMUsage, nAccRAMUsage);
357 :
358 16 : if (psBandTree != nullptr)
359 : {
360 : CPLXMLNode *psMaskBandElement =
361 16 : CPLCreateXMLNode(psDSTree, CXT_Element, "MaskBand");
362 16 : CPLAddXMLChild(psMaskBandElement, psBandTree);
363 : }
364 : }
365 :
366 : /* -------------------------------------------------------------------- */
367 : /* Overview factors. */
368 : /* -------------------------------------------------------------------- */
369 453 : if (!m_anOverviewFactors.empty())
370 : {
371 8 : CPLString osOverviewList;
372 14 : for (int nOvFactor : m_anOverviewFactors)
373 : {
374 10 : if (!osOverviewList.empty())
375 6 : osOverviewList += " ";
376 10 : osOverviewList += CPLSPrintf("%d", nOvFactor);
377 : }
378 4 : CPLXMLNode *psOverviewList = CPLCreateXMLElementAndValue(
379 : psDSTree, "OverviewList", osOverviewList);
380 4 : if (!m_osOverviewResampling.empty())
381 : {
382 4 : CPLAddXMLAttributeAndValue(psOverviewList, "resampling",
383 : m_osOverviewResampling);
384 : }
385 : }
386 :
387 453 : return psDSTree;
388 : }
389 :
390 : /*! @endcond */
391 : /************************************************************************/
392 : /* VRTSerializeToXML() */
393 : /************************************************************************/
394 :
395 : /**
396 : * @see VRTDataset::SerializeToXML()
397 : */
398 :
399 0 : CPLXMLNode *CPL_STDCALL VRTSerializeToXML(VRTDatasetH hDataset,
400 : const char *pszVRTPath)
401 : {
402 0 : VALIDATE_POINTER1(hDataset, "VRTSerializeToXML", nullptr);
403 :
404 0 : return static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))
405 0 : ->SerializeToXML(pszVRTPath);
406 : }
407 :
408 : /*! @cond Doxygen_Suppress */
409 :
410 : /************************************************************************/
411 : /* InitBand() */
412 : /************************************************************************/
413 :
414 1648 : VRTRasterBand *VRTDataset::InitBand(const char *pszSubclass, int nBand,
415 : bool bAllowPansharpenedOrProcessed)
416 : {
417 1648 : VRTRasterBand *poBand = nullptr;
418 1648 : if (auto poProcessedDS = dynamic_cast<VRTProcessedDataset *>(this))
419 : {
420 2 : if (bAllowPansharpenedOrProcessed &&
421 2 : EQUAL(pszSubclass, "VRTProcessedRasterBand"))
422 : {
423 2 : poBand = new VRTProcessedRasterBand(poProcessedDS, nBand);
424 : }
425 : }
426 1646 : else if (EQUAL(pszSubclass, "VRTSourcedRasterBand"))
427 980 : poBand = new VRTSourcedRasterBand(this, nBand);
428 666 : else if (EQUAL(pszSubclass, "VRTDerivedRasterBand"))
429 162 : poBand = new VRTDerivedRasterBand(this, nBand);
430 504 : else if (EQUAL(pszSubclass, "VRTRawRasterBand"))
431 22 : poBand = new VRTRawRasterBand(this, nBand);
432 925 : else if (EQUAL(pszSubclass, "VRTWarpedRasterBand") &&
433 443 : dynamic_cast<VRTWarpedDataset *>(this) != nullptr)
434 443 : poBand = new VRTWarpedRasterBand(this, nBand);
435 39 : else if (bAllowPansharpenedOrProcessed &&
436 77 : EQUAL(pszSubclass, "VRTPansharpenedRasterBand") &&
437 38 : dynamic_cast<VRTPansharpenedDataset *>(this) != nullptr)
438 38 : poBand = new VRTPansharpenedRasterBand(this, nBand);
439 :
440 1648 : if (!poBand)
441 : {
442 1 : CPLError(CE_Failure, CPLE_AppDefined,
443 : "VRTRasterBand of unrecognized subclass '%s'.", pszSubclass);
444 : }
445 :
446 1648 : return poBand;
447 : }
448 :
449 : /************************************************************************/
450 : /* XMLInit() */
451 : /************************************************************************/
452 :
453 1375 : CPLErr VRTDataset::XMLInit(const CPLXMLNode *psTree, const char *pszVRTPathIn)
454 :
455 : {
456 1375 : if (pszVRTPathIn != nullptr)
457 957 : m_pszVRTPath = CPLStrdup(pszVRTPathIn);
458 :
459 : /* -------------------------------------------------------------------- */
460 : /* Check for an SRS node. */
461 : /* -------------------------------------------------------------------- */
462 1375 : const CPLXMLNode *psSRSNode = CPLGetXMLNode(psTree, "SRS");
463 1375 : if (psSRSNode)
464 : {
465 550 : m_poSRS.reset(new OGRSpatialReference());
466 550 : m_poSRS->SetFromUserInput(
467 : CPLGetXMLValue(psSRSNode, nullptr, ""),
468 : OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS_get());
469 : const char *pszMapping =
470 550 : CPLGetXMLValue(psSRSNode, "dataAxisToSRSAxisMapping", nullptr);
471 550 : if (pszMapping)
472 : {
473 : char **papszTokens =
474 319 : CSLTokenizeStringComplex(pszMapping, ",", FALSE, FALSE);
475 638 : std::vector<int> anMapping;
476 960 : for (int i = 0; papszTokens && papszTokens[i]; i++)
477 : {
478 641 : anMapping.push_back(atoi(papszTokens[i]));
479 : }
480 319 : CSLDestroy(papszTokens);
481 319 : m_poSRS->SetDataAxisToSRSAxisMapping(anMapping);
482 : }
483 : else
484 : {
485 231 : m_poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
486 : }
487 :
488 : const char *pszCoordinateEpoch =
489 550 : CPLGetXMLValue(psSRSNode, "coordinateEpoch", nullptr);
490 550 : if (pszCoordinateEpoch)
491 1 : m_poSRS->SetCoordinateEpoch(CPLAtof(pszCoordinateEpoch));
492 : }
493 :
494 : /* -------------------------------------------------------------------- */
495 : /* Check for a GeoTransform node. */
496 : /* -------------------------------------------------------------------- */
497 1375 : const char *pszGT = CPLGetXMLValue(psTree, "GeoTransform", "");
498 1375 : if (strlen(pszGT) > 0)
499 : {
500 : const CPLStringList aosTokens(
501 1226 : CSLTokenizeStringComplex(pszGT, ",", FALSE, FALSE));
502 613 : if (aosTokens.size() != 6)
503 : {
504 0 : CPLError(CE_Warning, CPLE_AppDefined,
505 : "GeoTransform node does not have expected six values.");
506 : }
507 : else
508 : {
509 4291 : for (int iTA = 0; iTA < 6; iTA++)
510 3678 : m_adfGeoTransform[iTA] = CPLAtof(aosTokens[iTA]);
511 613 : m_bGeoTransformSet = TRUE;
512 : }
513 : }
514 :
515 : /* -------------------------------------------------------------------- */
516 : /* Check for GCPs. */
517 : /* -------------------------------------------------------------------- */
518 1375 : if (const CPLXMLNode *psGCPList = CPLGetXMLNode(psTree, "GCPList"))
519 : {
520 51 : OGRSpatialReference *poSRS = nullptr;
521 51 : GDALDeserializeGCPListFromXML(psGCPList, m_asGCPs, &poSRS);
522 51 : m_poGCP_SRS.reset(poSRS);
523 : }
524 :
525 : /* -------------------------------------------------------------------- */
526 : /* Apply any dataset level metadata. */
527 : /* -------------------------------------------------------------------- */
528 1375 : oMDMD.XMLInit(psTree, TRUE);
529 :
530 : /* -------------------------------------------------------------------- */
531 : /* Create dataset mask band. */
532 : /* -------------------------------------------------------------------- */
533 :
534 : /* Parse dataset mask band first */
535 1375 : const CPLXMLNode *psMaskBandNode = CPLGetXMLNode(psTree, "MaskBand");
536 :
537 1375 : const CPLXMLNode *psChild = nullptr;
538 1375 : if (psMaskBandNode)
539 20 : psChild = psMaskBandNode->psChild;
540 : else
541 1355 : psChild = nullptr;
542 :
543 1375 : for (; psChild != nullptr; psChild = psChild->psNext)
544 : {
545 20 : if (psChild->eType == CXT_Element &&
546 20 : EQUAL(psChild->pszValue, "VRTRasterBand"))
547 : {
548 : const char *pszSubclass =
549 20 : CPLGetXMLValue(psChild, "subclass", "VRTSourcedRasterBand");
550 :
551 20 : VRTRasterBand *poBand = InitBand(pszSubclass, 0, false);
552 40 : if (poBand != nullptr &&
553 20 : poBand->XMLInit(psChild, pszVRTPathIn, m_oMapSharedSources) ==
554 : CE_None)
555 : {
556 20 : SetMaskBand(poBand);
557 20 : break;
558 : }
559 : else
560 : {
561 0 : delete poBand;
562 0 : return CE_Failure;
563 : }
564 : }
565 : }
566 :
567 : /* -------------------------------------------------------------------- */
568 : /* Create band information objects. */
569 : /* -------------------------------------------------------------------- */
570 1375 : int l_nBands = 0;
571 8109 : for (psChild = psTree->psChild; psChild != nullptr;
572 6734 : psChild = psChild->psNext)
573 : {
574 6765 : if (psChild->eType == CXT_Element &&
575 4314 : EQUAL(psChild->pszValue, "VRTRasterBand"))
576 : {
577 : const char *pszSubclass =
578 1628 : CPLGetXMLValue(psChild, "subclass", "VRTSourcedRasterBand");
579 1628 : if (dynamic_cast<VRTProcessedDataset *>(this) &&
580 2 : !EQUAL(pszSubclass, "VRTProcessedRasterBand"))
581 : {
582 0 : CPLError(CE_Failure, CPLE_NotSupported,
583 : "Only subClass=VRTProcessedRasterBand supported");
584 0 : return CE_Failure;
585 : }
586 :
587 1628 : VRTRasterBand *poBand = InitBand(pszSubclass, l_nBands + 1, true);
588 3255 : if (poBand != nullptr &&
589 1627 : poBand->XMLInit(psChild, pszVRTPathIn, m_oMapSharedSources) ==
590 : CE_None)
591 : {
592 1597 : l_nBands++;
593 1597 : SetBand(l_nBands, poBand);
594 : }
595 : else
596 : {
597 31 : delete poBand;
598 31 : return CE_Failure;
599 : }
600 : }
601 : }
602 :
603 1344 : if (const CPLXMLNode *psGroup = CPLGetXMLNode(psTree, "Group"))
604 : {
605 212 : const char *pszName = CPLGetXMLValue(psGroup, "name", nullptr);
606 212 : if (pszName == nullptr || !EQUAL(pszName, "/"))
607 : {
608 2 : CPLError(CE_Failure, CPLE_AppDefined,
609 : "Missing name or not equal to '/'");
610 2 : return CE_Failure;
611 : }
612 :
613 210 : m_poRootGroup = VRTGroup::Create(std::string(), "/");
614 210 : m_poRootGroup->SetIsRootGroup();
615 210 : if (!m_poRootGroup->XMLInit(m_poRootGroup, m_poRootGroup, psGroup,
616 : pszVRTPathIn))
617 : {
618 21 : return CE_Failure;
619 : }
620 : }
621 :
622 : /* -------------------------------------------------------------------- */
623 : /* Create virtual overviews. */
624 : /* -------------------------------------------------------------------- */
625 1321 : const char *pszSubClass = CPLGetXMLValue(psTree, "subClass", "");
626 1321 : if (EQUAL(pszSubClass, ""))
627 : {
628 : m_aosOverviewList =
629 1025 : CSLTokenizeString(CPLGetXMLValue(psTree, "OverviewList", ""));
630 : m_osOverviewResampling =
631 1025 : CPLGetXMLValue(psTree, "OverviewList.resampling", "");
632 : }
633 :
634 1321 : return CE_None;
635 : }
636 :
637 : /************************************************************************/
638 : /* GetGCPCount() */
639 : /************************************************************************/
640 :
641 1109 : int VRTDataset::GetGCPCount()
642 :
643 : {
644 1109 : return static_cast<int>(m_asGCPs.size());
645 : }
646 :
647 : /************************************************************************/
648 : /* GetGCPs() */
649 : /************************************************************************/
650 :
651 79 : const GDAL_GCP *VRTDataset::GetGCPs()
652 :
653 : {
654 79 : return gdal::GCP::c_ptr(m_asGCPs);
655 : }
656 :
657 : /************************************************************************/
658 : /* SetGCPs() */
659 : /************************************************************************/
660 :
661 31 : CPLErr VRTDataset::SetGCPs(int nGCPCountIn, const GDAL_GCP *pasGCPListIn,
662 : const OGRSpatialReference *poGCP_SRS)
663 :
664 : {
665 31 : m_poGCP_SRS.reset(poGCP_SRS ? poGCP_SRS->Clone() : nullptr);
666 31 : m_asGCPs = gdal::GCP::fromC(pasGCPListIn, nGCPCountIn);
667 :
668 31 : SetNeedsFlush();
669 :
670 31 : return CE_None;
671 : }
672 :
673 : /************************************************************************/
674 : /* SetSpatialRef() */
675 : /************************************************************************/
676 :
677 1123 : CPLErr VRTDataset::SetSpatialRef(const OGRSpatialReference *poSRS)
678 :
679 : {
680 1123 : m_poSRS.reset(poSRS ? poSRS->Clone() : nullptr);
681 :
682 1123 : SetNeedsFlush();
683 :
684 1123 : return CE_None;
685 : }
686 :
687 : /************************************************************************/
688 : /* SetGeoTransform() */
689 : /************************************************************************/
690 :
691 1253 : CPLErr VRTDataset::SetGeoTransform(double *padfGeoTransformIn)
692 :
693 : {
694 1253 : memcpy(m_adfGeoTransform, padfGeoTransformIn, sizeof(double) * 6);
695 1253 : m_bGeoTransformSet = TRUE;
696 :
697 1253 : SetNeedsFlush();
698 :
699 1253 : return CE_None;
700 : }
701 :
702 : /************************************************************************/
703 : /* GetGeoTransform() */
704 : /************************************************************************/
705 :
706 2943 : CPLErr VRTDataset::GetGeoTransform(double *padfGeoTransform)
707 :
708 : {
709 2943 : memcpy(padfGeoTransform, m_adfGeoTransform, sizeof(double) * 6);
710 :
711 2943 : return m_bGeoTransformSet ? CE_None : CE_Failure;
712 : }
713 :
714 : /************************************************************************/
715 : /* SetMetadata() */
716 : /************************************************************************/
717 :
718 1065 : CPLErr VRTDataset::SetMetadata(char **papszMetadata, const char *pszDomain)
719 :
720 : {
721 1065 : SetNeedsFlush();
722 :
723 1065 : return GDALDataset::SetMetadata(papszMetadata, pszDomain);
724 : }
725 :
726 : /************************************************************************/
727 : /* SetMetadataItem() */
728 : /************************************************************************/
729 :
730 865 : CPLErr VRTDataset::SetMetadataItem(const char *pszName, const char *pszValue,
731 : const char *pszDomain)
732 :
733 : {
734 865 : SetNeedsFlush();
735 :
736 865 : return GDALDataset::SetMetadataItem(pszName, pszValue, pszDomain);
737 : }
738 :
739 : /************************************************************************/
740 : /* Identify() */
741 : /************************************************************************/
742 :
743 75559 : int VRTDataset::Identify(GDALOpenInfo *poOpenInfo)
744 :
745 : {
746 75559 : if (poOpenInfo->nHeaderBytes > 20 &&
747 26378 : strstr(reinterpret_cast<const char *>(poOpenInfo->pabyHeader),
748 : "<VRTDataset") != nullptr)
749 1928 : return TRUE;
750 :
751 73631 : if (strstr(poOpenInfo->pszFilename, "<VRTDataset") != nullptr)
752 863 : return TRUE;
753 :
754 72768 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, VRT_PROTOCOL_PREFIX))
755 138 : return TRUE;
756 :
757 72630 : return FALSE;
758 : }
759 :
760 : /************************************************************************/
761 : /* Open() */
762 : /************************************************************************/
763 :
764 1456 : GDALDataset *VRTDataset::Open(GDALOpenInfo *poOpenInfo)
765 :
766 : {
767 : /* -------------------------------------------------------------------- */
768 : /* Does this appear to be a virtual dataset definition XML */
769 : /* file? */
770 : /* -------------------------------------------------------------------- */
771 1456 : if (!Identify(poOpenInfo))
772 0 : return nullptr;
773 :
774 1456 : if (STARTS_WITH_CI(poOpenInfo->pszFilename, VRT_PROTOCOL_PREFIX))
775 69 : return OpenVRTProtocol(poOpenInfo->pszFilename);
776 :
777 : /* -------------------------------------------------------------------- */
778 : /* Try to read the whole file into memory. */
779 : /* -------------------------------------------------------------------- */
780 1387 : char *pszXML = nullptr;
781 1387 : VSILFILE *fp = poOpenInfo->fpL;
782 :
783 1387 : char *pszVRTPath = nullptr;
784 1387 : if (fp != nullptr)
785 : {
786 956 : poOpenInfo->fpL = nullptr;
787 :
788 956 : GByte *pabyOut = nullptr;
789 956 : if (!VSIIngestFile(fp, poOpenInfo->pszFilename, &pabyOut, nullptr,
790 : INT_MAX - 1))
791 : {
792 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
793 0 : return nullptr;
794 : }
795 956 : pszXML = reinterpret_cast<char *>(pabyOut);
796 :
797 956 : char *pszCurDir = CPLGetCurrentDir();
798 : const char *currentVrtFilename =
799 956 : CPLProjectRelativeFilename(pszCurDir, poOpenInfo->pszFilename);
800 956 : CPLString osInitialCurrentVrtFilename(currentVrtFilename);
801 956 : CPLFree(pszCurDir);
802 :
803 : #if defined(HAVE_READLINK) && defined(HAVE_LSTAT)
804 : char filenameBuffer[2048];
805 :
806 : while (true)
807 : {
808 : VSIStatBuf statBuffer;
809 960 : int lstatCode = lstat(currentVrtFilename, &statBuffer);
810 960 : if (lstatCode == -1)
811 : {
812 211 : if (errno == ENOENT)
813 : {
814 : // File could be a virtual file, let later checks handle it.
815 211 : break;
816 : }
817 : else
818 : {
819 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
820 0 : CPLFree(pszXML);
821 0 : CPLError(CE_Failure, CPLE_FileIO, "Failed to lstat %s: %s",
822 0 : currentVrtFilename, VSIStrerror(errno));
823 0 : return nullptr;
824 : }
825 : }
826 :
827 749 : if (!VSI_ISLNK(statBuffer.st_mode))
828 : {
829 745 : break;
830 : }
831 :
832 4 : const int bufferSize = static_cast<int>(readlink(
833 4 : currentVrtFilename, filenameBuffer, sizeof(filenameBuffer)));
834 4 : if (bufferSize != -1)
835 : {
836 4 : filenameBuffer[std::min(
837 4 : bufferSize, static_cast<int>(sizeof(filenameBuffer)) - 1)] =
838 : 0;
839 : // The filename in filenameBuffer might be a relative path
840 : // from the linkfile resolve it before looping
841 4 : currentVrtFilename = CPLProjectRelativeFilename(
842 : CPLGetDirname(currentVrtFilename), filenameBuffer);
843 : }
844 : else
845 : {
846 0 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
847 0 : CPLFree(pszXML);
848 0 : CPLError(CE_Failure, CPLE_FileIO,
849 : "Failed to read filename from symlink %s: %s",
850 0 : currentVrtFilename, VSIStrerror(errno));
851 0 : return nullptr;
852 : }
853 4 : }
854 : #endif // HAVE_READLINK && HAVE_LSTAT
855 :
856 956 : if (osInitialCurrentVrtFilename == currentVrtFilename)
857 953 : pszVRTPath = CPLStrdup(CPLGetPath(poOpenInfo->pszFilename));
858 : else
859 3 : pszVRTPath = CPLStrdup(CPLGetPath(currentVrtFilename));
860 :
861 956 : CPL_IGNORE_RET_VAL(VSIFCloseL(fp));
862 : }
863 : /* -------------------------------------------------------------------- */
864 : /* Or use the filename as the XML input. */
865 : /* -------------------------------------------------------------------- */
866 : else
867 : {
868 431 : pszXML = CPLStrdup(poOpenInfo->pszFilename);
869 : }
870 :
871 1387 : if (CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH") != nullptr)
872 : {
873 2 : CPLFree(pszVRTPath);
874 2 : pszVRTPath = CPLStrdup(
875 2 : CSLFetchNameValue(poOpenInfo->papszOpenOptions, "ROOT_PATH"));
876 : }
877 :
878 : /* -------------------------------------------------------------------- */
879 : /* Turn the XML representation into a VRTDataset. */
880 : /* -------------------------------------------------------------------- */
881 1387 : VRTDataset *poDS = OpenXML(pszXML, pszVRTPath, poOpenInfo->eAccess);
882 :
883 1387 : if (poDS != nullptr)
884 1276 : poDS->m_bNeedsFlush = false;
885 :
886 1387 : if (poDS != nullptr)
887 : {
888 1276 : if (poDS->GetRasterCount() == 0 &&
889 1277 : (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) == 0 &&
890 1 : strstr(pszXML, "VRTPansharpenedDataset") == nullptr)
891 : {
892 0 : delete poDS;
893 0 : poDS = nullptr;
894 : }
895 1276 : else if (poDS->GetRootGroup() == nullptr &&
896 1276 : (poOpenInfo->nOpenFlags & GDAL_OF_RASTER) == 0 &&
897 0 : (poOpenInfo->nOpenFlags & GDAL_OF_MULTIDIM_RASTER) != 0)
898 : {
899 0 : delete poDS;
900 0 : poDS = nullptr;
901 : }
902 : }
903 :
904 1387 : CPLFree(pszXML);
905 1387 : CPLFree(pszVRTPath);
906 :
907 : /* -------------------------------------------------------------------- */
908 : /* Initialize info for later overview discovery. */
909 : /* -------------------------------------------------------------------- */
910 :
911 1387 : if (poDS != nullptr)
912 : {
913 1276 : if (fp != nullptr)
914 : {
915 953 : poDS->oOvManager.Initialize(poDS, poOpenInfo->pszFilename);
916 953 : if (poOpenInfo->AreSiblingFilesLoaded())
917 2 : poDS->oOvManager.TransferSiblingFiles(
918 : poOpenInfo->StealSiblingFiles());
919 : }
920 :
921 : // Creating virtual overviews, but only if there is no higher priority
922 : // overview source, ie. a Overview element at VRT band level,
923 : // or external .vrt.ovr
924 1276 : if (!poDS->m_aosOverviewList.empty())
925 : {
926 6 : if (poDS->nBands > 0)
927 : {
928 6 : auto poBand = dynamic_cast<VRTRasterBand *>(poDS->papoBands[0]);
929 6 : if (poBand && !poBand->m_aoOverviewInfos.empty())
930 : {
931 0 : poDS->m_aosOverviewList.Clear();
932 0 : CPLDebug("VRT",
933 : "Ignoring virtual overviews of OverviewList "
934 : "because Overview element is present on VRT band");
935 : }
936 12 : else if (poBand &&
937 6 : poBand->GDALRasterBand::GetOverviewCount() > 0)
938 : {
939 1 : poDS->m_aosOverviewList.Clear();
940 1 : CPLDebug("VRT",
941 : "Ignoring virtual overviews of OverviewList "
942 : "because external .vrt.ovr is available");
943 : }
944 : }
945 17 : for (int iOverview = 0; iOverview < poDS->m_aosOverviewList.size();
946 : iOverview++)
947 : {
948 11 : const int nOvFactor = atoi(poDS->m_aosOverviewList[iOverview]);
949 11 : if (nOvFactor <= 1)
950 : {
951 0 : CPLError(CE_Failure, CPLE_AppDefined,
952 : "Invalid overview factor");
953 0 : delete poDS;
954 0 : return nullptr;
955 : }
956 :
957 22 : poDS->AddVirtualOverview(
958 11 : nOvFactor, poDS->m_osOverviewResampling.empty()
959 : ? "nearest"
960 11 : : poDS->m_osOverviewResampling.c_str());
961 : }
962 6 : poDS->m_aosOverviewList.Clear();
963 : }
964 :
965 1348 : if (poDS->eAccess == GA_Update && poDS->m_poRootGroup &&
966 72 : !STARTS_WITH_CI(poOpenInfo->pszFilename, "<VRT"))
967 : {
968 72 : poDS->m_poRootGroup->SetFilename(poOpenInfo->pszFilename);
969 : }
970 : }
971 :
972 1387 : return poDS;
973 : }
974 :
975 : /************************************************************************/
976 : /* OpenVRTProtocol() */
977 : /* */
978 : /* Create an open VRTDataset from a vrt:// string. */
979 : /************************************************************************/
980 :
981 69 : GDALDataset *VRTDataset::OpenVRTProtocol(const char *pszSpec)
982 :
983 : {
984 69 : CPLAssert(STARTS_WITH_CI(pszSpec, VRT_PROTOCOL_PREFIX));
985 138 : CPLString osFilename(pszSpec + strlen(VRT_PROTOCOL_PREFIX));
986 69 : const auto nPosQuotationMark = osFilename.find('?');
987 138 : CPLString osQueryString;
988 69 : if (nPosQuotationMark != std::string::npos)
989 : {
990 61 : osQueryString = osFilename.substr(nPosQuotationMark + 1);
991 61 : osFilename.resize(nPosQuotationMark);
992 : }
993 :
994 : // Parse query string, get args required for initial Open()
995 138 : const CPLStringList aosTokens(CSLTokenizeString2(osQueryString, "&", 0));
996 138 : CPLStringList aosAllowedDrivers;
997 138 : CPLStringList aosOpenOptions;
998 :
999 154 : for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(
1000 219 : aosTokens, /* bReturnNullKeyIfNotNameValue = */ true))
1001 : {
1002 79 : if (!pszKey)
1003 : {
1004 2 : CPLError(CE_Failure, CPLE_NotSupported,
1005 : "Invalid option specification: %s\n"
1006 : "must be in the form 'key=value'",
1007 : pszValue);
1008 4 : return nullptr;
1009 : }
1010 77 : else if (EQUAL(pszKey, "if"))
1011 : {
1012 4 : if (!aosAllowedDrivers.empty())
1013 : {
1014 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1015 : "'if' option should be specified once, use commas "
1016 : "to input multiple values.");
1017 1 : return nullptr;
1018 : }
1019 3 : aosAllowedDrivers = CSLTokenizeString2(pszValue, ",", 0);
1020 : }
1021 73 : else if (EQUAL(pszKey, "oo"))
1022 : {
1023 3 : if (!aosOpenOptions.empty())
1024 : {
1025 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1026 : "'oo' option should be specified once, use commas "
1027 : "to input multiple values.");
1028 1 : return nullptr;
1029 : }
1030 2 : aosOpenOptions = CSLTokenizeString2(pszValue, ",", 0);
1031 : }
1032 : }
1033 :
1034 : // We don't open in GDAL_OF_SHARED mode to avoid issues when we open a
1035 : // http://.jp2 file with the JP2OpenJPEG driver through the HTTP driver,
1036 : // which returns a /vsimem/ file
1037 : auto poSrcDS = std::unique_ptr<GDALDataset, GDALDatasetUniquePtrReleaser>(
1038 65 : GDALDataset::Open(osFilename, GDAL_OF_RASTER, aosAllowedDrivers.List(),
1039 195 : aosOpenOptions.List(), nullptr));
1040 65 : if (poSrcDS == nullptr)
1041 : {
1042 4 : return nullptr;
1043 : }
1044 :
1045 : // scan for sd_name/sd in tokens, close the source dataset and reopen if found/valid
1046 61 : bool bFound_subdataset = false;
1047 129 : for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(aosTokens))
1048 : {
1049 71 : if (EQUAL(pszKey, "sd_name"))
1050 : {
1051 4 : if (bFound_subdataset)
1052 : {
1053 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1054 : "'sd_name' is mutually exclusive with option "
1055 : "'sd'");
1056 3 : return nullptr;
1057 : }
1058 3 : char **papszSubdatasets = poSrcDS->GetMetadata("SUBDATASETS");
1059 3 : int nSubdatasets = CSLCount(papszSubdatasets);
1060 :
1061 3 : if (nSubdatasets > 0)
1062 : {
1063 3 : bool bFound = false;
1064 25 : for (int j = 0; j < nSubdatasets; j += 2)
1065 : {
1066 : const std::string osSubdatasetSource(
1067 24 : strstr(papszSubdatasets[j], "=") + 1);
1068 24 : if (osSubdatasetSource.empty())
1069 : {
1070 0 : CPLError(CE_Failure, CPLE_IllegalArg,
1071 : "'sd_name:' failed to obtain "
1072 : "subdataset string ");
1073 0 : return nullptr;
1074 : }
1075 : GDALSubdatasetInfoH info =
1076 24 : GDALGetSubdatasetInfo(osSubdatasetSource.c_str());
1077 : char *component =
1078 24 : info ? GDALSubdatasetInfoGetSubdatasetComponent(info)
1079 24 : : nullptr;
1080 :
1081 24 : bFound = component && EQUAL(pszValue, component);
1082 24 : bFound_subdataset = true;
1083 24 : CPLFree(component);
1084 24 : GDALDestroySubdatasetInfo(info);
1085 24 : if (bFound)
1086 : {
1087 2 : poSrcDS.reset(GDALDataset::Open(
1088 : osSubdatasetSource.c_str(), GDAL_OF_RASTER,
1089 2 : aosAllowedDrivers.List(), aosOpenOptions.List(),
1090 : nullptr));
1091 2 : if (poSrcDS == nullptr)
1092 : {
1093 0 : return nullptr;
1094 : }
1095 :
1096 2 : break;
1097 : }
1098 : }
1099 :
1100 3 : if (!bFound)
1101 : {
1102 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1103 : "'sd_name' option should be be a valid "
1104 : "subdataset component name");
1105 1 : return nullptr;
1106 : }
1107 : }
1108 : }
1109 :
1110 69 : if (EQUAL(pszKey, "sd"))
1111 : {
1112 3 : if (bFound_subdataset)
1113 : {
1114 0 : CPLError(CE_Failure, CPLE_IllegalArg,
1115 : "'sd' is mutually exclusive with option "
1116 : "'sd_name'");
1117 0 : return nullptr;
1118 : }
1119 3 : CSLConstList papszSubdatasets = poSrcDS->GetMetadata("SUBDATASETS");
1120 3 : int nSubdatasets = CSLCount(papszSubdatasets);
1121 :
1122 3 : if (nSubdatasets > 0)
1123 : {
1124 3 : int iSubdataset = atoi(pszValue);
1125 3 : if (iSubdataset < 1 || iSubdataset > (nSubdatasets) / 2)
1126 : {
1127 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1128 : "'sd' option should indicate a valid "
1129 : "subdataset component number (starting with 1)");
1130 1 : return nullptr;
1131 : }
1132 : const std::string osSubdatasetSource(
1133 2 : strstr(papszSubdatasets[(iSubdataset - 1) * 2], "=") + 1);
1134 2 : if (osSubdatasetSource.empty())
1135 : {
1136 0 : CPLError(CE_Failure, CPLE_IllegalArg,
1137 : "'sd:' failed to obtain subdataset "
1138 : "string ");
1139 0 : return nullptr;
1140 : }
1141 :
1142 2 : poSrcDS.reset(GDALDataset::Open(
1143 : osSubdatasetSource.c_str(), GDAL_OF_RASTER,
1144 2 : aosAllowedDrivers.List(), aosOpenOptions.List(), nullptr));
1145 2 : if (poSrcDS == nullptr)
1146 : {
1147 0 : return nullptr;
1148 : }
1149 2 : bFound_subdataset = true;
1150 : }
1151 : }
1152 : }
1153 :
1154 116 : std::vector<int> anBands;
1155 :
1156 116 : CPLStringList argv;
1157 58 : argv.AddString("-of");
1158 58 : argv.AddString("VRT");
1159 :
1160 115 : for (const auto &[pszKey, pszValue] : cpl::IterateNameValue(aosTokens))
1161 : {
1162 67 : if (EQUAL(pszKey, "bands"))
1163 : {
1164 6 : const CPLStringList aosBands(CSLTokenizeString2(pszValue, ",", 0));
1165 12 : for (int j = 0; j < aosBands.size(); j++)
1166 : {
1167 9 : if (EQUAL(aosBands[j], "mask"))
1168 : {
1169 1 : anBands.push_back(0);
1170 : }
1171 : else
1172 : {
1173 8 : const int nBand = atoi(aosBands[j]);
1174 8 : if (nBand <= 0 || nBand > poSrcDS->GetRasterCount())
1175 : {
1176 3 : CPLError(CE_Failure, CPLE_IllegalArg,
1177 : "Invalid band number: %s", aosBands[j]);
1178 3 : return nullptr;
1179 : }
1180 5 : anBands.push_back(nBand);
1181 : }
1182 : }
1183 :
1184 9 : for (const int nBand : anBands)
1185 : {
1186 6 : argv.AddString("-b");
1187 6 : argv.AddString(nBand == 0 ? "mask" : CPLSPrintf("%d", nBand));
1188 : }
1189 : }
1190 :
1191 61 : else if (EQUAL(pszKey, "a_nodata"))
1192 : {
1193 1 : argv.AddString("-a_nodata");
1194 1 : argv.AddString(pszValue);
1195 : }
1196 :
1197 60 : else if (EQUAL(pszKey, "a_srs"))
1198 : {
1199 1 : argv.AddString("-a_srs");
1200 1 : argv.AddString(pszValue);
1201 : }
1202 :
1203 59 : else if (EQUAL(pszKey, "a_ullr"))
1204 : {
1205 : // Parse the limits
1206 1 : const CPLStringList aosUllr(CSLTokenizeString2(pszValue, ",", 0));
1207 : // fail if not four values
1208 1 : if (aosUllr.size() != 4)
1209 : {
1210 0 : CPLError(CE_Failure, CPLE_IllegalArg,
1211 : "Invalid a_ullr option: %s", pszValue);
1212 0 : return nullptr;
1213 : }
1214 :
1215 1 : argv.AddString("-a_ullr");
1216 1 : argv.AddString(aosUllr[0]);
1217 1 : argv.AddString(aosUllr[1]);
1218 1 : argv.AddString(aosUllr[2]);
1219 1 : argv.AddString(aosUllr[3]);
1220 : }
1221 :
1222 58 : else if (EQUAL(pszKey, "ovr"))
1223 : {
1224 1 : argv.AddString("-ovr");
1225 1 : argv.AddString(pszValue);
1226 : }
1227 57 : else if (EQUAL(pszKey, "expand"))
1228 : {
1229 1 : argv.AddString("-expand");
1230 1 : argv.AddString(pszValue);
1231 : }
1232 56 : else if (EQUAL(pszKey, "a_scale"))
1233 : {
1234 2 : argv.AddString("-a_scale");
1235 2 : argv.AddString(pszValue);
1236 : }
1237 54 : else if (EQUAL(pszKey, "a_offset"))
1238 : {
1239 1 : argv.AddString("-a_offset");
1240 1 : argv.AddString(pszValue);
1241 : }
1242 53 : else if (EQUAL(pszKey, "ot"))
1243 : {
1244 2 : argv.AddString("-ot");
1245 2 : argv.AddString(pszValue);
1246 : }
1247 51 : else if (EQUAL(pszKey, "gcp"))
1248 : {
1249 6 : const CPLStringList aosGCP(CSLTokenizeString2(pszValue, ",", 0));
1250 :
1251 6 : if (aosGCP.size() < 4 || aosGCP.size() > 5)
1252 : {
1253 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1254 : "Invalid value for GCP: %s\n need 4, or 5 "
1255 : "numbers, comma separated: "
1256 : "'gcp=<pixel>,<line>,<easting>,<northing>[,<"
1257 : "elevation>]'",
1258 : pszValue);
1259 1 : return nullptr;
1260 : }
1261 5 : argv.AddString("-gcp");
1262 28 : for (int j = 0; j < aosGCP.size(); j++)
1263 : {
1264 23 : argv.AddString(aosGCP[j]);
1265 : }
1266 : }
1267 45 : else if (EQUAL(pszKey, "scale") || STARTS_WITH_CI(pszKey, "scale_"))
1268 : {
1269 : const CPLStringList aosScaleParams(
1270 7 : CSLTokenizeString2(pszValue, ",", 0));
1271 :
1272 7 : if (!(aosScaleParams.size() == 2) &&
1273 7 : !(aosScaleParams.size() == 4) && !(aosScaleParams.size() == 1))
1274 : {
1275 0 : CPLError(CE_Failure, CPLE_IllegalArg,
1276 : "Invalid value for scale, (or scale_bn): "
1277 : "%s\n need 'scale=true', or 2 or 4 "
1278 : "numbers, comma separated: "
1279 : "'scale=src_min,src_max[,dst_min,dst_max]' or "
1280 : "'scale_bn=src_min,src_max[,dst_min,dst_max]'",
1281 : pszValue);
1282 0 : return nullptr;
1283 : }
1284 :
1285 : // -scale because scale=true or scale=min,max or scale=min,max,dstmin,dstmax
1286 7 : if (aosScaleParams.size() == 1 && CPLTestBool(aosScaleParams[0]))
1287 : {
1288 2 : argv.AddString(CPLSPrintf("-%s", pszKey));
1289 : }
1290 : // add remaining params (length 2 or 4)
1291 7 : if (aosScaleParams.size() > 1)
1292 : {
1293 5 : argv.AddString(CPLSPrintf("-%s", pszKey));
1294 21 : for (int j = 0; j < aosScaleParams.size(); j++)
1295 : {
1296 16 : argv.AddString(aosScaleParams[j]);
1297 : }
1298 7 : }
1299 : }
1300 38 : else if (EQUAL(pszKey, "exponent") ||
1301 36 : STARTS_WITH_CI(pszKey, "exponent_"))
1302 : {
1303 3 : argv.AddString(CPLSPrintf("-%s", pszKey));
1304 3 : argv.AddString(pszValue);
1305 : }
1306 35 : else if (EQUAL(pszKey, "outsize"))
1307 : {
1308 : const CPLStringList aosOutSize(
1309 4 : CSLTokenizeString2(pszValue, ",", 0));
1310 4 : if (aosOutSize.size() != 2)
1311 : {
1312 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1313 : "Invalid outsize option: %s, must be two"
1314 : "values separated by comma pixel,line or two "
1315 : "fraction values with percent symbol",
1316 : pszValue);
1317 1 : return nullptr;
1318 : }
1319 3 : argv.AddString("-outsize");
1320 3 : argv.AddString(aosOutSize[0]);
1321 3 : argv.AddString(aosOutSize[1]);
1322 : }
1323 31 : else if (EQUAL(pszKey, "projwin"))
1324 : {
1325 : // Parse the limits
1326 : const CPLStringList aosProjWin(
1327 3 : CSLTokenizeString2(pszValue, ",", 0));
1328 : // fail if not four values
1329 3 : if (aosProjWin.size() != 4)
1330 : {
1331 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1332 : "Invalid projwin option: %s", pszValue);
1333 1 : return nullptr;
1334 : }
1335 :
1336 2 : argv.AddString("-projwin");
1337 2 : argv.AddString(aosProjWin[0]);
1338 2 : argv.AddString(aosProjWin[1]);
1339 2 : argv.AddString(aosProjWin[2]);
1340 2 : argv.AddString(aosProjWin[3]);
1341 : }
1342 28 : else if (EQUAL(pszKey, "projwin_srs"))
1343 : {
1344 2 : argv.AddString("-projwin_srs");
1345 2 : argv.AddString(pszValue);
1346 : }
1347 26 : else if (EQUAL(pszKey, "tr"))
1348 : {
1349 : const CPLStringList aosTargetResolution(
1350 3 : CSLTokenizeString2(pszValue, ",", 0));
1351 3 : if (aosTargetResolution.size() != 2)
1352 : {
1353 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1354 : "Invalid tr option: %s, must be two "
1355 : "values separated by comma xres,yres",
1356 : pszValue);
1357 1 : return nullptr;
1358 : }
1359 2 : argv.AddString("-tr");
1360 2 : argv.AddString(aosTargetResolution[0]);
1361 2 : argv.AddString(aosTargetResolution[1]);
1362 : }
1363 23 : else if (EQUAL(pszKey, "r"))
1364 : {
1365 1 : argv.AddString("-r");
1366 1 : argv.AddString(pszValue);
1367 : }
1368 :
1369 22 : else if (EQUAL(pszKey, "srcwin"))
1370 : {
1371 : // Parse the limits
1372 6 : const CPLStringList aosSrcWin(CSLTokenizeString2(pszValue, ",", 0));
1373 : // fail if not four values
1374 6 : if (aosSrcWin.size() != 4)
1375 : {
1376 1 : CPLError(CE_Failure, CPLE_IllegalArg,
1377 : "Invalid srcwin option: %s, must be four "
1378 : "values separated by comma xoff,yoff,xsize,ysize",
1379 : pszValue);
1380 1 : return nullptr;
1381 : }
1382 :
1383 5 : argv.AddString("-srcwin");
1384 5 : argv.AddString(aosSrcWin[0]);
1385 5 : argv.AddString(aosSrcWin[1]);
1386 5 : argv.AddString(aosSrcWin[2]);
1387 5 : argv.AddString(aosSrcWin[3]);
1388 : }
1389 :
1390 16 : else if (EQUAL(pszKey, "a_gt"))
1391 : {
1392 : // Parse the limits
1393 : const CPLStringList aosAGeoTransform(
1394 2 : CSLTokenizeString2(pszValue, ",", 0));
1395 : // fail if not six values
1396 2 : if (aosAGeoTransform.size() != 6)
1397 : {
1398 1 : CPLError(CE_Failure, CPLE_IllegalArg, "Invalid a_gt option: %s",
1399 : pszValue);
1400 1 : return nullptr;
1401 : }
1402 :
1403 1 : argv.AddString("-a_gt");
1404 1 : argv.AddString(aosAGeoTransform[0]);
1405 1 : argv.AddString(aosAGeoTransform[1]);
1406 1 : argv.AddString(aosAGeoTransform[2]);
1407 1 : argv.AddString(aosAGeoTransform[3]);
1408 1 : argv.AddString(aosAGeoTransform[4]);
1409 1 : argv.AddString(aosAGeoTransform[5]);
1410 : }
1411 14 : else if (EQUAL(pszKey, "oo"))
1412 : {
1413 : // do nothing, we passed this in earlier
1414 : }
1415 13 : else if (EQUAL(pszKey, "if"))
1416 : {
1417 : // do nothing, we passed this in earlier
1418 : }
1419 12 : else if (EQUAL(pszKey, "sd_name"))
1420 : {
1421 : // do nothing, we passed this in earlier
1422 : }
1423 10 : else if (EQUAL(pszKey, "sd"))
1424 : {
1425 : // do nothing, we passed this in earlier
1426 : }
1427 9 : else if (EQUAL(pszKey, "unscale"))
1428 : {
1429 1 : if (CPLTestBool(pszValue))
1430 : {
1431 1 : argv.AddString("-unscale");
1432 : }
1433 : }
1434 8 : else if (EQUAL(pszKey, "a_coord_epoch"))
1435 : {
1436 0 : argv.AddString("-a_coord_epoch");
1437 0 : argv.AddString(pszValue);
1438 : }
1439 8 : else if (EQUAL(pszKey, "nogcp"))
1440 : {
1441 1 : if (CPLTestBool(pszValue))
1442 : {
1443 1 : argv.AddString("-nogcp");
1444 : }
1445 : }
1446 7 : else if (EQUAL(pszKey, "epo"))
1447 : {
1448 3 : if (CPLTestBool(pszValue))
1449 : {
1450 2 : argv.AddString("-epo");
1451 : }
1452 : }
1453 4 : else if (EQUAL(pszKey, "eco"))
1454 : {
1455 3 : if (CPLTestBool(pszValue))
1456 : {
1457 3 : argv.AddString("-eco");
1458 : }
1459 : }
1460 : else
1461 : {
1462 1 : CPLError(CE_Failure, CPLE_NotSupported, "Unknown option: %s",
1463 : pszKey);
1464 1 : return nullptr;
1465 : }
1466 : }
1467 :
1468 : GDALTranslateOptions *psOptions =
1469 48 : GDALTranslateOptionsNew(argv.List(), nullptr);
1470 :
1471 48 : auto hRet = GDALTranslate("", GDALDataset::ToHandle(poSrcDS.get()),
1472 : psOptions, nullptr);
1473 :
1474 48 : GDALTranslateOptionsFree(psOptions);
1475 :
1476 : // Situation where we open a http://.jp2 file with the JP2OpenJPEG driver
1477 : // through the HTTP driver, which returns a /vsimem/ file
1478 : const bool bPatchSourceFilename =
1479 48 : (STARTS_WITH(osFilename.c_str(), "http://") ||
1480 49 : STARTS_WITH(osFilename.c_str(), "https://")) &&
1481 1 : osFilename != poSrcDS->GetDescription();
1482 :
1483 48 : poSrcDS.reset();
1484 :
1485 48 : auto poDS = dynamic_cast<VRTDataset *>(GDALDataset::FromHandle(hRet));
1486 48 : if (poDS)
1487 : {
1488 45 : if (bPatchSourceFilename)
1489 : {
1490 2 : for (int i = 0; i < poDS->nBands; ++i)
1491 : {
1492 : auto poBand =
1493 1 : dynamic_cast<VRTSourcedRasterBand *>(poDS->papoBands[i]);
1494 2 : if (poBand && poBand->nSources == 1 &&
1495 1 : poBand->papoSources[0]->IsSimpleSource())
1496 : {
1497 2 : auto poSource = cpl::down_cast<VRTSimpleSource *>(
1498 1 : poBand->papoSources[0]);
1499 1 : poSource->m_bRelativeToVRTOri = 0;
1500 1 : poSource->m_osSourceFileNameOri = osFilename;
1501 : }
1502 : }
1503 : }
1504 45 : poDS->SetDescription(pszSpec);
1505 45 : poDS->SetWritable(false);
1506 : }
1507 48 : return poDS;
1508 : }
1509 :
1510 : /************************************************************************/
1511 : /* OpenXML() */
1512 : /* */
1513 : /* Create an open VRTDataset from a supplied XML representation */
1514 : /* of the dataset. */
1515 : /************************************************************************/
1516 :
1517 1388 : VRTDataset *VRTDataset::OpenXML(const char *pszXML, const char *pszVRTPath,
1518 : GDALAccess eAccessIn)
1519 :
1520 : {
1521 : /* -------------------------------------------------------------------- */
1522 : /* Parse the XML. */
1523 : /* -------------------------------------------------------------------- */
1524 2776 : CPLXMLTreeCloser psTree(CPLParseXMLString(pszXML));
1525 1388 : if (psTree == nullptr)
1526 0 : return nullptr;
1527 :
1528 1388 : CPLXMLNode *psRoot = CPLGetXMLNode(psTree.get(), "=VRTDataset");
1529 1388 : if (psRoot == nullptr)
1530 : {
1531 0 : CPLError(CE_Failure, CPLE_AppDefined, "Missing VRTDataset element.");
1532 0 : return nullptr;
1533 : }
1534 :
1535 1388 : const char *pszSubClass = CPLGetXMLValue(psRoot, "subClass", "");
1536 :
1537 1388 : const bool bIsPansharpened =
1538 1388 : strcmp(pszSubClass, "VRTPansharpenedDataset") == 0;
1539 1388 : const bool bIsProcessed = strcmp(pszSubClass, "VRTProcessedDataset") == 0;
1540 :
1541 1321 : if (!bIsPansharpened && !bIsProcessed &&
1542 3770 : CPLGetXMLNode(psRoot, "Group") == nullptr &&
1543 1061 : (CPLGetXMLNode(psRoot, "rasterXSize") == nullptr ||
1544 1060 : CPLGetXMLNode(psRoot, "rasterYSize") == nullptr ||
1545 1060 : CPLGetXMLNode(psRoot, "VRTRasterBand") == nullptr))
1546 : {
1547 2 : CPLError(CE_Failure, CPLE_AppDefined,
1548 : "Missing one of rasterXSize, rasterYSize or bands on"
1549 : " VRTDataset.");
1550 2 : return nullptr;
1551 : }
1552 :
1553 : /* -------------------------------------------------------------------- */
1554 : /* Create the new virtual dataset object. */
1555 : /* -------------------------------------------------------------------- */
1556 1386 : const int nXSize = atoi(CPLGetXMLValue(psRoot, "rasterXSize", "0"));
1557 1386 : const int nYSize = atoi(CPLGetXMLValue(psRoot, "rasterYSize", "0"));
1558 :
1559 1319 : if (!bIsPansharpened && !bIsProcessed &&
1560 3764 : CPLGetXMLNode(psRoot, "VRTRasterBand") != nullptr &&
1561 1059 : !GDALCheckDatasetDimensions(nXSize, nYSize))
1562 : {
1563 0 : return nullptr;
1564 : }
1565 :
1566 1386 : VRTDataset *poDS = nullptr;
1567 1386 : if (strcmp(pszSubClass, "VRTWarpedDataset") == 0)
1568 193 : poDS = new VRTWarpedDataset(nXSize, nYSize);
1569 1193 : else if (bIsPansharpened)
1570 67 : poDS = new VRTPansharpenedDataset(nXSize, nYSize);
1571 1126 : else if (bIsProcessed)
1572 48 : poDS = new VRTProcessedDataset(nXSize, nYSize);
1573 : else
1574 : {
1575 1078 : poDS = new VRTDataset(nXSize, nYSize);
1576 1078 : poDS->eAccess = eAccessIn;
1577 : }
1578 :
1579 1386 : if (poDS->XMLInit(psRoot, pszVRTPath) != CE_None)
1580 : {
1581 110 : delete poDS;
1582 110 : poDS = nullptr;
1583 : }
1584 :
1585 : /* -------------------------------------------------------------------- */
1586 : /* Try to return a regular handle on the file. */
1587 : /* -------------------------------------------------------------------- */
1588 :
1589 1386 : return poDS;
1590 : }
1591 :
1592 : /************************************************************************/
1593 : /* AddBand() */
1594 : /************************************************************************/
1595 :
1596 3423 : CPLErr VRTDataset::AddBand(GDALDataType eType, char **papszOptions)
1597 :
1598 : {
1599 3423 : SetNeedsFlush();
1600 :
1601 : /* ==================================================================== */
1602 : /* Handle a new raw band. */
1603 : /* ==================================================================== */
1604 3423 : const char *pszSubClass = CSLFetchNameValue(papszOptions, "subclass");
1605 :
1606 3423 : if (pszSubClass != nullptr && EQUAL(pszSubClass, "VRTRawRasterBand"))
1607 : {
1608 6 : const int nWordDataSize = GDALGetDataTypeSizeBytes(eType);
1609 :
1610 : /* --------------------------------------------------------------------
1611 : */
1612 : /* Collect required information. */
1613 : /* --------------------------------------------------------------------
1614 : */
1615 : const char *pszImageOffset =
1616 6 : CSLFetchNameValueDef(papszOptions, "ImageOffset", "0");
1617 12 : vsi_l_offset nImageOffset = CPLScanUIntBig(
1618 6 : pszImageOffset, static_cast<int>(strlen(pszImageOffset)));
1619 :
1620 6 : int nPixelOffset = nWordDataSize;
1621 : const char *pszPixelOffset =
1622 6 : CSLFetchNameValue(papszOptions, "PixelOffset");
1623 6 : if (pszPixelOffset != nullptr)
1624 4 : nPixelOffset = atoi(pszPixelOffset);
1625 :
1626 : int nLineOffset;
1627 : const char *pszLineOffset =
1628 6 : CSLFetchNameValue(papszOptions, "LineOffset");
1629 6 : if (pszLineOffset != nullptr)
1630 4 : nLineOffset = atoi(pszLineOffset);
1631 : else
1632 : {
1633 4 : if (nPixelOffset > INT_MAX / GetRasterXSize() ||
1634 2 : nPixelOffset < INT_MIN / GetRasterXSize())
1635 : {
1636 0 : CPLError(CE_Failure, CPLE_AppDefined, "Int overflow");
1637 0 : return CE_Failure;
1638 : }
1639 2 : nLineOffset = nPixelOffset * GetRasterXSize();
1640 : }
1641 :
1642 6 : const char *pszByteOrder = CSLFetchNameValue(papszOptions, "ByteOrder");
1643 :
1644 : const char *pszFilename =
1645 6 : CSLFetchNameValue(papszOptions, "SourceFilename");
1646 6 : if (pszFilename == nullptr)
1647 : {
1648 0 : CPLError(CE_Failure, CPLE_AppDefined,
1649 : "AddBand() requires a SourceFilename option for "
1650 : "VRTRawRasterBands.");
1651 0 : return CE_Failure;
1652 : }
1653 :
1654 : const bool bRelativeToVRT =
1655 6 : CPLFetchBool(papszOptions, "relativeToVRT", false);
1656 :
1657 : /* --------------------------------------------------------------------
1658 : */
1659 : /* Create and initialize the band. */
1660 : /* --------------------------------------------------------------------
1661 : */
1662 :
1663 : VRTRawRasterBand *poBand =
1664 6 : new VRTRawRasterBand(this, GetRasterCount() + 1, eType);
1665 :
1666 6 : char *l_pszVRTPath = CPLStrdup(CPLGetPath(GetDescription()));
1667 6 : if (EQUAL(l_pszVRTPath, ""))
1668 : {
1669 0 : CPLFree(l_pszVRTPath);
1670 0 : l_pszVRTPath = nullptr;
1671 : }
1672 :
1673 6 : const CPLErr eErr = poBand->SetRawLink(
1674 : pszFilename, l_pszVRTPath, bRelativeToVRT, nImageOffset,
1675 : nPixelOffset, nLineOffset, pszByteOrder);
1676 6 : CPLFree(l_pszVRTPath);
1677 6 : if (eErr != CE_None)
1678 : {
1679 0 : delete poBand;
1680 0 : return eErr;
1681 : }
1682 :
1683 6 : SetBand(GetRasterCount() + 1, poBand);
1684 :
1685 6 : return CE_None;
1686 : }
1687 :
1688 : /* ==================================================================== */
1689 : /* Handle a new "sourced" band. */
1690 : /* ==================================================================== */
1691 : else
1692 : {
1693 3417 : VRTSourcedRasterBand *poBand = nullptr;
1694 :
1695 : /* ---- Check for our sourced band 'derived' subclass ---- */
1696 3417 : if (pszSubClass != nullptr &&
1697 5 : EQUAL(pszSubClass, "VRTDerivedRasterBand"))
1698 : {
1699 :
1700 : /* We'll need a pointer to the subclass in case we need */
1701 : /* to set the new band's pixel function below. */
1702 : VRTDerivedRasterBand *poDerivedBand =
1703 4 : new VRTDerivedRasterBand(this, GetRasterCount() + 1, eType,
1704 4 : GetRasterXSize(), GetRasterYSize());
1705 :
1706 : /* Set the pixel function options it provided. */
1707 : const char *pszFuncName =
1708 4 : CSLFetchNameValue(papszOptions, "PixelFunctionType");
1709 4 : if (pszFuncName != nullptr)
1710 3 : poDerivedBand->SetPixelFunctionName(pszFuncName);
1711 :
1712 : const char *pszLanguage =
1713 4 : CSLFetchNameValue(papszOptions, "PixelFunctionLanguage");
1714 4 : if (pszLanguage != nullptr)
1715 1 : poDerivedBand->SetPixelFunctionLanguage(pszLanguage);
1716 :
1717 : const char *pszTransferTypeName =
1718 4 : CSLFetchNameValue(papszOptions, "SourceTransferType");
1719 4 : if (pszTransferTypeName != nullptr)
1720 : {
1721 : const GDALDataType eTransferType =
1722 2 : GDALGetDataTypeByName(pszTransferTypeName);
1723 2 : if (eTransferType == GDT_Unknown)
1724 : {
1725 1 : CPLError(CE_Failure, CPLE_AppDefined,
1726 : "invalid SourceTransferType: \"%s\".",
1727 : pszTransferTypeName);
1728 1 : delete poDerivedBand;
1729 1 : return CE_Failure;
1730 : }
1731 1 : poDerivedBand->SetSourceTransferType(eTransferType);
1732 : }
1733 :
1734 : /* We're done with the derived band specific stuff, so */
1735 : /* we can assigned the base class pointer now. */
1736 3 : poBand = poDerivedBand;
1737 : }
1738 : else
1739 : {
1740 : int nBlockXSizeIn =
1741 3413 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "0"));
1742 : int nBlockYSizeIn =
1743 3413 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "0"));
1744 3413 : if (nBlockXSizeIn == 0 && nBlockYSizeIn == 0)
1745 : {
1746 2186 : nBlockXSizeIn = m_nBlockXSize;
1747 2186 : nBlockYSizeIn = m_nBlockYSize;
1748 : }
1749 : /* ---- Standard sourced band ---- */
1750 3413 : poBand = new VRTSourcedRasterBand(
1751 3413 : this, GetRasterCount() + 1, eType, GetRasterXSize(),
1752 3413 : GetRasterYSize(), nBlockXSizeIn, nBlockYSizeIn);
1753 : }
1754 :
1755 3416 : SetBand(GetRasterCount() + 1, poBand);
1756 :
1757 5875 : for (int i = 0; papszOptions != nullptr && papszOptions[i] != nullptr;
1758 : i++)
1759 : {
1760 2459 : if (STARTS_WITH_CI(papszOptions[i], "AddFuncSource="))
1761 : {
1762 0 : char **papszTokens = CSLTokenizeStringComplex(
1763 0 : papszOptions[i] + 14, ",", TRUE, FALSE);
1764 0 : if (CSLCount(papszTokens) < 1)
1765 : {
1766 0 : CPLError(CE_Failure, CPLE_AppDefined,
1767 : "AddFuncSource(): required argument missing.");
1768 : // TODO: How should this error be handled? Return
1769 : // CE_Failure?
1770 : }
1771 :
1772 0 : VRTImageReadFunc pfnReadFunc = nullptr;
1773 0 : sscanf(papszTokens[0], "%p", &pfnReadFunc);
1774 :
1775 0 : void *pCBData = nullptr;
1776 0 : if (CSLCount(papszTokens) > 1)
1777 0 : sscanf(papszTokens[1], "%p", &pCBData);
1778 :
1779 0 : const double dfNoDataValue = (CSLCount(papszTokens) > 2)
1780 0 : ? CPLAtof(papszTokens[2])
1781 0 : : VRT_NODATA_UNSET;
1782 :
1783 0 : poBand->AddFuncSource(pfnReadFunc, pCBData, dfNoDataValue);
1784 :
1785 0 : CSLDestroy(papszTokens);
1786 : }
1787 : }
1788 :
1789 3416 : return CE_None;
1790 : }
1791 : }
1792 :
1793 : /*! @endcond */
1794 : /************************************************************************/
1795 : /* VRTAddBand() */
1796 : /************************************************************************/
1797 :
1798 : /**
1799 : * @see VRTDataset::VRTAddBand().
1800 : *
1801 : * @note The return type of this function is int, but the actual values
1802 : * returned are of type CPLErr.
1803 : */
1804 :
1805 965 : int CPL_STDCALL VRTAddBand(VRTDatasetH hDataset, GDALDataType eType,
1806 : char **papszOptions)
1807 :
1808 : {
1809 965 : VALIDATE_POINTER1(hDataset, "VRTAddBand", 0);
1810 :
1811 965 : return static_cast<VRTDataset *>(GDALDataset::FromHandle(hDataset))
1812 965 : ->AddBand(eType, papszOptions);
1813 : }
1814 :
1815 : /*! @cond Doxygen_Suppress */
1816 : /************************************************************************/
1817 : /* Create() */
1818 : /************************************************************************/
1819 :
1820 342 : GDALDataset *VRTDataset::Create(const char *pszName, int nXSize, int nYSize,
1821 : int nBandsIn, GDALDataType eType,
1822 : char **papszOptions)
1823 :
1824 : {
1825 342 : if (STARTS_WITH_CI(pszName, "<VRTDataset"))
1826 : {
1827 0 : GDALDataset *poDS = OpenXML(pszName, nullptr, GA_Update);
1828 0 : if (poDS != nullptr)
1829 0 : poDS->SetDescription("<FromXML>");
1830 0 : return poDS;
1831 : }
1832 :
1833 342 : const char *pszSubclass = CSLFetchNameValue(papszOptions, "SUBCLASS");
1834 :
1835 342 : VRTDataset *poDS = nullptr;
1836 :
1837 : const int nBlockXSize =
1838 342 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKXSIZE", "0"));
1839 : const int nBlockYSize =
1840 342 : atoi(CSLFetchNameValueDef(papszOptions, "BLOCKYSIZE", "0"));
1841 342 : if (pszSubclass == nullptr || EQUAL(pszSubclass, "VRTDataset"))
1842 264 : poDS = new VRTDataset(nXSize, nYSize, nBlockXSize, nBlockYSize);
1843 78 : else if (EQUAL(pszSubclass, "VRTWarpedDataset"))
1844 : {
1845 78 : poDS = new VRTWarpedDataset(nXSize, nYSize, nBlockXSize, nBlockYSize);
1846 : }
1847 : else
1848 : {
1849 0 : CPLError(CE_Failure, CPLE_AppDefined, "SUBCLASS=%s not recognised.",
1850 : pszSubclass);
1851 0 : return nullptr;
1852 : }
1853 342 : poDS->eAccess = GA_Update;
1854 :
1855 342 : poDS->SetDescription(pszName);
1856 :
1857 546 : for (int iBand = 0; iBand < nBandsIn; iBand++)
1858 204 : poDS->AddBand(eType, nullptr);
1859 :
1860 342 : poDS->SetNeedsFlush();
1861 :
1862 342 : poDS->oOvManager.Initialize(poDS, pszName);
1863 :
1864 342 : return poDS;
1865 : }
1866 :
1867 : /************************************************************************/
1868 : /* CreateMultiDimensional() */
1869 : /************************************************************************/
1870 :
1871 : GDALDataset *
1872 100 : VRTDataset::CreateMultiDimensional(const char *pszFilename,
1873 : CSLConstList /*papszRootGroupOptions*/,
1874 : CSLConstList /*papszOptions*/)
1875 : {
1876 100 : VRTDataset *poDS = new VRTDataset(0, 0);
1877 100 : poDS->eAccess = GA_Update;
1878 100 : poDS->SetDescription(pszFilename);
1879 100 : poDS->m_poRootGroup = VRTGroup::Create(std::string(), "/");
1880 100 : poDS->m_poRootGroup->SetIsRootGroup();
1881 100 : poDS->m_poRootGroup->SetFilename(pszFilename);
1882 100 : poDS->m_poRootGroup->SetDirty();
1883 :
1884 100 : return poDS;
1885 : }
1886 :
1887 : /************************************************************************/
1888 : /* GetFileList() */
1889 : /************************************************************************/
1890 :
1891 54 : char **VRTDataset::GetFileList()
1892 : {
1893 54 : char **papszFileList = GDALDataset::GetFileList();
1894 :
1895 54 : int nSize = CSLCount(papszFileList);
1896 54 : int nMaxSize = nSize;
1897 :
1898 : // Do not need an element deallocator as each string points to an
1899 : // element of the papszFileList.
1900 : CPLHashSet *hSetFiles =
1901 54 : CPLHashSetNew(CPLHashSetHashStr, CPLHashSetEqualStr, nullptr);
1902 :
1903 119 : for (int iBand = 0; iBand < nBands; iBand++)
1904 : {
1905 65 : static_cast<VRTRasterBand *>(papoBands[iBand])
1906 65 : ->GetFileList(&papszFileList, &nSize, &nMaxSize, hSetFiles);
1907 : }
1908 :
1909 54 : CPLHashSetDestroy(hSetFiles);
1910 :
1911 54 : return papszFileList;
1912 : }
1913 :
1914 : /************************************************************************/
1915 : /* Delete() */
1916 : /************************************************************************/
1917 :
1918 : /* We implement Delete() to avoid that the default implementation */
1919 : /* in GDALDriver::Delete() destroys the source files listed by GetFileList(),*/
1920 : /* which would be an undesired effect... */
1921 12 : CPLErr VRTDataset::Delete(const char *pszFilename)
1922 : {
1923 12 : GDALDriverH hDriver = GDALIdentifyDriver(pszFilename, nullptr);
1924 :
1925 12 : if (!hDriver || !EQUAL(GDALGetDriverShortName(hDriver), "VRT"))
1926 0 : return CE_Failure;
1927 :
1928 23 : if (strstr(pszFilename, "<VRTDataset") == nullptr &&
1929 11 : VSIUnlink(pszFilename) != 0)
1930 : {
1931 0 : CPLError(CE_Failure, CPLE_AppDefined, "Deleting %s failed:\n%s",
1932 0 : pszFilename, VSIStrerror(errno));
1933 0 : return CE_Failure;
1934 : }
1935 :
1936 12 : return CE_None;
1937 : }
1938 :
1939 : /************************************************************************/
1940 : /* CreateMaskBand() */
1941 : /************************************************************************/
1942 :
1943 32 : CPLErr VRTDataset::CreateMaskBand(int)
1944 : {
1945 32 : if (m_poMaskBand != nullptr)
1946 : {
1947 1 : CPLError(CE_Failure, CPLE_AppDefined,
1948 : "This VRT dataset has already a mask band");
1949 1 : return CE_Failure;
1950 : }
1951 :
1952 31 : SetMaskBand(new VRTSourcedRasterBand(this, 0));
1953 :
1954 31 : return CE_None;
1955 : }
1956 :
1957 : /************************************************************************/
1958 : /* SetMaskBand() */
1959 : /************************************************************************/
1960 :
1961 57 : void VRTDataset::SetMaskBand(VRTRasterBand *poMaskBandIn)
1962 : {
1963 57 : delete m_poMaskBand;
1964 57 : m_poMaskBand = poMaskBandIn;
1965 57 : m_poMaskBand->SetIsMaskBand();
1966 57 : }
1967 :
1968 : /************************************************************************/
1969 : /* CloseDependentDatasets() */
1970 : /************************************************************************/
1971 :
1972 539 : int VRTDataset::CloseDependentDatasets()
1973 : {
1974 : /* We need to call it before removing the sources, otherwise */
1975 : /* we would remove them from the serizalized VRT */
1976 539 : FlushCache(true);
1977 :
1978 539 : int bHasDroppedRef = GDALDataset::CloseDependentDatasets();
1979 :
1980 1518 : for (int iBand = 0; iBand < nBands; iBand++)
1981 : {
1982 1958 : bHasDroppedRef |= static_cast<VRTRasterBand *>(papoBands[iBand])
1983 979 : ->CloseDependentDatasets();
1984 : }
1985 :
1986 539 : return bHasDroppedRef;
1987 : }
1988 :
1989 : /************************************************************************/
1990 : /* CheckCompatibleForDatasetIO() */
1991 : /************************************************************************/
1992 :
1993 : /* We will return TRUE only if all the bands are VRTSourcedRasterBands */
1994 : /* made of identical sources, that are strictly VRTSimpleSource, and that */
1995 : /* the band number of each source is the band number of the */
1996 : /* VRTSourcedRasterBand. */
1997 :
1998 3792 : int VRTDataset::CheckCompatibleForDatasetIO()
1999 : {
2000 3792 : int nSources = 0;
2001 3792 : VRTSource **papoSources = nullptr;
2002 7584 : CPLString osResampling;
2003 :
2004 3792 : if (m_bCompatibleForDatasetIO >= 0)
2005 : {
2006 0 : return m_bCompatibleForDatasetIO;
2007 : }
2008 :
2009 8530 : for (int iBand = 0; iBand < nBands; iBand++)
2010 : {
2011 12096 : if (!static_cast<VRTRasterBand *>(papoBands[iBand])
2012 6048 : ->IsSourcedRasterBand())
2013 47 : return FALSE;
2014 :
2015 6001 : VRTSourcedRasterBand *poBand =
2016 6001 : static_cast<VRTSourcedRasterBand *>(papoBands[iBand]);
2017 :
2018 : // Do not allow VRTDerivedRasterBand for example
2019 6001 : if (typeid(*poBand) != typeid(VRTSourcedRasterBand))
2020 16 : return FALSE;
2021 :
2022 5985 : if (iBand == 0)
2023 : {
2024 3652 : nSources = poBand->nSources;
2025 3652 : papoSources = poBand->papoSources;
2026 6327 : for (int iSource = 0; iSource < nSources; iSource++)
2027 : {
2028 3678 : if (!papoSources[iSource]->IsSimpleSource())
2029 0 : return FALSE;
2030 :
2031 3678 : VRTSimpleSource *poSource =
2032 3678 : static_cast<VRTSimpleSource *>(papoSources[iSource]);
2033 3678 : if (!EQUAL(poSource->GetType(), "SimpleSource"))
2034 301 : return FALSE;
2035 :
2036 10112 : if (poSource->m_nBand != iBand + 1 ||
2037 3377 : poSource->m_bGetMaskBand || poSource->m_osSrcDSName.empty())
2038 702 : return FALSE;
2039 2675 : osResampling = poSource->GetResampling();
2040 : }
2041 : }
2042 2333 : else if (nSources != poBand->nSources)
2043 : {
2044 0 : return FALSE;
2045 : }
2046 : else
2047 : {
2048 4477 : for (int iSource = 0; iSource < nSources; iSource++)
2049 : {
2050 2388 : if (!poBand->papoSources[iSource]->IsSimpleSource())
2051 0 : return FALSE;
2052 2388 : VRTSimpleSource *poRefSource =
2053 2388 : static_cast<VRTSimpleSource *>(papoSources[iSource]);
2054 :
2055 2388 : VRTSimpleSource *poSource = static_cast<VRTSimpleSource *>(
2056 2388 : poBand->papoSources[iSource]);
2057 2388 : if (!EQUAL(poSource->GetType(), "SimpleSource"))
2058 33 : return FALSE;
2059 6854 : if (poSource->m_nBand != iBand + 1 ||
2060 2355 : poSource->m_bGetMaskBand || poSource->m_osSrcDSName.empty())
2061 211 : return FALSE;
2062 2144 : if (!poSource->IsSameExceptBandNumber(poRefSource))
2063 0 : return FALSE;
2064 2144 : if (osResampling.compare(poSource->GetResampling()) != 0)
2065 0 : return FALSE;
2066 : }
2067 : }
2068 : }
2069 :
2070 2482 : return nSources != 0;
2071 : }
2072 :
2073 : /************************************************************************/
2074 : /* GetSingleSimpleSource() */
2075 : /* */
2076 : /* Returns a non-NULL dataset if the VRT is made of a single source */
2077 : /* that is a simple source, in its full extent, and with all of its */
2078 : /* bands. Basically something produced by : */
2079 : /* gdal_translate src dst.vrt -of VRT (-a_srs / -a_ullr) */
2080 : /************************************************************************/
2081 :
2082 362 : GDALDataset *VRTDataset::GetSingleSimpleSource()
2083 : {
2084 362 : if (!CheckCompatibleForDatasetIO())
2085 119 : return nullptr;
2086 :
2087 243 : VRTSourcedRasterBand *poVRTBand =
2088 243 : static_cast<VRTSourcedRasterBand *>(papoBands[0]);
2089 243 : if (poVRTBand->nSources != 1)
2090 1 : return nullptr;
2091 :
2092 242 : VRTSimpleSource *poSource =
2093 242 : static_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
2094 :
2095 242 : GDALRasterBand *poBand = poSource->GetRasterBand();
2096 242 : if (poBand == nullptr || poSource->GetMaskBandMainBand() != nullptr)
2097 3 : return nullptr;
2098 :
2099 239 : GDALDataset *poSrcDS = poBand->GetDataset();
2100 239 : if (poSrcDS == nullptr)
2101 0 : return nullptr;
2102 :
2103 : /* Check that it uses the full source dataset */
2104 239 : double dfReqXOff = 0.0;
2105 239 : double dfReqYOff = 0.0;
2106 239 : double dfReqXSize = 0.0;
2107 239 : double dfReqYSize = 0.0;
2108 239 : int nReqXOff = 0;
2109 239 : int nReqYOff = 0;
2110 239 : int nReqXSize = 0;
2111 239 : int nReqYSize = 0;
2112 239 : int nOutXOff = 0;
2113 239 : int nOutYOff = 0;
2114 239 : int nOutXSize = 0;
2115 239 : int nOutYSize = 0;
2116 239 : bool bError = false;
2117 478 : if (!poSource->GetSrcDstWindow(
2118 239 : 0, 0, poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(),
2119 : poSrcDS->GetRasterXSize(), poSrcDS->GetRasterYSize(), &dfReqXOff,
2120 : &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
2121 : &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize,
2122 : &nOutYSize, bError))
2123 0 : return nullptr;
2124 :
2125 202 : if (nReqXOff != 0 || nReqYOff != 0 ||
2126 563 : nReqXSize != poSrcDS->GetRasterXSize() ||
2127 122 : nReqYSize != poSrcDS->GetRasterYSize())
2128 119 : return nullptr;
2129 :
2130 120 : if (nOutXOff != 0 || nOutYOff != 0 ||
2131 352 : nOutXSize != poSrcDS->GetRasterXSize() ||
2132 112 : nOutYSize != poSrcDS->GetRasterYSize())
2133 8 : return nullptr;
2134 :
2135 112 : return poSrcDS;
2136 : }
2137 :
2138 : /************************************************************************/
2139 : /* AdviseRead() */
2140 : /************************************************************************/
2141 :
2142 1507 : CPLErr VRTDataset::AdviseRead(int nXOff, int nYOff, int nXSize, int nYSize,
2143 : int nBufXSize, int nBufYSize, GDALDataType eDT,
2144 : int nBandCount, int *panBandList,
2145 : char **papszOptions)
2146 : {
2147 1507 : if (!CheckCompatibleForDatasetIO())
2148 617 : return CE_None;
2149 :
2150 890 : VRTSourcedRasterBand *poVRTBand =
2151 890 : static_cast<VRTSourcedRasterBand *>(papoBands[0]);
2152 890 : if (poVRTBand->nSources != 1)
2153 9 : return CE_None;
2154 :
2155 881 : VRTSimpleSource *poSource =
2156 881 : static_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
2157 :
2158 : /* Find source window and buffer size */
2159 881 : double dfReqXOff = 0.0;
2160 881 : double dfReqYOff = 0.0;
2161 881 : double dfReqXSize = 0.0;
2162 881 : double dfReqYSize = 0.0;
2163 881 : int nReqXOff = 0;
2164 881 : int nReqYOff = 0;
2165 881 : int nReqXSize = 0;
2166 881 : int nReqYSize = 0;
2167 881 : int nOutXOff = 0;
2168 881 : int nOutYOff = 0;
2169 881 : int nOutXSize = 0;
2170 881 : int nOutYSize = 0;
2171 881 : bool bError = false;
2172 881 : if (!poSource->GetSrcDstWindow(nXOff, nYOff, nXSize, nYSize, nBufXSize,
2173 : nBufYSize, &dfReqXOff, &dfReqYOff,
2174 : &dfReqXSize, &dfReqYSize, &nReqXOff,
2175 : &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
2176 : &nOutYOff, &nOutXSize, &nOutYSize, bError))
2177 : {
2178 91 : return bError ? CE_Failure : CE_None;
2179 : }
2180 :
2181 790 : GDALRasterBand *poBand = poSource->GetRasterBand();
2182 790 : if (poBand == nullptr || poSource->GetMaskBandMainBand() != nullptr)
2183 0 : return CE_None;
2184 :
2185 790 : GDALDataset *poSrcDS = poBand->GetDataset();
2186 790 : if (poSrcDS == nullptr)
2187 0 : return CE_None;
2188 :
2189 790 : return poSrcDS->AdviseRead(nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2190 : nOutXSize, nOutYSize, eDT, nBandCount,
2191 790 : panBandList, papszOptions);
2192 : }
2193 :
2194 : /************************************************************************/
2195 : /* IRasterIO() */
2196 : /************************************************************************/
2197 :
2198 1874 : CPLErr VRTDataset::IRasterIO(GDALRWFlag eRWFlag, int nXOff, int nYOff,
2199 : int nXSize, int nYSize, void *pData, int nBufXSize,
2200 : int nBufYSize, GDALDataType eBufType,
2201 : int nBandCount, int *panBandMap,
2202 : GSpacing nPixelSpace, GSpacing nLineSpace,
2203 : GSpacing nBandSpace,
2204 : GDALRasterIOExtraArg *psExtraArg)
2205 : {
2206 : bool bLocalCompatibleForDatasetIO =
2207 1874 : CPL_TO_BOOL(CheckCompatibleForDatasetIO());
2208 1231 : if (bLocalCompatibleForDatasetIO && eRWFlag == GF_Read &&
2209 3105 : (nBufXSize < nXSize || nBufYSize < nYSize) && m_apoOverviews.empty())
2210 : {
2211 5 : int bTried = FALSE;
2212 5 : const CPLErr eErr = TryOverviewRasterIO(
2213 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
2214 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
2215 : nBandSpace, psExtraArg, &bTried);
2216 :
2217 5 : if (bTried)
2218 : {
2219 2 : return eErr;
2220 : }
2221 :
2222 8 : for (int iBand = 0; iBand < nBands; iBand++)
2223 : {
2224 6 : VRTSourcedRasterBand *poBand =
2225 6 : static_cast<VRTSourcedRasterBand *>(papoBands[iBand]);
2226 :
2227 : // If there are overviews, let VRTSourcedRasterBand::IRasterIO()
2228 : // do the job.
2229 6 : if (poBand->GetOverviewCount() != 0)
2230 : {
2231 1 : bLocalCompatibleForDatasetIO = false;
2232 1 : break;
2233 : }
2234 : }
2235 : }
2236 :
2237 : // If resampling with non-nearest neighbour, we need to be careful
2238 : // if the VRT band exposes a nodata value, but the sources do not have it.
2239 : // To also avoid edge effects on sources when downsampling, use the
2240 : // base implementation of IRasterIO() (that is acquiring sources at their
2241 : // nominal resolution, and then downsampling), but only if none of the
2242 : // contributing sources have overviews.
2243 1872 : if (bLocalCompatibleForDatasetIO && eRWFlag == GF_Read &&
2244 1101 : (nXSize != nBufXSize || nYSize != nBufYSize) &&
2245 127 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour)
2246 : {
2247 4 : for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
2248 : {
2249 : VRTSourcedRasterBand *poBand = static_cast<VRTSourcedRasterBand *>(
2250 3 : GetRasterBand(panBandMap[iBandIndex]));
2251 3 : if (!poBand->CanIRasterIOBeForwardedToEachSource(
2252 : eRWFlag, nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
2253 : psExtraArg))
2254 : {
2255 2 : bLocalCompatibleForDatasetIO = false;
2256 2 : break;
2257 : }
2258 : }
2259 : }
2260 :
2261 1872 : if (bLocalCompatibleForDatasetIO && eRWFlag == GF_Read)
2262 : {
2263 3740 : for (int iBandIndex = 0; iBandIndex < nBandCount; iBandIndex++)
2264 : {
2265 : VRTSourcedRasterBand *poBand = static_cast<VRTSourcedRasterBand *>(
2266 2514 : GetRasterBand(panBandMap[iBandIndex]));
2267 :
2268 : /* Dirty little trick to initialize the buffer without doing */
2269 : /* any real I/O */
2270 2514 : const int nSavedSources = poBand->nSources;
2271 2514 : poBand->nSources = 0;
2272 :
2273 2514 : GByte *pabyBandData =
2274 2514 : static_cast<GByte *>(pData) + iBandIndex * nBandSpace;
2275 :
2276 2514 : poBand->IRasterIO(GF_Read, nXOff, nYOff, nXSize, nYSize,
2277 : pabyBandData, nBufXSize, nBufYSize, eBufType,
2278 2514 : nPixelSpace, nLineSpace, psExtraArg);
2279 :
2280 2514 : poBand->nSources = nSavedSources;
2281 : }
2282 :
2283 1226 : CPLErr eErr = CE_None;
2284 1226 : GDALProgressFunc pfnProgressGlobal = psExtraArg->pfnProgress;
2285 1226 : void *pProgressDataGlobal = psExtraArg->pProgressData;
2286 :
2287 : // Use the last band, because when sources reference a GDALProxyDataset,
2288 : // they don't necessary instantiate all underlying rasterbands.
2289 1226 : VRTSourcedRasterBand *poBand =
2290 1226 : static_cast<VRTSourcedRasterBand *>(papoBands[nBands - 1]);
2291 2495 : for (int iSource = 0; eErr == CE_None && iSource < poBand->nSources;
2292 : iSource++)
2293 : {
2294 1269 : psExtraArg->pfnProgress = GDALScaledProgress;
2295 2538 : psExtraArg->pProgressData = GDALCreateScaledProgress(
2296 1269 : 1.0 * iSource / poBand->nSources,
2297 1269 : 1.0 * (iSource + 1) / poBand->nSources, pfnProgressGlobal,
2298 : pProgressDataGlobal);
2299 :
2300 1269 : VRTSimpleSource *poSource =
2301 1269 : static_cast<VRTSimpleSource *>(poBand->papoSources[iSource]);
2302 :
2303 1269 : eErr = poSource->DatasetRasterIO(
2304 : poBand->GetRasterDataType(), nXOff, nYOff, nXSize, nYSize,
2305 : pData, nBufXSize, nBufYSize, eBufType, nBandCount, panBandMap,
2306 : nPixelSpace, nLineSpace, nBandSpace, psExtraArg);
2307 :
2308 1269 : GDALDestroyScaledProgress(psExtraArg->pProgressData);
2309 : }
2310 :
2311 1226 : psExtraArg->pfnProgress = pfnProgressGlobal;
2312 1226 : psExtraArg->pProgressData = pProgressDataGlobal;
2313 :
2314 1226 : return eErr;
2315 : }
2316 :
2317 : CPLErr eErr;
2318 646 : if (eRWFlag == GF_Read &&
2319 646 : psExtraArg->eResampleAlg != GRIORA_NearestNeighbour &&
2320 3 : nBufXSize < nXSize && nBufYSize < nYSize && nBandCount > 1)
2321 : {
2322 : // Force going through VRTSourcedRasterBand::IRasterIO(), otherwise
2323 : // GDALDataset::IRasterIOResampled() would be used without source
2324 : // overviews being potentially used.
2325 2 : eErr = GDALDataset::BandBasedRasterIO(
2326 : eRWFlag, nXOff, nYOff, nXSize, nYSize, pData, nBufXSize, nBufYSize,
2327 : eBufType, nBandCount, panBandMap, nPixelSpace, nLineSpace,
2328 : nBandSpace, psExtraArg);
2329 : }
2330 : else
2331 : {
2332 644 : eErr = GDALDataset::IRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
2333 : pData, nBufXSize, nBufYSize, eBufType,
2334 : nBandCount, panBandMap, nPixelSpace,
2335 : nLineSpace, nBandSpace, psExtraArg);
2336 : }
2337 646 : return eErr;
2338 : }
2339 :
2340 : /************************************************************************/
2341 : /* UnsetPreservedRelativeFilenames() */
2342 : /************************************************************************/
2343 :
2344 104 : void VRTDataset::UnsetPreservedRelativeFilenames()
2345 : {
2346 207 : for (int iBand = 0; iBand < nBands; iBand++)
2347 : {
2348 290 : if (!static_cast<VRTRasterBand *>(papoBands[iBand])
2349 103 : ->IsSourcedRasterBand())
2350 84 : continue;
2351 :
2352 19 : VRTSourcedRasterBand *poBand =
2353 19 : static_cast<VRTSourcedRasterBand *>(papoBands[iBand]);
2354 19 : const int nSources = poBand->nSources;
2355 19 : VRTSource **papoSources = poBand->papoSources;
2356 25 : for (int iSource = 0; iSource < nSources; iSource++)
2357 : {
2358 6 : if (!papoSources[iSource]->IsSimpleSource())
2359 0 : continue;
2360 :
2361 6 : VRTSimpleSource *poSource =
2362 6 : static_cast<VRTSimpleSource *>(papoSources[iSource]);
2363 6 : poSource->UnsetPreservedRelativeFilenames();
2364 : }
2365 : }
2366 104 : }
2367 :
2368 : /************************************************************************/
2369 : /* BuildVirtualOverviews() */
2370 : /************************************************************************/
2371 :
2372 5462 : static bool CheckBandForOverview(GDALRasterBand *poBand,
2373 : GDALRasterBand *&poFirstBand, int &nOverviews,
2374 : std::set<std::pair<int, int>> &oSetOvrSizes,
2375 : std::vector<GDALDataset *> &apoOverviewsBak)
2376 : {
2377 5462 : if (!cpl::down_cast<VRTRasterBand *>(poBand)->IsSourcedRasterBand())
2378 0 : return false;
2379 :
2380 : VRTSourcedRasterBand *poVRTBand =
2381 5462 : cpl::down_cast<VRTSourcedRasterBand *>(poBand);
2382 5462 : if (poVRTBand->nSources != 1)
2383 4237 : return false;
2384 1225 : if (!poVRTBand->papoSources[0]->IsSimpleSource())
2385 0 : return false;
2386 :
2387 : VRTSimpleSource *poSource =
2388 1225 : cpl::down_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
2389 1243 : if (!EQUAL(poSource->GetType(), "SimpleSource") &&
2390 18 : !EQUAL(poSource->GetType(), "ComplexSource"))
2391 0 : return false;
2392 1225 : GDALRasterBand *poSrcBand = poBand->GetBand() == 0
2393 1225 : ? poSource->GetMaskBandMainBand()
2394 1215 : : poSource->GetRasterBand();
2395 1225 : if (poSrcBand == nullptr)
2396 97 : return false;
2397 :
2398 : // To prevent recursion
2399 1128 : apoOverviewsBak.push_back(nullptr);
2400 1128 : const int nOvrCount = poSrcBand->GetOverviewCount();
2401 : oSetOvrSizes.insert(
2402 1128 : std::pair<int, int>(poSrcBand->GetXSize(), poSrcBand->GetYSize()));
2403 1222 : for (int i = 0; i < nOvrCount; ++i)
2404 : {
2405 94 : auto poSrcOvrBand = poSrcBand->GetOverview(i);
2406 94 : if (poSrcOvrBand)
2407 : {
2408 94 : oSetOvrSizes.insert(std::pair<int, int>(poSrcOvrBand->GetXSize(),
2409 188 : poSrcOvrBand->GetYSize()));
2410 : }
2411 : }
2412 1128 : apoOverviewsBak.resize(0);
2413 :
2414 1128 : if (nOvrCount == 0)
2415 1049 : return false;
2416 79 : if (poFirstBand == nullptr)
2417 : {
2418 29 : if (poSrcBand->GetXSize() == 0 || poSrcBand->GetYSize() == 0)
2419 0 : return false;
2420 29 : poFirstBand = poSrcBand;
2421 29 : nOverviews = nOvrCount;
2422 : }
2423 50 : else if (nOvrCount < nOverviews)
2424 0 : nOverviews = nOvrCount;
2425 79 : return true;
2426 : }
2427 :
2428 5435 : void VRTDataset::BuildVirtualOverviews()
2429 : {
2430 : // Currently we expose virtual overviews only if the dataset is made of
2431 : // a single SimpleSource/ComplexSource, in each band.
2432 : // And if the underlying sources have overviews of course
2433 5435 : if (!m_apoOverviews.empty() || !m_apoOverviewsBak.empty())
2434 5417 : return;
2435 :
2436 5401 : int nOverviews = 0;
2437 5401 : GDALRasterBand *poFirstBand = nullptr;
2438 5401 : std::set<std::pair<int, int>> oSetOvrSizes;
2439 :
2440 5478 : for (int iBand = 0; iBand < nBands; iBand++)
2441 : {
2442 5452 : if (!CheckBandForOverview(papoBands[iBand], poFirstBand, nOverviews,
2443 5452 : oSetOvrSizes, m_apoOverviewsBak))
2444 5375 : return;
2445 : }
2446 :
2447 26 : if (m_poMaskBand)
2448 : {
2449 10 : if (!CheckBandForOverview(m_poMaskBand, poFirstBand, nOverviews,
2450 10 : oSetOvrSizes, m_apoOverviewsBak))
2451 8 : return;
2452 : }
2453 18 : if (poFirstBand == nullptr)
2454 : {
2455 : // to make cppcheck happy
2456 0 : CPLAssert(false);
2457 : return;
2458 : }
2459 :
2460 : VRTSourcedRasterBand *l_poVRTBand =
2461 18 : cpl::down_cast<VRTSourcedRasterBand *>(papoBands[0]);
2462 : VRTSimpleSource *poSource =
2463 18 : cpl::down_cast<VRTSimpleSource *>(l_poVRTBand->papoSources[0]);
2464 18 : const double dfDstToSrcXRatio =
2465 18 : poSource->m_dfDstXSize / poSource->m_dfSrcXSize;
2466 18 : const double dfDstToSrcYRatio =
2467 18 : poSource->m_dfDstYSize / poSource->m_dfSrcYSize;
2468 :
2469 40 : for (int j = 0; j < nOverviews; j++)
2470 : {
2471 23 : auto poOvrBand = poFirstBand->GetOverview(j);
2472 23 : if (!poOvrBand)
2473 0 : return;
2474 23 : const double dfXRatio = static_cast<double>(poOvrBand->GetXSize()) /
2475 23 : poFirstBand->GetXSize();
2476 23 : const double dfYRatio = static_cast<double>(poOvrBand->GetYSize()) /
2477 23 : poFirstBand->GetYSize();
2478 23 : if (dfXRatio >= dfDstToSrcXRatio || dfYRatio >= dfDstToSrcYRatio)
2479 : {
2480 5 : continue;
2481 : }
2482 18 : int nOvrXSize = static_cast<int>(0.5 + nRasterXSize * dfXRatio);
2483 18 : int nOvrYSize = static_cast<int>(0.5 + nRasterYSize * dfYRatio);
2484 18 : if (nOvrXSize < 128 || nOvrYSize < 128)
2485 : break;
2486 :
2487 : // Look for a source overview whose size is very close to the
2488 : // theoretical computed one.
2489 33 : for (const auto &ovrSize : oSetOvrSizes)
2490 : {
2491 31 : if (std::abs(ovrSize.first - nOvrXSize) <= 1 &&
2492 15 : std::abs(ovrSize.second - nOvrYSize) <= 1)
2493 : {
2494 15 : nOvrXSize = ovrSize.first;
2495 15 : nOvrYSize = ovrSize.second;
2496 15 : break;
2497 : }
2498 : }
2499 :
2500 17 : VRTDataset *poOvrVDS = new VRTDataset(nOvrXSize, nOvrYSize);
2501 17 : m_apoOverviews.push_back(poOvrVDS);
2502 :
2503 : const auto CreateOverviewBand =
2504 38 : [&poOvrVDS, nOvrXSize, nOvrYSize, dfXRatio,
2505 76 : dfYRatio](VRTSourcedRasterBand *poVRTBand)
2506 : {
2507 : VRTSourcedRasterBand *poOvrVRTBand = new VRTSourcedRasterBand(
2508 38 : poOvrVDS, poVRTBand->GetBand(), poVRTBand->GetRasterDataType(),
2509 38 : nOvrXSize, nOvrYSize);
2510 38 : poOvrVRTBand->CopyCommonInfoFrom(poVRTBand);
2511 38 : poOvrVRTBand->m_bNoDataValueSet = poVRTBand->m_bNoDataValueSet;
2512 38 : poOvrVRTBand->m_dfNoDataValue = poVRTBand->m_dfNoDataValue;
2513 38 : poOvrVRTBand->m_bHideNoDataValue = poVRTBand->m_bHideNoDataValue;
2514 :
2515 : VRTSimpleSource *poSrcSource =
2516 38 : cpl::down_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
2517 38 : VRTSimpleSource *poNewSource = nullptr;
2518 38 : if (EQUAL(poSrcSource->GetType(), "SimpleSource"))
2519 : {
2520 33 : poNewSource =
2521 33 : new VRTSimpleSource(poSrcSource, dfXRatio, dfYRatio);
2522 : }
2523 5 : else if (EQUAL(poSrcSource->GetType(), "ComplexSource"))
2524 : {
2525 5 : poNewSource = new VRTComplexSource(
2526 5 : cpl::down_cast<VRTComplexSource *>(poSrcSource), dfXRatio,
2527 5 : dfYRatio);
2528 : }
2529 : else
2530 : {
2531 0 : CPLAssert(false);
2532 : }
2533 38 : if (poNewSource)
2534 : {
2535 38 : auto poNewSourceBand = poVRTBand->GetBand() == 0
2536 38 : ? poNewSource->GetMaskBandMainBand()
2537 34 : : poNewSource->GetRasterBand();
2538 38 : CPLAssert(poNewSourceBand);
2539 38 : auto poNewSourceBandDS = poNewSourceBand->GetDataset();
2540 38 : if (poNewSourceBandDS)
2541 38 : poNewSourceBandDS->Reference();
2542 38 : poOvrVRTBand->AddSource(poNewSource);
2543 : }
2544 :
2545 38 : return poOvrVRTBand;
2546 17 : };
2547 :
2548 51 : for (int i = 0; i < nBands; i++)
2549 : {
2550 : VRTSourcedRasterBand *poSrcBand =
2551 34 : cpl::down_cast<VRTSourcedRasterBand *>(GetRasterBand(i + 1));
2552 34 : auto poOvrVRTBand = CreateOverviewBand(poSrcBand);
2553 34 : poOvrVDS->SetBand(poOvrVDS->GetRasterCount() + 1, poOvrVRTBand);
2554 : }
2555 :
2556 17 : if (m_poMaskBand)
2557 : {
2558 : VRTSourcedRasterBand *poSrcBand =
2559 4 : cpl::down_cast<VRTSourcedRasterBand *>(m_poMaskBand);
2560 4 : auto poOvrVRTBand = CreateOverviewBand(poSrcBand);
2561 4 : poOvrVDS->SetMaskBand(poOvrVRTBand);
2562 : }
2563 : }
2564 : }
2565 :
2566 : /************************************************************************/
2567 : /* AddVirtualOverview() */
2568 : /************************************************************************/
2569 :
2570 34 : bool VRTDataset::AddVirtualOverview(int nOvFactor, const char *pszResampling)
2571 : {
2572 34 : if (nRasterXSize / nOvFactor == 0 || nRasterYSize / nOvFactor == 0)
2573 : {
2574 1 : return false;
2575 : }
2576 :
2577 66 : CPLStringList argv;
2578 33 : argv.AddString("-of");
2579 33 : argv.AddString("VRT");
2580 33 : argv.AddString("-outsize");
2581 33 : argv.AddString(CPLSPrintf("%d", nRasterXSize / nOvFactor));
2582 33 : argv.AddString(CPLSPrintf("%d", nRasterYSize / nOvFactor));
2583 33 : argv.AddString("-r");
2584 33 : argv.AddString(pszResampling);
2585 :
2586 : GDALTranslateOptions *psOptions =
2587 33 : GDALTranslateOptionsNew(argv.List(), nullptr);
2588 :
2589 : // Add a dummy overview so that BuildVirtualOverviews() doesn't trigger
2590 33 : m_apoOverviews.push_back(nullptr);
2591 33 : CPLAssert(m_bCanTakeRef);
2592 33 : m_bCanTakeRef =
2593 : false; // we don't want hOverviewDS to take a reference on ourselves.
2594 : GDALDatasetH hOverviewDS =
2595 33 : GDALTranslate("", GDALDataset::ToHandle(this), psOptions, nullptr);
2596 33 : m_bCanTakeRef = true;
2597 33 : m_apoOverviews.resize(m_apoOverviews.size() - 1);
2598 :
2599 33 : GDALTranslateOptionsFree(psOptions);
2600 33 : if (hOverviewDS == nullptr)
2601 0 : return false;
2602 :
2603 33 : m_anOverviewFactors.push_back(nOvFactor);
2604 33 : m_apoOverviews.push_back(GDALDataset::FromHandle(hOverviewDS));
2605 33 : return true;
2606 : }
2607 :
2608 : /************************************************************************/
2609 : /* IBuildOverviews() */
2610 : /************************************************************************/
2611 :
2612 28 : CPLErr VRTDataset::IBuildOverviews(const char *pszResampling, int nOverviews,
2613 : const int *panOverviewList, int nListBands,
2614 : const int *panBandList,
2615 : GDALProgressFunc pfnProgress,
2616 : void *pProgressData,
2617 : CSLConstList papszOptions)
2618 : {
2619 28 : if (CPLTestBool(CPLGetConfigOption("VRT_VIRTUAL_OVERVIEWS", "NO")))
2620 : {
2621 13 : SetNeedsFlush();
2622 25 : if (nOverviews == 0 ||
2623 12 : (!m_apoOverviews.empty() && m_anOverviewFactors.empty()))
2624 : {
2625 2 : m_anOverviewFactors.clear();
2626 2 : m_apoOverviewsBak.insert(m_apoOverviewsBak.end(),
2627 : m_apoOverviews.begin(),
2628 4 : m_apoOverviews.end());
2629 2 : m_apoOverviews.clear();
2630 : }
2631 13 : m_osOverviewResampling = pszResampling;
2632 36 : for (int i = 0; i < nOverviews; i++)
2633 : {
2634 23 : if (std::find(m_anOverviewFactors.begin(),
2635 : m_anOverviewFactors.end(),
2636 23 : panOverviewList[i]) == m_anOverviewFactors.end())
2637 : {
2638 23 : AddVirtualOverview(panOverviewList[i], pszResampling);
2639 : }
2640 : }
2641 13 : return CE_None;
2642 : }
2643 :
2644 15 : if (!oOvManager.IsInitialized())
2645 : {
2646 1 : const char *pszDesc = GetDescription();
2647 1 : if (pszDesc[0])
2648 : {
2649 1 : oOvManager.Initialize(this, pszDesc);
2650 : }
2651 : }
2652 :
2653 : // Make implicit overviews invisible, but do not destroy them in case they
2654 : // are already used. Should the client do that? Behavior might undefined
2655 : // in GDAL API?
2656 15 : if (!m_apoOverviews.empty())
2657 : {
2658 2 : m_apoOverviewsBak.insert(m_apoOverviewsBak.end(),
2659 4 : m_apoOverviews.begin(), m_apoOverviews.end());
2660 2 : m_apoOverviews.clear();
2661 : }
2662 : else
2663 : {
2664 : // Add a dummy overview so that GDALDataset::IBuildOverviews()
2665 : // doesn't manage to get a virtual implicit overview.
2666 13 : m_apoOverviews.push_back(nullptr);
2667 : }
2668 :
2669 15 : CPLErr eErr = GDALDataset::IBuildOverviews(
2670 : pszResampling, nOverviews, panOverviewList, nListBands, panBandList,
2671 : pfnProgress, pProgressData, papszOptions);
2672 :
2673 15 : m_apoOverviews.clear();
2674 15 : return eErr;
2675 : }
2676 :
2677 : /************************************************************************/
2678 : /* GetShiftedDataset() */
2679 : /* */
2680 : /* Returns true if the VRT is made of a single source that is a simple */
2681 : /* in its full resolution. */
2682 : /************************************************************************/
2683 :
2684 49 : bool VRTDataset::GetShiftedDataset(int nXOff, int nYOff, int nXSize, int nYSize,
2685 : GDALDataset *&poSrcDataset, int &nSrcXOff,
2686 : int &nSrcYOff)
2687 : {
2688 49 : if (!CheckCompatibleForDatasetIO())
2689 40 : return false;
2690 :
2691 9 : VRTSourcedRasterBand *poVRTBand =
2692 9 : static_cast<VRTSourcedRasterBand *>(papoBands[0]);
2693 9 : if (poVRTBand->nSources != 1)
2694 0 : return false;
2695 :
2696 9 : VRTSimpleSource *poSource =
2697 9 : static_cast<VRTSimpleSource *>(poVRTBand->papoSources[0]);
2698 :
2699 9 : GDALRasterBand *poBand = poSource->GetRasterBand();
2700 9 : if (!poBand || poSource->GetMaskBandMainBand())
2701 4 : return false;
2702 :
2703 5 : poSrcDataset = poBand->GetDataset();
2704 5 : if (!poSrcDataset)
2705 0 : return false;
2706 :
2707 5 : double dfReqXOff = 0.0;
2708 5 : double dfReqYOff = 0.0;
2709 5 : double dfReqXSize = 0.0;
2710 5 : double dfReqYSize = 0.0;
2711 5 : int nReqXOff = 0;
2712 5 : int nReqYOff = 0;
2713 5 : int nReqXSize = 0;
2714 5 : int nReqYSize = 0;
2715 5 : int nOutXOff = 0;
2716 5 : int nOutYOff = 0;
2717 5 : int nOutXSize = 0;
2718 5 : int nOutYSize = 0;
2719 5 : bool bError = false;
2720 5 : if (!poSource->GetSrcDstWindow(nXOff, nYOff, nXSize, nYSize, nXSize, nYSize,
2721 : &dfReqXOff, &dfReqYOff, &dfReqXSize,
2722 : &dfReqYSize, &nReqXOff, &nReqYOff,
2723 : &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
2724 : &nOutXSize, &nOutYSize, bError))
2725 0 : return false;
2726 :
2727 5 : if (nReqXSize != nXSize || nReqYSize != nYSize || nReqXSize != nOutXSize ||
2728 5 : nReqYSize != nOutYSize)
2729 0 : return false;
2730 :
2731 5 : nSrcXOff = nReqXOff;
2732 5 : nSrcYOff = nReqYOff;
2733 5 : return true;
2734 : }
2735 :
2736 : /************************************************************************/
2737 : /* GetCompressionFormats() */
2738 : /************************************************************************/
2739 :
2740 0 : CPLStringList VRTDataset::GetCompressionFormats(int nXOff, int nYOff,
2741 : int nXSize, int nYSize,
2742 : int nBandCount,
2743 : const int *panBandList)
2744 : {
2745 : GDALDataset *poSrcDataset;
2746 : int nSrcXOff;
2747 : int nSrcYOff;
2748 0 : if (!GetShiftedDataset(nXOff, nYOff, nXSize, nYSize, poSrcDataset, nSrcXOff,
2749 : nSrcYOff))
2750 0 : return CPLStringList();
2751 : return poSrcDataset->GetCompressionFormats(nSrcXOff, nSrcYOff, nXSize,
2752 0 : nYSize, nBandCount, panBandList);
2753 : }
2754 :
2755 : /************************************************************************/
2756 : /* ReadCompressedData() */
2757 : /************************************************************************/
2758 :
2759 49 : CPLErr VRTDataset::ReadCompressedData(const char *pszFormat, int nXOff,
2760 : int nYOff, int nXSize, int nYSize,
2761 : int nBandCount, const int *panBandList,
2762 : void **ppBuffer, size_t *pnBufferSize,
2763 : char **ppszDetailedFormat)
2764 : {
2765 : GDALDataset *poSrcDataset;
2766 : int nSrcXOff;
2767 : int nSrcYOff;
2768 49 : if (!GetShiftedDataset(nXOff, nYOff, nXSize, nYSize, poSrcDataset, nSrcXOff,
2769 : nSrcYOff))
2770 44 : return CE_Failure;
2771 5 : return poSrcDataset->ReadCompressedData(
2772 : pszFormat, nSrcXOff, nSrcYOff, nXSize, nYSize, nBandCount, panBandList,
2773 5 : ppBuffer, pnBufferSize, ppszDetailedFormat);
2774 : }
2775 :
2776 : /************************************************************************/
2777 : /* ClearStatistics() */
2778 : /************************************************************************/
2779 :
2780 2 : void VRTDataset::ClearStatistics()
2781 : {
2782 6 : for (int i = 1; i <= nBands; ++i)
2783 : {
2784 4 : bool bChanged = false;
2785 4 : GDALRasterBand *poBand = GetRasterBand(i);
2786 4 : CSLConstList papszOldMD = poBand->GetMetadata();
2787 8 : CPLStringList aosNewMD;
2788 14 : for (const char *pszMDItem : cpl::Iterate(papszOldMD))
2789 : {
2790 10 : if (STARTS_WITH_CI(pszMDItem, "STATISTICS_"))
2791 : {
2792 10 : bChanged = true;
2793 : }
2794 : else
2795 : {
2796 0 : aosNewMD.AddString(pszMDItem);
2797 : }
2798 : }
2799 4 : if (bChanged)
2800 : {
2801 2 : poBand->SetMetadata(aosNewMD.List());
2802 : }
2803 : }
2804 :
2805 2 : GDALDataset::ClearStatistics();
2806 2 : }
2807 :
2808 : /************************************************************************/
2809 : /* BuildSourceFilename() */
2810 : /************************************************************************/
2811 :
2812 : /* static */
2813 1528 : std::string VRTDataset::BuildSourceFilename(const char *pszFilename,
2814 : const char *pszVRTPath,
2815 : bool bRelativeToVRT)
2816 : {
2817 1528 : std::string osSrcDSName;
2818 1528 : if (pszVRTPath != nullptr && bRelativeToVRT)
2819 : {
2820 : // Try subdatasetinfo API first
2821 : // Note: this will become the only branch when subdatasetinfo will become
2822 : // available for NITF_IM, RASTERLITE and TILEDB
2823 914 : const auto oSubDSInfo{GDALGetSubdatasetInfo(pszFilename)};
2824 914 : if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
2825 : {
2826 8 : auto path{oSubDSInfo->GetPathComponent()};
2827 8 : osSrcDSName = oSubDSInfo->ModifyPathComponent(
2828 4 : CPLProjectRelativeFilename(pszVRTPath, path.c_str()));
2829 4 : GDALDestroySubdatasetInfo(oSubDSInfo);
2830 : }
2831 : else
2832 : {
2833 910 : bool bDone = false;
2834 5450 : for (const char *pszSyntax : VRTDataset::apszSpecialSyntax)
2835 : {
2836 4542 : CPLString osPrefix(pszSyntax);
2837 4542 : osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
2838 4542 : if (pszSyntax[osPrefix.size()] == '"')
2839 908 : osPrefix += '"';
2840 4542 : if (EQUALN(pszFilename, osPrefix, osPrefix.size()))
2841 : {
2842 2 : if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
2843 : {
2844 2 : const char *pszLastPart = strrchr(pszFilename, ':') + 1;
2845 : // CSV:z:/foo.xyz
2846 2 : if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
2847 0 : pszLastPart - pszFilename >= 3 &&
2848 0 : pszLastPart[-3] == ':')
2849 : {
2850 0 : pszLastPart -= 2;
2851 : }
2852 2 : CPLString osPrefixFilename = pszFilename;
2853 2 : osPrefixFilename.resize(pszLastPart - pszFilename);
2854 : osSrcDSName =
2855 4 : osPrefixFilename +
2856 2 : CPLProjectRelativeFilename(pszVRTPath, pszLastPart);
2857 2 : bDone = true;
2858 : }
2859 0 : else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
2860 : "{FILENAME}"))
2861 : {
2862 0 : CPLString osFilename(pszFilename + osPrefix.size());
2863 0 : size_t nPos = 0;
2864 0 : if (osFilename.size() >= 3 && osFilename[1] == ':' &&
2865 0 : (osFilename[2] == '\\' || osFilename[2] == '/'))
2866 0 : nPos = 2;
2867 0 : nPos = osFilename.find(
2868 0 : pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
2869 : nPos);
2870 0 : if (nPos != std::string::npos)
2871 : {
2872 0 : const CPLString osSuffix = osFilename.substr(nPos);
2873 0 : osFilename.resize(nPos);
2874 0 : osSrcDSName = osPrefix +
2875 : CPLProjectRelativeFilename(
2876 0 : pszVRTPath, osFilename) +
2877 0 : osSuffix;
2878 0 : bDone = true;
2879 : }
2880 : }
2881 2 : break;
2882 : }
2883 : }
2884 910 : if (!bDone)
2885 : {
2886 : osSrcDSName =
2887 908 : CPLProjectRelativeFilename(pszVRTPath, pszFilename);
2888 : }
2889 914 : }
2890 : }
2891 : else
2892 : {
2893 614 : osSrcDSName = pszFilename;
2894 : }
2895 1528 : return osSrcDSName;
2896 : }
2897 :
2898 : /*! @endcond */
|