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