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