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