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