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