Coverage Report

Created: 2025-06-09 08:44

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