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