• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

OSGeo / gdal / 17249656951

26 Aug 2025 08:27PM UTC coverage: 71.175% (+0.004%) from 71.171%
17249656951

Pull #12942

github

web-flow
Merge 49c3e5f58 into 4e2b27da8
Pull Request #12942: VSIFilesystemHandler: make Open() and CreateOnlyVisibleAtCloseTime() return a VSIVirtualHandleUniquePtr

112 of 117 new or added lines in 22 files covered. (95.73%)

62 existing lines in 39 files now uncovered.

579216 of 813789 relevant lines covered (71.18%)

292108.69 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.26
/frmts/vrt/vrtsources.cpp
1
/******************************************************************************
2
 *
3
 * Project:  Virtual GDAL Datasets
4
 * Purpose:  Implementation of VRTSimpleSource, VRTFuncSource and
5
 *           VRTAveragedSource.
6
 * Author:   Frank Warmerdam <warmerdam@pobox.com>
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2001, Frank Warmerdam <warmerdam@pobox.com>
10
 * Copyright (c) 2008-2013, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 ****************************************************************************/
14

15
#include "gdal_vrt.h"
16
#include "vrtdataset.h"
17

18
#include <cassert>
19
#include <climits>
20
#include <cmath>
21
#include <cstddef>
22
#include <cstdio>
23
#include <cstdlib>
24
#include <cstring>
25
#include <algorithm>
26
#include <limits>
27
#include <string>
28

29
#include "cpl_conv.h"
30
#include "cpl_error.h"
31
#include "cpl_hash_set.h"
32
#include "cpl_minixml.h"
33
#include "cpl_progress.h"
34
#include "cpl_string.h"
35
#include "cpl_vsi.h"
36
#include "gdal.h"
37
#include "gdal_priv.h"
38
#include "gdal_proxy.h"
39
#include "gdal_priv_templates.hpp"
40

41
/*! @cond Doxygen_Suppress */
42

43
// #define DEBUG_VERBOSE 1
44

45
/************************************************************************/
46
/* ==================================================================== */
47
/*                             VRTSource                                */
48
/* ==================================================================== */
49
/************************************************************************/
50

51
VRTSource::~VRTSource()
247,180✔
52
{
53
}
247,180✔
54

55
/************************************************************************/
56
/*                             GetFileList()                            */
57
/************************************************************************/
58

59
void VRTSource::GetFileList(char *** /* ppapszFileList */, int * /* pnSize */,
×
60
                            int * /* pnMaxSize */, CPLHashSet * /* hSetFiles */)
61
{
62
}
×
63

64
/************************************************************************/
65
/* ==================================================================== */
66
/*                          VRTSimpleSource                             */
67
/* ==================================================================== */
68
/************************************************************************/
69

70
/************************************************************************/
71
/*                          VRTSimpleSource()                           */
72
/************************************************************************/
73

74
VRTSimpleSource::VRTSimpleSource() = default;
75

76
/************************************************************************/
77
/*                          VRTSimpleSource()                           */
78
/************************************************************************/
79

80
VRTSimpleSource::VRTSimpleSource(const VRTSimpleSource *poSrcSource,
85✔
81
                                 double dfXDstRatio, double dfYDstRatio)
85✔
82
    : m_poMapSharedSources(poSrcSource->m_poMapSharedSources),
85✔
83
      m_poRasterBand(poSrcSource->m_poRasterBand),
85✔
84
      m_poMaskBandMainBand(poSrcSource->m_poMaskBandMainBand),
85✔
85
      m_aosOpenOptionsOri(poSrcSource->m_aosOpenOptionsOri),
85✔
86
      m_aosOpenOptions(poSrcSource->m_aosOpenOptions),
85✔
87
      m_bSrcDSNameFromVRT(poSrcSource->m_bSrcDSNameFromVRT),
85✔
88
      m_nBand(poSrcSource->m_nBand),
85✔
89
      m_bGetMaskBand(poSrcSource->m_bGetMaskBand),
85✔
90
      m_dfSrcXOff(poSrcSource->m_dfSrcXOff),
85✔
91
      m_dfSrcYOff(poSrcSource->m_dfSrcYOff),
85✔
92
      m_dfSrcXSize(poSrcSource->m_dfSrcXSize),
85✔
93
      m_dfSrcYSize(poSrcSource->m_dfSrcYSize),
85✔
94
      m_nMaxValue(poSrcSource->m_nMaxValue), m_bRelativeToVRTOri(-1),
85✔
95
      m_nExplicitSharedStatus(poSrcSource->m_nExplicitSharedStatus),
85✔
96
      m_osSrcDSName(poSrcSource->m_osSrcDSName),
85✔
97
      m_bDropRefOnSrcBand(poSrcSource->m_bDropRefOnSrcBand)
85✔
98
{
99
    if (!poSrcSource->IsSrcWinSet() && !poSrcSource->IsDstWinSet() &&
85✔
100
        (dfXDstRatio != 1.0 || dfYDstRatio != 1.0))
×
101
    {
102
        auto l_band = GetRasterBand();
1✔
103
        if (l_band)
1✔
104
        {
105
            m_dfSrcXOff = 0;
1✔
106
            m_dfSrcYOff = 0;
1✔
107
            m_dfSrcXSize = l_band->GetXSize();
1✔
108
            m_dfSrcYSize = l_band->GetYSize();
1✔
109
            m_dfDstXOff = 0;
1✔
110
            m_dfDstYOff = 0;
1✔
111
            m_dfDstXSize = l_band->GetXSize() * dfXDstRatio;
1✔
112
            m_dfDstYSize = l_band->GetYSize() * dfYDstRatio;
1✔
113
        }
114
    }
115
    else if (poSrcSource->IsDstWinSet())
84✔
116
    {
117
        m_dfDstXOff = poSrcSource->m_dfDstXOff * dfXDstRatio;
84✔
118
        m_dfDstYOff = poSrcSource->m_dfDstYOff * dfYDstRatio;
84✔
119
        m_dfDstXSize = poSrcSource->m_dfDstXSize * dfXDstRatio;
84✔
120
        m_dfDstYSize = poSrcSource->m_dfDstYSize * dfYDstRatio;
84✔
121
    }
122
}
85✔
123

124
/************************************************************************/
125
/*                          ~VRTSimpleSource()                          */
126
/************************************************************************/
127

128
VRTSimpleSource::~VRTSimpleSource()
495,580✔
129

130
{
131
    if (!m_bDropRefOnSrcBand)
247,136✔
132
        return;
407✔
133

134
    if (m_poMaskBandMainBand != nullptr)
246,729✔
135
    {
136
        if (m_poMaskBandMainBand->GetDataset() != nullptr)
63✔
137
        {
138
            m_poMaskBandMainBand->GetDataset()->ReleaseRef();
63✔
139
        }
140
    }
141
    else if (m_poRasterBand != nullptr &&
490,716✔
142
             m_poRasterBand->GetDataset() != nullptr)
244,050✔
143
    {
144
        m_poRasterBand->GetDataset()->ReleaseRef();
244,050✔
145
    }
146
}
493,545✔
147

148
/************************************************************************/
149
/*                           GetTypeStatic()                            */
150
/************************************************************************/
151

152
const char *VRTSimpleSource::GetTypeStatic()
458,924✔
153
{
154
    static const char *TYPE = "SimpleSource";
155
    return TYPE;
458,924✔
156
}
157

158
/************************************************************************/
159
/*                            GetType()                                 */
160
/************************************************************************/
161

162
const char *VRTSimpleSource::GetType() const
126,728✔
163
{
164
    return GetTypeStatic();
126,728✔
165
}
166

167
/************************************************************************/
168
/*                           FlushCache()                               */
169
/************************************************************************/
170

171
CPLErr VRTSimpleSource::FlushCache(bool bAtClosing)
312,828✔
172

173
{
174
    if (m_poMaskBandMainBand != nullptr)
312,828✔
175
    {
176
        return m_poMaskBandMainBand->FlushCache(bAtClosing);
15✔
177
    }
178
    else if (m_poRasterBand != nullptr)
312,813✔
179
    {
180
        return m_poRasterBand->FlushCache(bAtClosing);
310,165✔
181
    }
182
    return CE_None;
2,648✔
183
}
184

185
/************************************************************************/
186
/*                    UnsetPreservedRelativeFilenames()                 */
187
/************************************************************************/
188

189
void VRTSimpleSource::UnsetPreservedRelativeFilenames()
106✔
190
{
191
    if (m_bRelativeToVRTOri &&
290✔
192
        !STARTS_WITH(m_osSourceFileNameOri.c_str(), "http://") &&
184✔
193
        !STARTS_WITH(m_osSourceFileNameOri.c_str(), "https://"))
78✔
194
    {
195
        m_bRelativeToVRTOri = -1;
78✔
196
        m_osSourceFileNameOri = "";
78✔
197
    }
198
}
106✔
199

200
/************************************************************************/
201
/*                             SetSrcBand()                             */
202
/************************************************************************/
203

204
void VRTSimpleSource::SetSrcBand(const char *pszFilename, int nBand)
463✔
205

206
{
207
    m_nBand = nBand;
463✔
208
    m_osSrcDSName = pszFilename;
463✔
209
}
463✔
210

211
/************************************************************************/
212
/*                             SetSrcBand()                             */
213
/************************************************************************/
214

215
void VRTSimpleSource::SetSrcBand(GDALRasterBand *poNewSrcBand)
142,070✔
216

217
{
218
    m_poRasterBand = poNewSrcBand;
142,070✔
219
    m_nBand = m_poRasterBand->GetBand();
142,070✔
220
    auto poDS = poNewSrcBand->GetDataset();
142,070✔
221
    if (poDS != nullptr)
142,070✔
222
    {
223
        m_osSrcDSName = poDS->GetDescription();
142,070✔
224
        m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
142,070✔
225
        m_aosOpenOptionsOri = m_aosOpenOptions;
142,070✔
226
    }
227
}
142,070✔
228

229
/************************************************************************/
230
/*                      SetSourceDatasetName()                          */
231
/************************************************************************/
232

233
void VRTSimpleSource::SetSourceDatasetName(const char *pszFilename,
7✔
234
                                           bool bRelativeToVRT)
235
{
236
    CPLAssert(m_nBand >= 0);
7✔
237
    m_osSrcDSName = pszFilename;
7✔
238
    m_osSourceFileNameOri = pszFilename;
7✔
239
    m_bRelativeToVRTOri = bRelativeToVRT;
7✔
240
}
7✔
241

242
/************************************************************************/
243
/*                          SetSrcMaskBand()                            */
244
/************************************************************************/
245

246
// poSrcBand is not the mask band, but the band from which the mask band is
247
// taken.
248
void VRTSimpleSource::SetSrcMaskBand(GDALRasterBand *poNewSrcBand)
44✔
249

250
{
251
    m_poRasterBand = poNewSrcBand->GetMaskBand();
44✔
252
    m_poMaskBandMainBand = poNewSrcBand;
44✔
253
    m_nBand = poNewSrcBand->GetBand();
44✔
254
    auto poDS = poNewSrcBand->GetDataset();
44✔
255
    if (poDS != nullptr)
44✔
256
    {
257
        m_osSrcDSName = poDS->GetDescription();
44✔
258
        m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
44✔
259
        m_aosOpenOptionsOri = m_aosOpenOptions;
44✔
260
    }
261
    m_bGetMaskBand = true;
44✔
262
}
44✔
263

264
/************************************************************************/
265
/*                         RoundIfCloseToInt()                          */
266
/************************************************************************/
267

268
static double RoundIfCloseToInt(double dfValue)
2,604,260✔
269
{
270
    double dfClosestInt = floor(dfValue + 0.5);
2,604,260✔
271
    return (fabs(dfValue - dfClosestInt) < 1e-3) ? dfClosestInt : dfValue;
2,604,260✔
272
}
273

274
/************************************************************************/
275
/*                            SetSrcWindow()                            */
276
/************************************************************************/
277

278
void VRTSimpleSource::SetSrcWindow(double dfNewXOff, double dfNewYOff,
145,720✔
279
                                   double dfNewXSize, double dfNewYSize)
280

281
{
282
    m_dfSrcXOff = RoundIfCloseToInt(dfNewXOff);
145,720✔
283
    m_dfSrcYOff = RoundIfCloseToInt(dfNewYOff);
145,720✔
284
    m_dfSrcXSize = RoundIfCloseToInt(dfNewXSize);
145,720✔
285
    m_dfSrcYSize = RoundIfCloseToInt(dfNewYSize);
145,720✔
286
}
145,720✔
287

288
/************************************************************************/
289
/*                            SetDstWindow()                            */
290
/************************************************************************/
291

292
void VRTSimpleSource::SetDstWindow(double dfNewXOff, double dfNewYOff,
145,719✔
293
                                   double dfNewXSize, double dfNewYSize)
294

295
{
296
    m_dfDstXOff = RoundIfCloseToInt(dfNewXOff);
145,719✔
297
    m_dfDstYOff = RoundIfCloseToInt(dfNewYOff);
145,719✔
298
    m_dfDstXSize = RoundIfCloseToInt(dfNewXSize);
145,719✔
299
    m_dfDstYSize = RoundIfCloseToInt(dfNewYSize);
145,719✔
300
}
145,719✔
301

302
/************************************************************************/
303
/*                            GetDstWindow()                            */
304
/************************************************************************/
305

306
void VRTSimpleSource::GetDstWindow(double &dfDstXOff, double &dfDstYOff,
527✔
307
                                   double &dfDstXSize, double &dfDstYSize) const
308
{
309
    dfDstXOff = m_dfDstXOff;
527✔
310
    dfDstYOff = m_dfDstYOff;
527✔
311
    dfDstXSize = m_dfDstXSize;
527✔
312
    dfDstYSize = m_dfDstYSize;
527✔
313
}
527✔
314

315
/************************************************************************/
316
/*                        DstWindowIntersects()                         */
317
/************************************************************************/
318

319
bool VRTSimpleSource::DstWindowIntersects(double dfXOff, double dfYOff,
1,128✔
320
                                          double dfXSize, double dfYSize) const
321
{
322
    return IsDstWinSet() && m_dfDstXOff + m_dfDstXSize > dfXOff &&
2,247✔
323
           m_dfDstYOff + m_dfDstYSize > dfYOff &&
1,119✔
324
           m_dfDstXOff < dfXOff + dfXSize && m_dfDstYOff < dfYOff + dfYSize;
2,247✔
325
}
326

327
/************************************************************************/
328
/*                            IsSlowSource()                            */
329
/************************************************************************/
330

331
static bool IsSlowSource(const char *pszSrcName)
2,522✔
332
{
333
    return strstr(pszSrcName, "/vsicurl/http") != nullptr ||
5,044✔
334
           strstr(pszSrcName, "/vsicurl/ftp") != nullptr ||
5,044✔
335
           (strstr(pszSrcName, "/vsicurl?") != nullptr &&
2,522✔
336
            strstr(pszSrcName, "&url=http") != nullptr);
2,522✔
337
}
338

339
/************************************************************************/
340
/*                         AddSourceFilenameNode()                      */
341
/************************************************************************/
342

343
void VRTSimpleSource::AddSourceFilenameNode(const char *pszVRTPath,
2,588✔
344
                                            CPLXMLNode *psSrc)
345
{
346

347
    VSIStatBufL sStat;
348
    int bRelativeToVRT = FALSE;  // TODO(schwehr): Make this a bool?
2,588✔
349
    std::string osSourceFilename;
5,176✔
350

351
    if (m_bRelativeToVRTOri >= 0)
2,588✔
352
    {
353
        osSourceFilename = m_osSourceFileNameOri;
66✔
354
        bRelativeToVRT = m_bRelativeToVRTOri;
66✔
355
    }
356
    else if (IsSlowSource(m_osSrcDSName))
2,522✔
357
    {
358
        // Testing the existence of remote resources can be excruciating
359
        // slow, so let's just suppose they exist.
360
        osSourceFilename = m_osSrcDSName;
×
361
        bRelativeToVRT = FALSE;
×
362
    }
363
    // If this isn't actually a file, don't even try to know if it is a
364
    // relative path. It can't be !, and unfortunately CPLIsFilenameRelative()
365
    // can only work with strings that are filenames To be clear
366
    // NITF_TOC_ENTRY:CADRG_JOG-A_250K_1_0:some_path isn't a relative file
367
    // path.
368
    else if (VSIStatExL(m_osSrcDSName, &sStat, VSI_STAT_EXISTS_FLAG) != 0)
2,522✔
369
    {
370
        osSourceFilename = m_osSrcDSName;
73✔
371
        bRelativeToVRT = FALSE;
73✔
372

373
        // Try subdatasetinfo API first
374
        // Note: this will become the only branch when subdatasetinfo will become
375
        //       available for NITF_IM, RASTERLITE and TILEDB
376
        const auto oSubDSInfo{GDALGetSubdatasetInfo(osSourceFilename.c_str())};
73✔
377
        if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
73✔
378
        {
379
            auto path{oSubDSInfo->GetPathComponent()};
8✔
380
            std::string relPath{CPLExtractRelativePath(pszVRTPath, path.c_str(),
381
                                                       &bRelativeToVRT)};
8✔
382
            osSourceFilename = oSubDSInfo->ModifyPathComponent(relPath);
4✔
383
            GDALDestroySubdatasetInfo(oSubDSInfo);
4✔
384
        }
385
        else
386
        {
387
            for (const char *pszSyntax :
330✔
388
                 GDALDataset::apszSpecialSubDatasetSyntax)
399✔
389
            {
390
                CPLString osPrefix(pszSyntax);
333✔
391
                osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
333✔
392
                if (pszSyntax[osPrefix.size()] == '"')
333✔
393
                    osPrefix += '"';
66✔
394
                if (EQUALN(osSourceFilename.c_str(), osPrefix, osPrefix.size()))
333✔
395
                {
396
                    if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
3✔
397
                    {
398
                        const char *pszLastPart =
399
                            strrchr(osSourceFilename.c_str(), ':') + 1;
3✔
400
                        // CSV:z:/foo.xyz
401
                        if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
1✔
402
                            pszLastPart - osSourceFilename.c_str() >= 3 &&
6✔
403
                            pszLastPart[-3] == ':')
2✔
404
                            pszLastPart -= 2;
×
405
                        CPLString osPrefixFilename(osSourceFilename);
3✔
406
                        osPrefixFilename.resize(pszLastPart -
3✔
407
                                                osSourceFilename.c_str());
3✔
408
                        osSourceFilename = CPLExtractRelativePath(
409
                            pszVRTPath, pszLastPart, &bRelativeToVRT);
3✔
410
                        osSourceFilename = osPrefixFilename + osSourceFilename;
3✔
411
                    }
412
                    else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
×
413
                                            "{FILENAME}"))
414
                    {
415
                        CPLString osFilename(osSourceFilename.c_str() +
×
416
                                             osPrefix.size());
×
417
                        size_t nPos = 0;
×
418
                        if (osFilename.size() >= 3 && osFilename[1] == ':' &&
×
419
                            (osFilename[2] == '\\' || osFilename[2] == '/'))
×
420
                            nPos = 2;
×
421
                        nPos = osFilename.find(
×
422
                            pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
×
423
                            nPos);
424
                        if (nPos != std::string::npos)
×
425
                        {
426
                            const CPLString osSuffix = osFilename.substr(nPos);
×
427
                            osFilename.resize(nPos);
×
428
                            osSourceFilename = CPLExtractRelativePath(
429
                                pszVRTPath, osFilename, &bRelativeToVRT);
×
430
                            osSourceFilename =
431
                                osPrefix + osSourceFilename + osSuffix;
×
432
                        }
433
                    }
434
                    break;
3✔
435
                }
436
            }
437
        }
438
    }
439
    else
440
    {
441
        std::string osVRTFilename = pszVRTPath;
4,898✔
442
        std::string osSourceDataset = m_osSrcDSName;
4,898✔
443
        char *pszCurDir = CPLGetCurrentDir();
2,449✔
444
        if (CPLIsFilenameRelative(osSourceDataset.c_str()) &&
2,449✔
445
            !CPLIsFilenameRelative(osVRTFilename.c_str()) &&
2,449✔
446
            pszCurDir != nullptr)
447
        {
448
            osSourceDataset = CPLFormFilenameSafe(
184✔
449
                pszCurDir, osSourceDataset.c_str(), nullptr);
92✔
450
        }
451
        else if (!CPLIsFilenameRelative(osSourceDataset.c_str()) &&
2,357✔
452
                 CPLIsFilenameRelative(osVRTFilename.c_str()) &&
2,357✔
453
                 pszCurDir != nullptr)
454
        {
455
            osVRTFilename =
456
                CPLFormFilenameSafe(pszCurDir, osVRTFilename.c_str(), nullptr);
83✔
457
        }
458
        CPLFree(pszCurDir);
2,449✔
459
        osSourceFilename = CPLExtractRelativePath(
460
            osVRTFilename.c_str(), osSourceDataset.c_str(), &bRelativeToVRT);
2,449✔
461
    }
462

463
    CPLSetXMLValue(psSrc, "SourceFilename", osSourceFilename.c_str());
2,588✔
464

465
    CPLCreateXMLNode(CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
2,588✔
466
                                      CXT_Attribute, "relativeToVRT"),
467
                     CXT_Text, bRelativeToVRT ? "1" : "0");
2,588✔
468

469
    // Determine if we must write the shared attribute. The config option
470
    // will override the m_nExplicitSharedStatus value
471
    const char *pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
2,588✔
472
    if ((pszShared == nullptr && m_nExplicitSharedStatus == 0) ||
2,588✔
473
        (pszShared != nullptr && !CPLTestBool(pszShared)))
×
474
    {
475
        CPLCreateXMLNode(
×
476
            CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
477
                             CXT_Attribute, "shared"),
478
            CXT_Text, "0");
479
    }
480
}
2,588✔
481

482
/************************************************************************/
483
/*                           SerializeToXML()                           */
484
/************************************************************************/
485

486
CPLXMLNode *VRTSimpleSource::SerializeToXML(const char *pszVRTPath)
2,629✔
487

488
{
489
    CPLXMLNode *const psSrc =
490
        CPLCreateXMLNode(nullptr, CXT_Element, GetTypeStatic());
2,629✔
491

492
    if (!m_osResampling.empty())
2,629✔
493
    {
494
        CPLCreateXMLNode(CPLCreateXMLNode(psSrc, CXT_Attribute, "resampling"),
24✔
495
                         CXT_Text, m_osResampling.c_str());
496
    }
497

498
    if (!m_osName.empty())
2,629✔
499
    {
500
        CPLAddXMLAttributeAndValue(psSrc, "name", m_osName.c_str());
73✔
501
    }
502

503
    if (m_bSrcDSNameFromVRT)
2,629✔
504
    {
505
        CPLAddXMLChild(psSrc, CPLParseXMLString(m_osSrcDSName.c_str()));
1✔
506
    }
507
    else
508
    {
509
        bool bDone = false;
2,628✔
510
        if (m_osSrcDSName.empty() && m_poRasterBand)
2,628✔
511
        {
512
            auto poSrcDS = m_poRasterBand->GetDataset();
100✔
513
            if (poSrcDS)
100✔
514
            {
515
                VRTDataset *poSrcVRTDS = nullptr;
100✔
516
                // For GDALComputedDataset
517
                void *pHandle = poSrcDS->GetInternalHandle("VRT_DATASET");
100✔
518
                if (pHandle && poSrcDS->GetInternalHandle(nullptr) == nullptr)
100✔
519
                {
520
                    poSrcVRTDS = static_cast<VRTDataset *>(pHandle);
40✔
521
                }
522
                else
523
                {
524
                    poSrcVRTDS = dynamic_cast<VRTDataset *>(poSrcDS);
60✔
525
                }
526
                if (poSrcVRTDS)
100✔
527
                {
528
                    poSrcVRTDS->UnsetPreservedRelativeFilenames();
40✔
529
                    CPLAddXMLChild(psSrc,
40✔
530
                                   poSrcVRTDS->SerializeToXML(pszVRTPath));
40✔
531
                    bDone = true;
40✔
532
                }
533
            }
534
        }
535
        if (!bDone)
2,628✔
536
        {
537
            AddSourceFilenameNode(pszVRTPath, psSrc);
2,588✔
538
        }
539
    }
540

541
    GDALSerializeOpenOptionsToXML(psSrc, m_aosOpenOptionsOri.List());
2,629✔
542

543
    if (m_bGetMaskBand)
2,629✔
544
        CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("mask,%d", m_nBand));
19✔
545
    else
546
        CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("%d", m_nBand));
2,610✔
547

548
    // TODO: in a later version, no longer emit SourceProperties, which
549
    // is no longer used by GDAL 3.4
550
    if (m_poRasterBand)
2,629✔
551
    {
552
        /* Write a few additional useful properties of the dataset */
553
        /* so that we can use a proxy dataset when re-opening. See XMLInit() */
554
        /* below */
555
        CPLSetXMLValue(psSrc, "SourceProperties.#RasterXSize",
2,510✔
556
                       CPLSPrintf("%d", m_poRasterBand->GetXSize()));
2,510✔
557
        CPLSetXMLValue(psSrc, "SourceProperties.#RasterYSize",
2,510✔
558
                       CPLSPrintf("%d", m_poRasterBand->GetYSize()));
2,510✔
559
        CPLSetXMLValue(
2,510✔
560
            psSrc, "SourceProperties.#DataType",
561
            GDALGetDataTypeName(m_poRasterBand->GetRasterDataType()));
2,510✔
562

563
        int nBlockXSize = 0;
2,510✔
564
        int nBlockYSize = 0;
2,510✔
565
        m_poRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
2,510✔
566

567
        CPLSetXMLValue(psSrc, "SourceProperties.#BlockXSize",
2,510✔
568
                       CPLSPrintf("%d", nBlockXSize));
569
        CPLSetXMLValue(psSrc, "SourceProperties.#BlockYSize",
2,510✔
570
                       CPLSPrintf("%d", nBlockYSize));
571
    }
572

573
    if (IsSrcWinSet())
2,629✔
574
    {
575
        CPLSetXMLValue(psSrc, "SrcRect.#xOff",
2,615✔
576
                       CPLSPrintf("%.15g", m_dfSrcXOff));
577
        CPLSetXMLValue(psSrc, "SrcRect.#yOff",
2,615✔
578
                       CPLSPrintf("%.15g", m_dfSrcYOff));
579
        CPLSetXMLValue(psSrc, "SrcRect.#xSize",
2,615✔
580
                       CPLSPrintf("%.15g", m_dfSrcXSize));
581
        CPLSetXMLValue(psSrc, "SrcRect.#ySize",
2,615✔
582
                       CPLSPrintf("%.15g", m_dfSrcYSize));
583
    }
584

585
    if (IsDstWinSet())
2,629✔
586
    {
587
        CPLSetXMLValue(psSrc, "DstRect.#xOff",
2,615✔
588
                       CPLSPrintf("%.15g", m_dfDstXOff));
589
        CPLSetXMLValue(psSrc, "DstRect.#yOff",
2,615✔
590
                       CPLSPrintf("%.15g", m_dfDstYOff));
591
        CPLSetXMLValue(psSrc, "DstRect.#xSize",
2,615✔
592
                       CPLSPrintf("%.15g", m_dfDstXSize));
593
        CPLSetXMLValue(psSrc, "DstRect.#ySize",
2,615✔
594
                       CPLSPrintf("%.15g", m_dfDstYSize));
595
    }
596

597
    return psSrc;
2,629✔
598
}
599

600
/************************************************************************/
601
/*                              XMLInit()                               */
602
/************************************************************************/
603

604
CPLErr VRTSimpleSource::XMLInit(const CPLXMLNode *psSrc, const char *pszVRTPath,
104,120✔
605
                                VRTMapSharedResources &oMapSharedSources)
606

607
{
608
    m_poMapSharedSources = &oMapSharedSources;
104,120✔
609

610
    m_osResampling = CPLGetXMLValue(psSrc, "resampling", "");
104,120✔
611
    m_osName = CPLGetXMLValue(psSrc, "name", "");
104,120✔
612

613
    /* -------------------------------------------------------------------- */
614
    /*      Prepare filename.                                               */
615
    /* -------------------------------------------------------------------- */
616
    const CPLXMLNode *psSourceFileNameNode =
617
        CPLGetXMLNode(psSrc, "SourceFilename");
104,120✔
618
    const CPLXMLNode *psSourceVRTDataset = CPLGetXMLNode(psSrc, "VRTDataset");
104,120✔
619
    const char *pszFilename =
620
        psSourceFileNameNode ? CPLGetXMLValue(psSourceFileNameNode, nullptr, "")
104,120✔
621
                             : "";
104,120✔
622

623
    if (pszFilename[0] == '\0' && !psSourceVRTDataset)
104,120✔
624
    {
625
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
626
                 "Missing <SourceFilename> or <VRTDataset> element in <%s>.",
627
                 psSrc->pszValue);
1✔
628
        return CE_Failure;
1✔
629
    }
630

631
    // Backup original filename and relativeToVRT so as to be able to
632
    // serialize them identically again (#5985)
633
    m_osSourceFileNameOri = pszFilename;
104,119✔
634
    if (pszFilename[0])
104,119✔
635
    {
636
        m_bRelativeToVRTOri =
104,110✔
637
            atoi(CPLGetXMLValue(psSourceFileNameNode, "relativetoVRT", "0"));
104,110✔
638
        const char *pszShared =
639
            CPLGetXMLValue(psSourceFileNameNode, "shared", nullptr);
104,110✔
640
        if (pszShared == nullptr)
104,110✔
641
        {
642
            pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
104,108✔
643
        }
644
        if (pszShared != nullptr)
104,110✔
645
        {
646
            m_nExplicitSharedStatus = CPLTestBool(pszShared);
8✔
647
        }
648

649
        m_osSrcDSName = GDALDataset::BuildFilename(
208,220✔
650
            pszFilename, pszVRTPath, CPL_TO_BOOL(m_bRelativeToVRTOri));
208,220✔
651
    }
652
    else if (psSourceVRTDataset)
9✔
653
    {
654
        CPLXMLNode sNode;
655
        sNode.eType = psSourceVRTDataset->eType;
9✔
656
        sNode.pszValue = psSourceVRTDataset->pszValue;
9✔
657
        sNode.psNext = nullptr;
9✔
658
        sNode.psChild = psSourceVRTDataset->psChild;
9✔
659
        char *pszXML = CPLSerializeXMLTree(&sNode);
9✔
660
        if (pszXML)
9✔
661
        {
662
            m_bSrcDSNameFromVRT = true;
9✔
663
            m_osSrcDSName = pszXML;
9✔
664
            CPLFree(pszXML);
9✔
665
        }
666
    }
667

668
    const char *pszSourceBand = CPLGetXMLValue(psSrc, "SourceBand", "1");
104,119✔
669
    m_bGetMaskBand = false;
104,119✔
670
    if (STARTS_WITH_CI(pszSourceBand, "mask"))
104,119✔
671
    {
672
        m_bGetMaskBand = true;
23✔
673
        if (pszSourceBand[4] == ',')
23✔
674
            m_nBand = atoi(pszSourceBand + 5);
23✔
675
        else
676
            m_nBand = 1;
×
677
    }
678
    else
679
    {
680
        m_nBand = atoi(pszSourceBand);
104,096✔
681
    }
682
    if (!GDALCheckBandCount(m_nBand, 0))
104,119✔
683
    {
684
        CPLError(CE_Warning, CPLE_AppDefined,
×
685
                 "Invalid <SourceBand> element in VRTRasterBand.");
686
        return CE_Failure;
×
687
    }
688

689
    m_aosOpenOptions = GDALDeserializeOpenOptionsFromXML(psSrc);
104,119✔
690
    m_aosOpenOptionsOri = m_aosOpenOptions;
104,119✔
691
    if (strstr(m_osSrcDSName.c_str(), "<VRTDataset") != nullptr)
104,119✔
692
        m_aosOpenOptions.SetNameValue("ROOT_PATH", pszVRTPath);
11✔
693

694
    return ParseSrcRectAndDstRect(psSrc);
104,119✔
695
}
696

697
/************************************************************************/
698
/*                        ParseSrcRectAndDstRect()                      */
699
/************************************************************************/
700

701
CPLErr VRTSimpleSource::ParseSrcRectAndDstRect(const CPLXMLNode *psSrc)
104,133✔
702
{
703
    const auto GetAttrValue = [](const CPLXMLNode *psNode,
25,156✔
704
                                 const char *pszAttrName, double dfDefaultVal)
705
    {
706
        if (const char *pszVal = CPLGetXMLValue(psNode, pszAttrName, nullptr))
25,156✔
707
            return CPLAtof(pszVal);
25,156✔
708
        else
709
            return dfDefaultVal;
×
710
    };
711

712
    /* -------------------------------------------------------------------- */
713
    /*      Set characteristics.                                            */
714
    /* -------------------------------------------------------------------- */
715
    const CPLXMLNode *const psSrcRect = CPLGetXMLNode(psSrc, "SrcRect");
104,133✔
716
    if (psSrcRect)
104,133✔
717
    {
718
        double xOff = GetAttrValue(psSrcRect, "xOff", UNINIT_WINDOW);
3,145✔
719
        double yOff = GetAttrValue(psSrcRect, "yOff", UNINIT_WINDOW);
3,145✔
720
        double xSize = GetAttrValue(psSrcRect, "xSize", UNINIT_WINDOW);
3,145✔
721
        double ySize = GetAttrValue(psSrcRect, "ySize", UNINIT_WINDOW);
3,145✔
722
        // Test written that way to catch NaN values
723
        if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
3,145✔
724
            !(yOff >= INT_MIN && yOff <= INT_MAX) ||
3,145✔
725
            !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
3,145✔
726
            !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
3,144✔
727
        {
728
            CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in SrcRect");
1✔
729
            return CE_Failure;
1✔
730
        }
731
        SetSrcWindow(xOff, yOff, xSize, ySize);
3,144✔
732
    }
733
    else
734
    {
735
        m_dfSrcXOff = UNINIT_WINDOW;
100,988✔
736
        m_dfSrcYOff = UNINIT_WINDOW;
100,988✔
737
        m_dfSrcXSize = UNINIT_WINDOW;
100,988✔
738
        m_dfSrcYSize = UNINIT_WINDOW;
100,988✔
739
    }
740

741
    const CPLXMLNode *const psDstRect = CPLGetXMLNode(psSrc, "DstRect");
104,132✔
742
    if (psDstRect)
104,132✔
743
    {
744
        double xOff = GetAttrValue(psDstRect, "xOff", UNINIT_WINDOW);
3,144✔
745
        ;
746
        double yOff = GetAttrValue(psDstRect, "yOff", UNINIT_WINDOW);
3,144✔
747
        double xSize = GetAttrValue(psDstRect, "xSize", UNINIT_WINDOW);
3,144✔
748
        ;
749
        double ySize = GetAttrValue(psDstRect, "ySize", UNINIT_WINDOW);
3,144✔
750
        // Test written that way to catch NaN values
751
        if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
3,144✔
752
            !(yOff >= INT_MIN && yOff <= INT_MAX) ||
3,144✔
753
            !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
3,144✔
754
            !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
3,144✔
755
        {
756
            CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in DstRect");
1✔
757
            return CE_Failure;
1✔
758
        }
759
        SetDstWindow(xOff, yOff, xSize, ySize);
3,143✔
760
    }
761
    else
762
    {
763
        m_dfDstXOff = UNINIT_WINDOW;
100,988✔
764
        m_dfDstYOff = UNINIT_WINDOW;
100,988✔
765
        m_dfDstXSize = UNINIT_WINDOW;
100,988✔
766
        m_dfDstYSize = UNINIT_WINDOW;
100,988✔
767
    }
768

769
    return CE_None;
104,131✔
770
}
771

772
/************************************************************************/
773
/*                             GetFileList()                            */
774
/************************************************************************/
775

776
void VRTSimpleSource::GetFileList(char ***ppapszFileList, int *pnSize,
113✔
777
                                  int *pnMaxSize, CPLHashSet *hSetFiles)
778
{
779
    if (!m_osSrcDSName.empty() && !m_bSrcDSNameFromVRT)
113✔
780
    {
781
        const char *pszFilename = m_osSrcDSName.c_str();
113✔
782

783
        /* --------------------------------------------------------------------
784
         */
785
        /*      Is it already in the list ? */
786
        /* --------------------------------------------------------------------
787
         */
788
        if (CPLHashSetLookup(hSetFiles, pszFilename) != nullptr)
113✔
789
            return;
15✔
790

791
        /* --------------------------------------------------------------------
792
         */
793
        /*      Grow array if necessary */
794
        /* --------------------------------------------------------------------
795
         */
796
        if (*pnSize + 1 >= *pnMaxSize)
98✔
797
        {
798
            *pnMaxSize = std::max(*pnSize + 2, 2 + 2 * (*pnMaxSize));
67✔
799
            *ppapszFileList = static_cast<char **>(
67✔
800
                CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
67✔
801
        }
802

803
        /* --------------------------------------------------------------------
804
         */
805
        /*      Add the string to the list */
806
        /* --------------------------------------------------------------------
807
         */
808
        (*ppapszFileList)[*pnSize] = CPLStrdup(pszFilename);
98✔
809
        (*ppapszFileList)[(*pnSize + 1)] = nullptr;
98✔
810
        CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
98✔
811

812
        (*pnSize)++;
98✔
813
    }
814
}
815

816
/************************************************************************/
817
/*                           OpenSource()                               */
818
/************************************************************************/
819

820
void VRTSimpleSource::OpenSource() const
102,157✔
821
{
822
    CPLAssert(m_poRasterBand == nullptr);
102,157✔
823

824
    /* ----------------------------------------------------------------- */
825
    /*      Create a proxy dataset                                       */
826
    /* ----------------------------------------------------------------- */
827
    GDALProxyPoolDataset *proxyDS = nullptr;
102,157✔
828
    std::string osKeyMapSharedSources;
102,157✔
829
    if (m_poMapSharedSources)
102,157✔
830
    {
831
        osKeyMapSharedSources = m_osSrcDSName;
102,109✔
832
        for (int i = 0; i < m_aosOpenOptions.size(); ++i)
102,123✔
833
        {
834
            osKeyMapSharedSources += "||";
14✔
835
            osKeyMapSharedSources += m_aosOpenOptions[i];
14✔
836
        }
837

838
        proxyDS = cpl::down_cast<GDALProxyPoolDataset *>(
102,109✔
839
            m_poMapSharedSources->Get(osKeyMapSharedSources));
102,109✔
840
    }
841

842
    if (proxyDS == nullptr)
102,157✔
843
    {
844
        int bShared = true;
3,185✔
845
        if (m_nExplicitSharedStatus != -1)
3,185✔
846
            bShared = m_nExplicitSharedStatus;
8✔
847

848
        const CPLString osUniqueHandle(CPLSPrintf("%p", m_poMapSharedSources));
3,185✔
849
        proxyDS = GDALProxyPoolDataset::Create(
3,185✔
850
            m_osSrcDSName, m_aosOpenOptions.List(), GA_ReadOnly, bShared,
851
            osUniqueHandle.c_str());
852
        if (proxyDS == nullptr)
3,185✔
853
            return;
175✔
854
    }
855
    else
856
    {
857
        proxyDS->Reference();
98,972✔
858
    }
859

860
    if (m_bGetMaskBand)
101,981✔
861
    {
862
        GDALProxyPoolRasterBand *poMaskBand =
863
            cpl::down_cast<GDALProxyPoolRasterBand *>(
15✔
864
                proxyDS->GetRasterBand(m_nBand));
15✔
865
        poMaskBand->AddSrcMaskBandDescriptionFromUnderlying();
15✔
866
    }
867

868
    /* -------------------------------------------------------------------- */
869
    /*      Get the raster band.                                            */
870
    /* -------------------------------------------------------------------- */
871

872
    m_poRasterBand = proxyDS->GetRasterBand(m_nBand);
101,981✔
873
    if (m_poRasterBand == nullptr || !ValidateOpenedBand(m_poRasterBand))
101,982✔
874
    {
875
        proxyDS->ReleaseRef();
2✔
876
        return;
2✔
877
    }
878

879
    if (m_bGetMaskBand)
101,980✔
880
    {
881
        m_poRasterBand = m_poRasterBand->GetMaskBand();
15✔
882
        if (m_poRasterBand == nullptr)
15✔
883
        {
884
            proxyDS->ReleaseRef();
×
885
            return;
×
886
        }
887
        m_poMaskBandMainBand = m_poRasterBand;
15✔
888
    }
889

890
    if (m_poMapSharedSources)
101,980✔
891
    {
892
        m_poMapSharedSources->Insert(osKeyMapSharedSources, proxyDS);
101,932✔
893
    }
894
}
895

896
/************************************************************************/
897
/*                         GetRasterBand()                              */
898
/************************************************************************/
899

900
GDALRasterBand *VRTSimpleSource::GetRasterBand() const
935,403✔
901
{
902
    if (m_poRasterBand == nullptr)
935,403✔
903
        OpenSource();
102,155✔
904
    return m_poRasterBand;
935,403✔
905
}
906

907
/************************************************************************/
908
/*                        GetMaskBandMainBand()                         */
909
/************************************************************************/
910

911
GDALRasterBand *VRTSimpleSource::GetMaskBandMainBand()
4,247✔
912
{
913
    if (m_poRasterBand == nullptr)
4,247✔
914
        OpenSource();
2✔
915
    return m_poMaskBandMainBand;
4,247✔
916
}
917

918
/************************************************************************/
919
/*                       IsSameExceptBandNumber()                       */
920
/************************************************************************/
921

922
bool VRTSimpleSource::IsSameExceptBandNumber(
2,867✔
923
    const VRTSimpleSource *poOtherSource) const
924
{
925
    return m_dfSrcXOff == poOtherSource->m_dfSrcXOff &&
5,734✔
926
           m_dfSrcYOff == poOtherSource->m_dfSrcYOff &&
2,867✔
927
           m_dfSrcXSize == poOtherSource->m_dfSrcXSize &&
2,867✔
928
           m_dfSrcYSize == poOtherSource->m_dfSrcYSize &&
2,867✔
929
           m_dfDstXOff == poOtherSource->m_dfDstXOff &&
2,867✔
930
           m_dfDstYOff == poOtherSource->m_dfDstYOff &&
2,867✔
931
           m_dfDstXSize == poOtherSource->m_dfDstXSize &&
2,867✔
932
           m_dfDstYSize == poOtherSource->m_dfDstYSize &&
8,601✔
933
           m_osSrcDSName == poOtherSource->m_osSrcDSName;
5,734✔
934
}
935

936
/************************************************************************/
937
/*                              SrcToDst()                              */
938
/*                                                                      */
939
/*      Note: this is a no-op if the both src and dst windows are unset */
940
/************************************************************************/
941

942
void VRTSimpleSource::SrcToDst(double dfX, double dfY, double &dfXOut,
10,250✔
943
                               double &dfYOut) const
944

945
{
946
    dfXOut = ((dfX - m_dfSrcXOff) / m_dfSrcXSize) * m_dfDstXSize + m_dfDstXOff;
10,250✔
947
    dfYOut = ((dfY - m_dfSrcYOff) / m_dfSrcYSize) * m_dfDstYSize + m_dfDstYOff;
10,250✔
948
}
10,250✔
949

950
/************************************************************************/
951
/*                              DstToSrc()                              */
952
/*                                                                      */
953
/*      Note: this is a no-op if the both src and dst windows are unset */
954
/************************************************************************/
955

956
void VRTSimpleSource::DstToSrc(double dfX, double dfY, double &dfXOut,
4,022,310✔
957
                               double &dfYOut) const
958

959
{
960
    dfXOut = ((dfX - m_dfDstXOff) / m_dfDstXSize) * m_dfSrcXSize + m_dfSrcXOff;
4,022,310✔
961
    dfYOut = ((dfY - m_dfDstYOff) / m_dfDstYSize) * m_dfSrcYSize + m_dfSrcYOff;
4,022,310✔
962
}
4,022,310✔
963

964
/************************************************************************/
965
/*                          GetSrcDstWindow()                           */
966
/************************************************************************/
967

968
int VRTSimpleSource::GetSrcDstWindow(
380,983✔
969
    double dfXOff, double dfYOff, double dfXSize, double dfYSize, int nBufXSize,
970
    int nBufYSize, double *pdfReqXOff, double *pdfReqYOff, double *pdfReqXSize,
971
    double *pdfReqYSize, int *pnReqXOff, int *pnReqYOff, int *pnReqXSize,
972
    int *pnReqYSize, int *pnOutXOff, int *pnOutYOff, int *pnOutXSize,
973
    int *pnOutYSize, bool &bErrorOut)
974

975
{
976
    bErrorOut = false;
380,983✔
977

978
    if (m_dfSrcXSize == 0.0 || m_dfSrcYSize == 0.0 || m_dfDstXSize == 0.0 ||
380,983✔
979
        m_dfDstYSize == 0.0)
380,983✔
980
    {
981
        return FALSE;
×
982
    }
983

984
    const bool bDstWinSet = IsDstWinSet();
380,983✔
985

986
#ifdef DEBUG
987
    const bool bSrcWinSet = IsSrcWinSet();
380,983✔
988

989
    if (bSrcWinSet != bDstWinSet)
380,983✔
990
    {
991
        return FALSE;
×
992
    }
993
#endif
994

995
    /* -------------------------------------------------------------------- */
996
    /*      If the input window completely misses the portion of the        */
997
    /*      virtual dataset provided by this source we have nothing to do.  */
998
    /* -------------------------------------------------------------------- */
999
    if (bDstWinSet)
380,983✔
1000
    {
1001
        if (dfXOff >= m_dfDstXOff + m_dfDstXSize ||
277,930✔
1002
            dfYOff >= m_dfDstYOff + m_dfDstYSize ||
267,502✔
1003
            dfXOff + dfXSize <= m_dfDstXOff || dfYOff + dfYSize <= m_dfDstYOff)
266,024✔
1004
            return FALSE;
21,253✔
1005
    }
1006

1007
    /* -------------------------------------------------------------------- */
1008
    /*      This request window corresponds to the whole output buffer.     */
1009
    /* -------------------------------------------------------------------- */
1010
    *pnOutXOff = 0;
359,730✔
1011
    *pnOutYOff = 0;
359,730✔
1012
    *pnOutXSize = nBufXSize;
359,730✔
1013
    *pnOutYSize = nBufYSize;
359,730✔
1014

1015
    /* -------------------------------------------------------------------- */
1016
    /*      If the input window extents outside the portion of the on       */
1017
    /*      the virtual file that this source can set, then clip down       */
1018
    /*      the requested window.                                           */
1019
    /* -------------------------------------------------------------------- */
1020
    bool bModifiedX = false;
359,730✔
1021
    bool bModifiedY = false;
359,730✔
1022
    double dfRXOff = dfXOff;
359,730✔
1023
    double dfRYOff = dfYOff;
359,730✔
1024
    double dfRXSize = dfXSize;
359,730✔
1025
    double dfRYSize = dfYSize;
359,730✔
1026

1027
    if (bDstWinSet)
359,730✔
1028
    {
1029
        if (dfRXOff < m_dfDstXOff)
256,677✔
1030
        {
1031
            dfRXSize = dfRXSize + dfRXOff - m_dfDstXOff;
1,880✔
1032
            dfRXOff = m_dfDstXOff;
1,880✔
1033
            bModifiedX = true;
1,880✔
1034
        }
1035

1036
        if (dfRYOff < m_dfDstYOff)
256,677✔
1037
        {
1038
            dfRYSize = dfRYSize + dfRYOff - m_dfDstYOff;
169✔
1039
            dfRYOff = m_dfDstYOff;
169✔
1040
            bModifiedY = true;
169✔
1041
        }
1042

1043
        if (dfRXOff + dfRXSize > m_dfDstXOff + m_dfDstXSize)
256,677✔
1044
        {
1045
            dfRXSize = m_dfDstXOff + m_dfDstXSize - dfRXOff;
3,572✔
1046
            bModifiedX = true;
3,572✔
1047
        }
1048

1049
        if (dfRYOff + dfRYSize > m_dfDstYOff + m_dfDstYSize)
256,677✔
1050
        {
1051
            dfRYSize = m_dfDstYOff + m_dfDstYSize - dfRYOff;
324✔
1052
            bModifiedY = true;
324✔
1053
        }
1054
    }
1055

1056
    /* -------------------------------------------------------------------- */
1057
    /*      Translate requested region in virtual file into the source      */
1058
    /*      band coordinates.                                               */
1059
    /* -------------------------------------------------------------------- */
1060
    const double dfScaleX = m_dfSrcXSize / m_dfDstXSize;
359,730✔
1061
    const double dfScaleY = m_dfSrcYSize / m_dfDstYSize;
359,730✔
1062

1063
    *pdfReqXOff = (dfRXOff - m_dfDstXOff) * dfScaleX + m_dfSrcXOff;
359,730✔
1064
    *pdfReqYOff = (dfRYOff - m_dfDstYOff) * dfScaleY + m_dfSrcYOff;
359,730✔
1065
    *pdfReqXSize = dfRXSize * dfScaleX;
359,730✔
1066
    *pdfReqYSize = dfRYSize * dfScaleY;
359,730✔
1067

1068
    if (!std::isfinite(*pdfReqXOff) || !std::isfinite(*pdfReqYOff) ||
719,460✔
1069
        !std::isfinite(*pdfReqXSize) || !std::isfinite(*pdfReqYSize) ||
359,730✔
1070
        *pdfReqXOff > INT_MAX || *pdfReqYOff > INT_MAX || *pdfReqXSize < 0 ||
1,079,190✔
1071
        *pdfReqYSize < 0)
359,730✔
1072
    {
1073
        return FALSE;
×
1074
    }
1075

1076
    /* -------------------------------------------------------------------- */
1077
    /*      Clamp within the bounds of the available source data.           */
1078
    /* -------------------------------------------------------------------- */
1079
    if (*pdfReqXOff < 0)
359,730✔
1080
    {
1081
        *pdfReqXSize += *pdfReqXOff;
9✔
1082
        *pdfReqXOff = 0;
9✔
1083
        bModifiedX = true;
9✔
1084
    }
1085
    if (*pdfReqYOff < 0)
359,730✔
1086
    {
1087
        *pdfReqYSize += *pdfReqYOff;
6✔
1088
        *pdfReqYOff = 0;
6✔
1089
        bModifiedY = true;
6✔
1090
    }
1091

1092
    *pnReqXOff = static_cast<int>(floor(*pdfReqXOff));
359,730✔
1093
    *pnReqYOff = static_cast<int>(floor(*pdfReqYOff));
359,730✔
1094

1095
    constexpr double EPS = 1e-3;
359,730✔
1096
    constexpr double ONE_MINUS_EPS = 1.0 - EPS;
359,730✔
1097
    if (*pdfReqXOff - *pnReqXOff > ONE_MINUS_EPS)
359,730✔
1098
    {
1099
        (*pnReqXOff)++;
2✔
1100
        *pdfReqXOff = *pnReqXOff;
2✔
1101
    }
1102
    if (*pdfReqYOff - *pnReqYOff > ONE_MINUS_EPS)
359,730✔
1103
    {
1104
        (*pnReqYOff)++;
18✔
1105
        *pdfReqYOff = *pnReqYOff;
18✔
1106
    }
1107

1108
    if (*pdfReqXSize > INT_MAX)
359,730✔
1109
        *pnReqXSize = INT_MAX;
×
1110
    else
1111
        *pnReqXSize = static_cast<int>(floor(*pdfReqXSize + 0.5));
359,730✔
1112

1113
    if (*pdfReqYSize > INT_MAX)
359,730✔
1114
        *pnReqYSize = INT_MAX;
×
1115
    else
1116
        *pnReqYSize = static_cast<int>(floor(*pdfReqYSize + 0.5));
359,730✔
1117

1118
    /* -------------------------------------------------------------------- */
1119
    /*      Clamp within the bounds of the available source data.           */
1120
    /* -------------------------------------------------------------------- */
1121

1122
    if (*pnReqXSize == 0)
359,730✔
1123
        *pnReqXSize = 1;
676✔
1124
    if (*pnReqYSize == 0)
359,730✔
1125
        *pnReqYSize = 1;
22,682✔
1126

1127
    auto l_band = GetRasterBand();
359,730✔
1128
    if (!l_band)
359,730✔
1129
    {
1130
        bErrorOut = true;
88✔
1131
        return FALSE;
88✔
1132
    }
1133
    if (*pnReqXSize > INT_MAX - *pnReqXOff ||
719,284✔
1134
        *pnReqXOff + *pnReqXSize > l_band->GetXSize())
359,642✔
1135
    {
1136
        *pnReqXSize = l_band->GetXSize() - *pnReqXOff;
248✔
1137
        bModifiedX = true;
248✔
1138
    }
1139
    if (*pdfReqXOff + *pdfReqXSize > l_band->GetXSize())
359,642✔
1140
    {
1141
        *pdfReqXSize = l_band->GetXSize() - *pdfReqXOff;
248✔
1142
        bModifiedX = true;
248✔
1143
    }
1144

1145
    if (*pnReqYSize > INT_MAX - *pnReqYOff ||
719,284✔
1146
        *pnReqYOff + *pnReqYSize > l_band->GetYSize())
359,642✔
1147
    {
1148
        *pnReqYSize = l_band->GetYSize() - *pnReqYOff;
48✔
1149
        bModifiedY = true;
48✔
1150
    }
1151
    if (*pdfReqYOff + *pdfReqYSize > l_band->GetYSize())
359,642✔
1152
    {
1153
        *pdfReqYSize = l_band->GetYSize() - *pdfReqYOff;
66✔
1154
        bModifiedY = true;
66✔
1155
    }
1156

1157
    /* -------------------------------------------------------------------- */
1158
    /*      Don't do anything if the requesting region is completely off    */
1159
    /*      the source image.                                               */
1160
    /* -------------------------------------------------------------------- */
1161
    if (*pnReqXOff >= l_band->GetXSize() || *pnReqYOff >= l_band->GetYSize() ||
719,280✔
1162
        *pnReqXSize <= 0 || *pnReqYSize <= 0)
719,280✔
1163
    {
1164
        return FALSE;
12✔
1165
    }
1166

1167
    /* -------------------------------------------------------------------- */
1168
    /*      If we haven't had to modify the source rectangle, then the      */
1169
    /*      destination rectangle must be the whole region.                 */
1170
    /* -------------------------------------------------------------------- */
1171
    if (bModifiedX || bModifiedY)
359,630✔
1172
    {
1173
        /* --------------------------------------------------------------------
1174
         */
1175
        /*      Now transform this possibly reduced request back into the */
1176
        /*      destination buffer coordinates in case the output region is */
1177
        /*      less than the whole buffer. */
1178
        /* --------------------------------------------------------------------
1179
         */
1180
        double dfDstULX = 0.0;
5,125✔
1181
        double dfDstULY = 0.0;
5,125✔
1182
        double dfDstLRX = 0.0;
5,125✔
1183
        double dfDstLRY = 0.0;
5,125✔
1184

1185
        SrcToDst(*pdfReqXOff, *pdfReqYOff, dfDstULX, dfDstULY);
5,125✔
1186
        SrcToDst(*pdfReqXOff + *pdfReqXSize, *pdfReqYOff + *pdfReqYSize,
5,125✔
1187
                 dfDstLRX, dfDstLRY);
1188
#if DEBUG_VERBOSE
1189
        CPLDebug("VRT", "dfDstULX=%g dfDstULY=%g dfDstLRX=%g dfDstLRY=%g",
1190
                 dfDstULX, dfDstULY, dfDstLRX, dfDstLRY);
1191
#endif
1192

1193
        if (bModifiedX)
5,125✔
1194
        {
1195
            const double dfScaleWinToBufX = nBufXSize / dfXSize;
5,071✔
1196

1197
            const double dfOutXOff = (dfDstULX - dfXOff) * dfScaleWinToBufX;
5,071✔
1198
            if (dfOutXOff <= 0)
5,071✔
1199
                *pnOutXOff = 0;
3,193✔
1200
            else if (dfOutXOff > INT_MAX)
1,878✔
1201
                *pnOutXOff = INT_MAX;
×
1202
            else
1203
                *pnOutXOff = static_cast<int>(dfOutXOff + EPS);
1,878✔
1204

1205
            // Apply correction on floating-point source window
1206
            {
1207
                double dfDstDeltaX =
5,071✔
1208
                    (dfOutXOff - *pnOutXOff) / dfScaleWinToBufX;
5,071✔
1209
                double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
5,071✔
1210
                *pdfReqXOff -= dfSrcDeltaX;
5,071✔
1211
                *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
10,142✔
1212
                                        static_cast<double>(INT_MAX));
5,071✔
1213
            }
1214

1215
            double dfOutRightXOff = (dfDstLRX - dfXOff) * dfScaleWinToBufX;
5,071✔
1216
            if (dfOutRightXOff < dfOutXOff)
5,071✔
1217
                return FALSE;
3✔
1218
            if (dfOutRightXOff > INT_MAX)
5,071✔
1219
                dfOutRightXOff = INT_MAX;
×
1220
            const int nOutRightXOff =
5,071✔
1221
                static_cast<int>(ceil(dfOutRightXOff - EPS));
5,071✔
1222
            *pnOutXSize = nOutRightXOff - *pnOutXOff;
5,071✔
1223

1224
            if (*pnOutXSize > INT_MAX - *pnOutXOff ||
5,071✔
1225
                *pnOutXOff + *pnOutXSize > nBufXSize)
5,071✔
1226
                *pnOutXSize = nBufXSize - *pnOutXOff;
×
1227

1228
            // Apply correction on floating-point source window
1229
            {
1230
                double dfDstDeltaX =
5,071✔
1231
                    (nOutRightXOff - dfOutRightXOff) / dfScaleWinToBufX;
5,071✔
1232
                double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
5,071✔
1233
                *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
10,142✔
1234
                                        static_cast<double>(INT_MAX));
5,071✔
1235
            }
1236
        }
1237

1238
        if (bModifiedY)
5,125✔
1239
        {
1240
            const double dfScaleWinToBufY = nBufYSize / dfYSize;
438✔
1241

1242
            const double dfOutYOff = (dfDstULY - dfYOff) * dfScaleWinToBufY;
438✔
1243
            if (dfOutYOff <= 0)
438✔
1244
                *pnOutYOff = 0;
252✔
1245
            else if (dfOutYOff > INT_MAX)
186✔
1246
                *pnOutYOff = INT_MAX;
×
1247
            else
1248
                *pnOutYOff = static_cast<int>(dfOutYOff + EPS);
186✔
1249

1250
            // Apply correction on floating-point source window
1251
            {
1252
                double dfDstDeltaY =
438✔
1253
                    (dfOutYOff - *pnOutYOff) / dfScaleWinToBufY;
438✔
1254
                double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
438✔
1255
                *pdfReqYOff -= dfSrcDeltaY;
438✔
1256
                *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
876✔
1257
                                        static_cast<double>(INT_MAX));
438✔
1258
            }
1259

1260
            double dfOutTopYOff = (dfDstLRY - dfYOff) * dfScaleWinToBufY;
438✔
1261
            if (dfOutTopYOff < dfOutYOff)
438✔
1262
                return FALSE;
×
1263
            if (dfOutTopYOff > INT_MAX)
438✔
1264
                dfOutTopYOff = INT_MAX;
×
1265
            const int nOutTopYOff = static_cast<int>(ceil(dfOutTopYOff - EPS));
438✔
1266
            *pnOutYSize = nOutTopYOff - *pnOutYOff;
438✔
1267

1268
            if (*pnOutYSize > INT_MAX - *pnOutYOff ||
438✔
1269
                *pnOutYOff + *pnOutYSize > nBufYSize)
438✔
1270
                *pnOutYSize = nBufYSize - *pnOutYOff;
×
1271

1272
            // Apply correction on floating-point source window
1273
            {
1274
                double dfDstDeltaY =
438✔
1275
                    (nOutTopYOff - dfOutTopYOff) / dfScaleWinToBufY;
438✔
1276
                double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
438✔
1277
                *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
876✔
1278
                                        static_cast<double>(INT_MAX));
438✔
1279
            }
1280
        }
1281

1282
        if (*pnOutXSize < 1 || *pnOutYSize < 1)
5,125✔
1283
            return FALSE;
3✔
1284
    }
1285

1286
    *pdfReqXOff = RoundIfCloseToInt(*pdfReqXOff);
359,627✔
1287
    *pdfReqYOff = RoundIfCloseToInt(*pdfReqYOff);
359,626✔
1288
    *pdfReqXSize = RoundIfCloseToInt(*pdfReqXSize);
359,627✔
1289
    *pdfReqYSize = RoundIfCloseToInt(*pdfReqYSize);
359,627✔
1290

1291
    return TRUE;
359,627✔
1292
}
1293

1294
/************************************************************************/
1295
/*                          NeedMaxValAdjustment()                      */
1296
/************************************************************************/
1297

1298
int VRTSimpleSource::NeedMaxValAdjustment() const
347,387✔
1299
{
1300
    if (!m_nMaxValue)
347,387✔
1301
        return FALSE;
347,365✔
1302

1303
    auto l_band = GetRasterBand();
22✔
1304
    if (!l_band)
22✔
1305
        return FALSE;
×
1306
    const char *pszNBITS = l_band->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
22✔
1307
    const int nBits = (pszNBITS) ? atoi(pszNBITS) : 0;
22✔
1308
    if (nBits >= 1 && nBits <= 31)
22✔
1309
    {
1310
        const int nBandMaxValue = static_cast<int>((1U << nBits) - 1);
×
1311
        return nBandMaxValue > m_nMaxValue;
×
1312
    }
1313
    return TRUE;
22✔
1314
}
1315

1316
/************************************************************************/
1317
/*                              RasterIO()                              */
1318
/************************************************************************/
1319

1320
CPLErr VRTSimpleSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
352,251✔
1321
                                 int nYOff, int nXSize, int nYSize, void *pData,
1322
                                 int nBufXSize, int nBufYSize,
1323
                                 GDALDataType eBufType, GSpacing nPixelSpace,
1324
                                 GSpacing nLineSpace,
1325
                                 GDALRasterIOExtraArg *psExtraArgIn,
1326
                                 WorkingState & /*oWorkingState*/)
1327

1328
{
1329
    GDALRasterIOExtraArg sExtraArg;
1330
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
352,251✔
1331
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
352,251✔
1332

1333
    double dfXOff = nXOff;
352,251✔
1334
    double dfYOff = nYOff;
352,251✔
1335
    double dfXSize = nXSize;
352,251✔
1336
    double dfYSize = nYSize;
352,251✔
1337
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
352,251✔
1338
    {
1339
        dfXOff = psExtraArgIn->dfXOff;
341✔
1340
        dfYOff = psExtraArgIn->dfYOff;
341✔
1341
        dfXSize = psExtraArgIn->dfXSize;
341✔
1342
        dfYSize = psExtraArgIn->dfYSize;
341✔
1343
    }
1344

1345
    // The window we will actually request from the source raster band.
1346
    double dfReqXOff = 0.0;
352,251✔
1347
    double dfReqYOff = 0.0;
352,251✔
1348
    double dfReqXSize = 0.0;
352,251✔
1349
    double dfReqYSize = 0.0;
352,251✔
1350
    int nReqXOff = 0;
352,251✔
1351
    int nReqYOff = 0;
352,251✔
1352
    int nReqXSize = 0;
352,251✔
1353
    int nReqYSize = 0;
352,251✔
1354

1355
    // The window we will actual set _within_ the pData buffer.
1356
    int nOutXOff = 0;
352,251✔
1357
    int nOutYOff = 0;
352,251✔
1358
    int nOutXSize = 0;
352,251✔
1359
    int nOutYSize = 0;
352,251✔
1360

1361
    bool bError = false;
352,251✔
1362
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
352,251✔
1363
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1364
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1365
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1366
    {
1367
        return bError ? CE_Failure : CE_None;
9,489✔
1368
    }
1369
#if DEBUG_VERBOSE
1370
    CPLDebug("VRT",
1371
             "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
1372
             "nBufYSize=%d,\n"
1373
             "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
1374
             "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
1375
             "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
1376
             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
1377
             dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
1378
             nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
1379
#endif
1380

1381
    /* -------------------------------------------------------------------- */
1382
    /*      Actually perform the IO request.                                */
1383
    /* -------------------------------------------------------------------- */
1384
    if (!m_osResampling.empty())
342,762✔
1385
    {
1386
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
202,606✔
1387
    }
1388
    else if (psExtraArgIn != nullptr)
140,156✔
1389
    {
1390
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
140,156✔
1391
    }
1392
    psExtraArg->bFloatingPointWindowValidity = TRUE;
342,762✔
1393
    psExtraArg->dfXOff = dfReqXOff;
342,762✔
1394
    psExtraArg->dfYOff = dfReqYOff;
342,762✔
1395
    psExtraArg->dfXSize = dfReqXSize;
342,762✔
1396
    psExtraArg->dfYSize = dfReqYSize;
342,762✔
1397
    if (psExtraArgIn)
342,762✔
1398
    {
1399
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
342,762✔
1400
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
342,762✔
1401
        if (psExtraArgIn->nVersion >= 2)
342,762✔
1402
        {
1403
            psExtraArg->bUseOnlyThisScale = psExtraArgIn->bUseOnlyThisScale;
342,762✔
1404
        }
1405
    }
1406

1407
    GByte *pabyOut = static_cast<unsigned char *>(pData) +
342,762✔
1408
                     nOutXOff * nPixelSpace +
342,762✔
1409
                     static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
342,762✔
1410

1411
    auto l_band = GetRasterBand();
342,762✔
1412
    if (!l_band)
342,762✔
1413
        return CE_Failure;
×
1414

1415
    CPLErr eErr = CE_Failure;
342,762✔
1416
    if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
342,762✔
1417
                                      eVRTBandDataType))
342,761✔
1418
    {
1419
        const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
1,218✔
1420
        void *pTemp = VSI_MALLOC3_VERBOSE(nOutXSize, nOutYSize, nBandDTSize);
1,218✔
1421
        if (pTemp)
1,218✔
1422
        {
1423
            eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1,218✔
1424
                                    nReqYSize, pTemp, nOutXSize, nOutYSize,
1425
                                    eVRTBandDataType, 0, 0, psExtraArg);
1426
            if (eErr == CE_None)
1,218✔
1427
            {
1428
                GByte *pabyTemp = static_cast<GByte *>(pTemp);
1,218✔
1429
                for (int iY = 0; iY < nOutYSize; iY++)
4,350✔
1430
                {
1431
                    GDALCopyWords(
3,132✔
1432
                        pabyTemp +
3,132✔
1433
                            static_cast<size_t>(iY) * nBandDTSize * nOutXSize,
3,132✔
1434
                        eVRTBandDataType, nBandDTSize,
1435
                        pabyOut + static_cast<GPtrDiff_t>(iY * nLineSpace),
3,132✔
1436
                        eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1437
                }
1438
            }
1439
            VSIFree(pTemp);
1,218✔
1440
        }
1441
    }
1442
    else
1443
    {
1444
        eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
341,543✔
1445
                                nReqYSize, pabyOut, nOutXSize, nOutYSize,
1446
                                eBufType, nPixelSpace, nLineSpace, psExtraArg);
1447
    }
1448

1449
    if (NeedMaxValAdjustment())
342,762✔
1450
    {
1451
        for (int j = 0; j < nOutYSize; j++)
234✔
1452
        {
1453
            for (int i = 0; i < nOutXSize; i++)
4,620✔
1454
            {
1455
                int nVal = 0;
4,400✔
1456
                GDALCopyWords(pabyOut + j * nLineSpace + i * nPixelSpace,
4,400✔
1457
                              eBufType, 0, &nVal, GDT_Int32, 0, 1);
1458
                if (nVal > m_nMaxValue)
4,400✔
1459
                    nVal = m_nMaxValue;
800✔
1460
                GDALCopyWords(&nVal, GDT_Int32, 0,
4,400✔
1461
                              pabyOut + j * nLineSpace + i * nPixelSpace,
4,400✔
1462
                              eBufType, 0, 1);
1463
            }
1464
        }
1465
    }
1466

1467
    if (psExtraArg->pfnProgress)
342,762✔
1468
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
495✔
1469

1470
    return eErr;
342,762✔
1471
}
1472

1473
/************************************************************************/
1474
/*                             GetMinimum()                             */
1475
/************************************************************************/
1476

1477
double VRTSimpleSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
52✔
1478
{
1479
    // The window we will actually request from the source raster band.
1480
    double dfReqXOff = 0.0;
52✔
1481
    double dfReqYOff = 0.0;
52✔
1482
    double dfReqXSize = 0.0;
52✔
1483
    double dfReqYSize = 0.0;
52✔
1484
    int nReqXOff = 0;
52✔
1485
    int nReqYOff = 0;
52✔
1486
    int nReqXSize = 0;
52✔
1487
    int nReqYSize = 0;
52✔
1488

1489
    // The window we will actual set _within_ the pData buffer.
1490
    int nOutXOff = 0;
52✔
1491
    int nOutYOff = 0;
52✔
1492
    int nOutXSize = 0;
52✔
1493
    int nOutYSize = 0;
52✔
1494

1495
    bool bError = false;
52✔
1496
    auto l_band = GetRasterBand();
52✔
1497
    if (!l_band ||
104✔
1498
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
52✔
1499
                         &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1500
                         &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1501
                         &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
52✔
1502
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
156✔
1503
        nReqYSize != l_band->GetYSize())
52✔
1504
    {
1505
        *pbSuccess = FALSE;
×
1506
        return 0;
×
1507
    }
1508

1509
    const double dfVal = l_band->GetMinimum(pbSuccess);
52✔
1510
    if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
52✔
1511
        return m_nMaxValue;
2✔
1512
    return dfVal;
50✔
1513
}
1514

1515
/************************************************************************/
1516
/*                             GetMaximum()                             */
1517
/************************************************************************/
1518

1519
double VRTSimpleSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
51✔
1520
{
1521
    // The window we will actually request from the source raster band.
1522
    double dfReqXOff = 0.0;
51✔
1523
    double dfReqYOff = 0.0;
51✔
1524
    double dfReqXSize = 0.0;
51✔
1525
    double dfReqYSize = 0.0;
51✔
1526
    int nReqXOff = 0;
51✔
1527
    int nReqYOff = 0;
51✔
1528
    int nReqXSize = 0;
51✔
1529
    int nReqYSize = 0;
51✔
1530

1531
    // The window we will actual set _within_ the pData buffer.
1532
    int nOutXOff = 0;
51✔
1533
    int nOutYOff = 0;
51✔
1534
    int nOutXSize = 0;
51✔
1535
    int nOutYSize = 0;
51✔
1536

1537
    bool bError = false;
51✔
1538
    auto l_band = GetRasterBand();
51✔
1539
    if (!l_band ||
102✔
1540
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
51✔
1541
                         &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1542
                         &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1543
                         &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
51✔
1544
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
153✔
1545
        nReqYSize != l_band->GetYSize())
51✔
1546
    {
1547
        *pbSuccess = FALSE;
×
1548
        return 0;
×
1549
    }
1550

1551
    const double dfVal = l_band->GetMaximum(pbSuccess);
51✔
1552
    if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
51✔
1553
        return m_nMaxValue;
2✔
1554
    return dfVal;
49✔
1555
}
1556

1557
/************************************************************************/
1558
/*                            GetHistogram()                            */
1559
/************************************************************************/
1560

1561
CPLErr VRTSimpleSource::GetHistogram(int nXSize, int nYSize, double dfMin,
4✔
1562
                                     double dfMax, int nBuckets,
1563
                                     GUIntBig *panHistogram,
1564
                                     int bIncludeOutOfRange, int bApproxOK,
1565
                                     GDALProgressFunc pfnProgress,
1566
                                     void *pProgressData)
1567
{
1568
    // The window we will actually request from the source raster band.
1569
    double dfReqXOff = 0.0;
4✔
1570
    double dfReqYOff = 0.0;
4✔
1571
    double dfReqXSize = 0.0;
4✔
1572
    double dfReqYSize = 0.0;
4✔
1573
    int nReqXOff = 0;
4✔
1574
    int nReqYOff = 0;
4✔
1575
    int nReqXSize = 0;
4✔
1576
    int nReqYSize = 0;
4✔
1577

1578
    // The window we will actual set _within_ the pData buffer.
1579
    int nOutXOff = 0;
4✔
1580
    int nOutYOff = 0;
4✔
1581
    int nOutXSize = 0;
4✔
1582
    int nOutYSize = 0;
4✔
1583

1584
    bool bError = false;
4✔
1585
    auto l_band = GetRasterBand();
4✔
1586
    if (!l_band || NeedMaxValAdjustment() ||
4✔
1587
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
4✔
1588
                         &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1589
                         &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1590
                         &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
4✔
1591
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
12✔
1592
        nReqYSize != l_band->GetYSize())
4✔
1593
    {
1594
        return CE_Failure;
×
1595
    }
1596

1597
    return l_band->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4✔
1598
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
1599
                                pProgressData);
4✔
1600
}
1601

1602
/************************************************************************/
1603
/*                          DatasetRasterIO()                           */
1604
/************************************************************************/
1605

1606
CPLErr VRTSimpleSource::DatasetRasterIO(
5,294✔
1607
    GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
1608
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1609
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
1610
    GSpacing nLineSpace, GSpacing nBandSpace,
1611
    GDALRasterIOExtraArg *psExtraArgIn)
1612
{
1613
    if (GetType() != VRTSimpleSource::GetTypeStatic())
5,294✔
1614
    {
1615
        CPLError(CE_Failure, CPLE_NotSupported,
×
1616
                 "DatasetRasterIO() not implemented for %s", GetType());
×
1617
        return CE_Failure;
×
1618
    }
1619

1620
    GDALRasterIOExtraArg sExtraArg;
1621
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
5,294✔
1622
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
5,294✔
1623

1624
    double dfXOff = nXOff;
5,294✔
1625
    double dfYOff = nYOff;
5,294✔
1626
    double dfXSize = nXSize;
5,294✔
1627
    double dfYSize = nYSize;
5,294✔
1628
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
5,294✔
1629
    {
1630
        dfXOff = psExtraArgIn->dfXOff;
11✔
1631
        dfYOff = psExtraArgIn->dfYOff;
11✔
1632
        dfXSize = psExtraArgIn->dfXSize;
11✔
1633
        dfYSize = psExtraArgIn->dfYSize;
11✔
1634
    }
1635

1636
    // The window we will actually request from the source raster band.
1637
    double dfReqXOff = 0.0;
5,294✔
1638
    double dfReqYOff = 0.0;
5,294✔
1639
    double dfReqXSize = 0.0;
5,294✔
1640
    double dfReqYSize = 0.0;
5,294✔
1641
    int nReqXOff = 0;
5,294✔
1642
    int nReqYOff = 0;
5,294✔
1643
    int nReqXSize = 0;
5,294✔
1644
    int nReqYSize = 0;
5,294✔
1645

1646
    // The window we will actual set _within_ the pData buffer.
1647
    int nOutXOff = 0;
5,294✔
1648
    int nOutYOff = 0;
5,294✔
1649
    int nOutXSize = 0;
5,294✔
1650
    int nOutYSize = 0;
5,294✔
1651

1652
    bool bError = false;
5,294✔
1653
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
5,294✔
1654
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1655
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1656
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1657
    {
1658
        return bError ? CE_Failure : CE_None;
839✔
1659
    }
1660

1661
    auto l_band = GetRasterBand();
4,455✔
1662
    if (!l_band)
4,455✔
1663
        return CE_Failure;
×
1664

1665
    GDALDataset *poDS = l_band->GetDataset();
4,455✔
1666
    if (poDS == nullptr)
4,455✔
1667
        return CE_Failure;
×
1668

1669
    if (!m_osResampling.empty())
4,455✔
1670
    {
1671
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
788✔
1672
    }
1673
    else if (psExtraArgIn != nullptr)
3,667✔
1674
    {
1675
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
3,667✔
1676
    }
1677
    psExtraArg->bFloatingPointWindowValidity = TRUE;
4,455✔
1678
    psExtraArg->dfXOff = dfReqXOff;
4,455✔
1679
    psExtraArg->dfYOff = dfReqYOff;
4,455✔
1680
    psExtraArg->dfXSize = dfReqXSize;
4,455✔
1681
    psExtraArg->dfYSize = dfReqYSize;
4,455✔
1682
    if (psExtraArgIn)
4,455✔
1683
    {
1684
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
4,455✔
1685
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
4,455✔
1686
    }
1687

1688
    GByte *pabyOut = static_cast<unsigned char *>(pData) +
4,455✔
1689
                     nOutXOff * nPixelSpace +
4,455✔
1690
                     static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
4,455✔
1691

1692
    CPLErr eErr = CE_Failure;
4,455✔
1693

1694
    if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
4,455✔
1695
                                      eVRTBandDataType))
4,455✔
1696
    {
1697
        const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
2✔
1698
        void *pTemp = VSI_MALLOC3_VERBOSE(
2✔
1699
            nOutXSize, nOutYSize, cpl::fits_on<int>(nBandDTSize * nBandCount));
1700
        if (pTemp)
2✔
1701
        {
1702
            eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
2✔
1703
                                  nReqYSize, pTemp, nOutXSize, nOutYSize,
1704
                                  eVRTBandDataType, nBandCount, panBandMap, 0,
1705
                                  0, 0, psExtraArg);
1706
            if (eErr == CE_None)
2✔
1707
            {
1708
                GByte *pabyTemp = static_cast<GByte *>(pTemp);
2✔
1709
                const size_t nSrcBandSpace =
2✔
1710
                    static_cast<size_t>(nOutYSize) * nOutXSize * nBandDTSize;
2✔
1711
                for (int iBand = 0; iBand < nBandCount; iBand++)
6✔
1712
                {
1713
                    for (int iY = 0; iY < nOutYSize; iY++)
174✔
1714
                    {
1715
                        GDALCopyWords(
170✔
1716
                            pabyTemp + iBand * nSrcBandSpace +
170✔
1717
                                static_cast<size_t>(iY) * nBandDTSize *
170✔
1718
                                    nOutXSize,
170✔
1719
                            eVRTBandDataType, nBandDTSize,
1720
                            pabyOut + static_cast<GPtrDiff_t>(
170✔
1721
                                          iY * nLineSpace + iBand * nBandSpace),
170✔
1722
                            eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1723
                    }
1724
                }
1725
            }
1726
            VSIFree(pTemp);
2✔
1727
        }
1728
    }
1729
    else
1730
    {
1731
        eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
4,453✔
1732
                              pabyOut, nOutXSize, nOutYSize, eBufType,
1733
                              nBandCount, panBandMap, nPixelSpace, nLineSpace,
1734
                              nBandSpace, psExtraArg);
1735
    }
1736

1737
    if (NeedMaxValAdjustment())
4,455✔
1738
    {
1739
        for (int k = 0; k < nBandCount; k++)
×
1740
        {
1741
            for (int j = 0; j < nOutYSize; j++)
×
1742
            {
1743
                for (int i = 0; i < nOutXSize; i++)
×
1744
                {
1745
                    int nVal = 0;
×
1746
                    GDALCopyWords(pabyOut + k * nBandSpace + j * nLineSpace +
×
1747
                                      i * nPixelSpace,
×
1748
                                  eBufType, 0, &nVal, GDT_Int32, 0, 1);
1749

1750
                    if (nVal > m_nMaxValue)
×
1751
                        nVal = m_nMaxValue;
×
1752

1753
                    GDALCopyWords(&nVal, GDT_Int32, 0,
×
1754
                                  pabyOut + k * nBandSpace + j * nLineSpace +
×
1755
                                      i * nPixelSpace,
×
1756
                                  eBufType, 0, 1);
1757
                }
1758
            }
1759
        }
1760
    }
1761

1762
    if (psExtraArg->pfnProgress)
4,455✔
1763
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
3,987✔
1764

1765
    return eErr;
4,455✔
1766
}
1767

1768
/************************************************************************/
1769
/*                          SetResampling()                             */
1770
/************************************************************************/
1771

1772
void VRTSimpleSource::SetResampling(const char *pszResampling)
70,064✔
1773
{
1774
    m_osResampling = (pszResampling) ? pszResampling : "";
70,064✔
1775
}
70,064✔
1776

1777
/************************************************************************/
1778
/* ==================================================================== */
1779
/*                         VRTAveragedSource                            */
1780
/* ==================================================================== */
1781
/************************************************************************/
1782

1783
/************************************************************************/
1784
/*                         VRTAveragedSource()                          */
1785
/************************************************************************/
1786

1787
VRTAveragedSource::VRTAveragedSource()
16✔
1788
{
1789
}
16✔
1790

1791
/************************************************************************/
1792
/*                           GetTypeStatic()                            */
1793
/************************************************************************/
1794

1795
const char *VRTAveragedSource::GetTypeStatic()
104,117✔
1796
{
1797
    static const char *TYPE = "AveragedSource";
1798
    return TYPE;
104,117✔
1799
}
1800

1801
/************************************************************************/
1802
/*                            GetType()                                 */
1803
/************************************************************************/
1804

1805
const char *VRTAveragedSource::GetType() const
11✔
1806
{
1807
    return GetTypeStatic();
11✔
1808
}
1809

1810
/************************************************************************/
1811
/*                           SerializeToXML()                           */
1812
/************************************************************************/
1813

1814
CPLXMLNode *VRTAveragedSource::SerializeToXML(const char *pszVRTPath)
×
1815

1816
{
1817
    CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
×
1818

1819
    if (psSrc == nullptr)
×
1820
        return nullptr;
×
1821

1822
    CPLFree(psSrc->pszValue);
×
1823
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
×
1824

1825
    return psSrc;
×
1826
}
1827

1828
/************************************************************************/
1829
/*                           SetNoDataValue()                           */
1830
/************************************************************************/
1831

1832
void VRTAveragedSource::SetNoDataValue(double dfNewNoDataValue)
×
1833

1834
{
1835
    if (dfNewNoDataValue == VRT_NODATA_UNSET)
×
1836
    {
1837
        m_bNoDataSet = FALSE;
×
1838
        m_dfNoDataValue = VRT_NODATA_UNSET;
×
1839
        return;
×
1840
    }
1841

1842
    m_bNoDataSet = TRUE;
×
1843
    m_dfNoDataValue = dfNewNoDataValue;
×
1844
}
1845

1846
/************************************************************************/
1847
/*                              RasterIO()                              */
1848
/************************************************************************/
1849

1850
CPLErr VRTAveragedSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
33✔
1851
                                   int nYOff, int nXSize, int nYSize,
1852
                                   void *pData, int nBufXSize, int nBufYSize,
1853
                                   GDALDataType eBufType, GSpacing nPixelSpace,
1854
                                   GSpacing nLineSpace,
1855
                                   GDALRasterIOExtraArg *psExtraArgIn,
1856
                                   WorkingState & /*oWorkingState*/)
1857

1858
{
1859
    GDALRasterIOExtraArg sExtraArg;
1860
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
33✔
1861
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
33✔
1862

1863
    double dfXOff = nXOff;
33✔
1864
    double dfYOff = nYOff;
33✔
1865
    double dfXSize = nXSize;
33✔
1866
    double dfYSize = nYSize;
33✔
1867
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
33✔
1868
    {
1869
        dfXOff = psExtraArgIn->dfXOff;
×
1870
        dfYOff = psExtraArgIn->dfYOff;
×
1871
        dfXSize = psExtraArgIn->dfXSize;
×
1872
        dfYSize = psExtraArgIn->dfYSize;
×
1873
    }
1874

1875
    // The window we will actually request from the source raster band.
1876
    double dfReqXOff = 0.0;
33✔
1877
    double dfReqYOff = 0.0;
33✔
1878
    double dfReqXSize = 0.0;
33✔
1879
    double dfReqYSize = 0.0;
33✔
1880
    int nReqXOff = 0;
33✔
1881
    int nReqYOff = 0;
33✔
1882
    int nReqXSize = 0;
33✔
1883
    int nReqYSize = 0;
33✔
1884

1885
    // The window we will actual set _within_ the pData buffer.
1886
    int nOutXOff = 0;
33✔
1887
    int nOutYOff = 0;
33✔
1888
    int nOutXSize = 0;
33✔
1889
    int nOutYSize = 0;
33✔
1890

1891
    bool bError = false;
33✔
1892
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
33✔
1893
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1894
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1895
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1896
    {
1897
        return bError ? CE_Failure : CE_None;
×
1898
    }
1899

1900
    auto l_band = GetRasterBand();
33✔
1901
    if (!l_band)
33✔
1902
        return CE_Failure;
×
1903

1904
    /* -------------------------------------------------------------------- */
1905
    /*      Allocate a temporary buffer to whole the full resolution        */
1906
    /*      data from the area of interest.                                 */
1907
    /* -------------------------------------------------------------------- */
1908
    float *const pafSrc = static_cast<float *>(
1909
        VSI_MALLOC3_VERBOSE(sizeof(float), nReqXSize, nReqYSize));
33✔
1910
    if (pafSrc == nullptr)
33✔
1911
    {
1912
        return CE_Failure;
×
1913
    }
1914

1915
    /* -------------------------------------------------------------------- */
1916
    /*      Load it.                                                        */
1917
    /* -------------------------------------------------------------------- */
1918
    if (!m_osResampling.empty())
33✔
1919
    {
1920
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
28✔
1921
    }
1922
    else if (psExtraArgIn != nullptr)
5✔
1923
    {
1924
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
5✔
1925
    }
1926

1927
    psExtraArg->bFloatingPointWindowValidity = TRUE;
33✔
1928
    psExtraArg->dfXOff = dfReqXOff;
33✔
1929
    psExtraArg->dfYOff = dfReqYOff;
33✔
1930
    psExtraArg->dfXSize = dfReqXSize;
33✔
1931
    psExtraArg->dfYSize = dfReqYSize;
33✔
1932
    if (psExtraArgIn)
33✔
1933
    {
1934
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
33✔
1935
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
33✔
1936
    }
1937

1938
    const CPLErr eErr = l_band->RasterIO(
33✔
1939
        GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize, pafSrc, nReqXSize,
1940
        nReqYSize, GDT_Float32, 0, 0, psExtraArg);
1941

1942
    if (eErr != CE_None)
33✔
1943
    {
1944
        VSIFree(pafSrc);
×
1945
        return eErr;
×
1946
    }
1947

1948
    /* -------------------------------------------------------------------- */
1949
    /*      Do the averaging.                                               */
1950
    /* -------------------------------------------------------------------- */
1951
    for (int iBufLine = nOutYOff; iBufLine < nOutYOff + nOutYSize; iBufLine++)
5,956✔
1952
    {
1953
        const double dfYDst =
5,923✔
1954
            (iBufLine / static_cast<double>(nBufYSize)) * nYSize + nYOff;
5,923✔
1955

1956
        for (int iBufPixel = nOutXOff; iBufPixel < nOutXOff + nOutXSize;
2,017,080✔
1957
             iBufPixel++)
1958
        {
1959
            double dfXSrcStart, dfXSrcEnd, dfYSrcStart, dfYSrcEnd;
1960
            int iXSrcStart, iYSrcStart, iXSrcEnd, iYSrcEnd;
1961

1962
            const double dfXDst =
2,011,160✔
1963
                (iBufPixel / static_cast<double>(nBufXSize)) * nXSize + nXOff;
2,011,160✔
1964

1965
            // Compute the source image rectangle needed for this pixel.
1966
            DstToSrc(dfXDst, dfYDst, dfXSrcStart, dfYSrcStart);
2,011,160✔
1967
            DstToSrc(dfXDst + 1.0, dfYDst + 1.0, dfXSrcEnd, dfYSrcEnd);
2,011,160✔
1968

1969
            // Convert to integers, assuming that the center of the source
1970
            // pixel must be in our rect to get included.
1971
            if (dfXSrcEnd >= dfXSrcStart + 1)
2,011,160✔
1972
            {
1973
                iXSrcStart = static_cast<int>(floor(dfXSrcStart + 0.5));
1,049,560✔
1974
                iXSrcEnd = static_cast<int>(floor(dfXSrcEnd + 0.5));
1,049,560✔
1975
            }
1976
            else
1977
            {
1978
                /* If the resampling factor is less than 100%, the distance */
1979
                /* between the source pixel is < 1, so we stick to nearest */
1980
                /* neighbour */
1981
                iXSrcStart = static_cast<int>(floor(dfXSrcStart));
961,600✔
1982
                iXSrcEnd = iXSrcStart + 1;
961,600✔
1983
            }
1984
            if (dfYSrcEnd >= dfYSrcStart + 1)
2,011,160✔
1985
            {
1986
                iYSrcStart = static_cast<int>(floor(dfYSrcStart + 0.5));
1,049,560✔
1987
                iYSrcEnd = static_cast<int>(floor(dfYSrcEnd + 0.5));
1,049,560✔
1988
            }
1989
            else
1990
            {
1991
                iYSrcStart = static_cast<int>(floor(dfYSrcStart));
961,600✔
1992
                iYSrcEnd = iYSrcStart + 1;
961,600✔
1993
            }
1994

1995
            // Transform into the coordinate system of the source *buffer*
1996
            iXSrcStart -= nReqXOff;
2,011,160✔
1997
            iYSrcStart -= nReqYOff;
2,011,160✔
1998
            iXSrcEnd -= nReqXOff;
2,011,160✔
1999
            iYSrcEnd -= nReqYOff;
2,011,160✔
2000

2001
            double dfSum = 0.0;
2,011,160✔
2002
            int nPixelCount = 0;
2,011,160✔
2003

2004
            for (int iY = iYSrcStart; iY < iYSrcEnd; iY++)
4,022,510✔
2005
            {
2006
                if (iY < 0 || iY >= nReqYSize)
2,011,360✔
2007
                    continue;
×
2008

2009
                for (int iX = iXSrcStart; iX < iXSrcEnd; iX++)
4,023,130✔
2010
                {
2011
                    if (iX < 0 || iX >= nReqXSize)
2,011,780✔
2012
                        continue;
×
2013

2014
                    const float fSampledValue =
2,011,780✔
2015
                        pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
2,011,780✔
2016
                    if (std::isnan(fSampledValue))
2,011,780✔
2017
                        continue;
×
2018

2019
                    if (m_bNoDataSet &&
4,023,550✔
2020
                        GDALIsValueInRange<float>(m_dfNoDataValue) &&
2,011,780✔
2021
                        ARE_REAL_EQUAL(fSampledValue,
×
2022
                                       static_cast<float>(m_dfNoDataValue)))
×
2023
                        continue;
×
2024

2025
                    nPixelCount++;
2,011,780✔
2026
                    dfSum += pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
2,011,780✔
2027
                }
2028
            }
2029

2030
            if (nPixelCount == 0)
2,011,160✔
2031
                continue;
×
2032

2033
            // Compute output value.
2034
            const float dfOutputValue = static_cast<float>(dfSum / nPixelCount);
2,011,160✔
2035

2036
            // Put it in the output buffer.
2037
            GByte *pDstLocation =
2,011,160✔
2038
                static_cast<GByte *>(pData) + nPixelSpace * iBufPixel +
2,011,160✔
2039
                static_cast<GPtrDiff_t>(nLineSpace) * iBufLine;
2,011,160✔
2040

2041
            if (eBufType == GDT_Byte)
2,011,160✔
2042
                *pDstLocation = static_cast<GByte>(
2,008,660✔
2043
                    std::min(255.0, std::max(0.0, dfOutputValue + 0.5)));
2,008,660✔
2044
            else
2045
                GDALCopyWords(&dfOutputValue, GDT_Float32, 4, pDstLocation,
2,500✔
2046
                              eBufType, 8, 1);
2047
        }
2048
    }
2049

2050
    VSIFree(pafSrc);
33✔
2051

2052
    if (psExtraArg->pfnProgress)
33✔
2053
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
×
2054

2055
    return CE_None;
33✔
2056
}
2057

2058
/************************************************************************/
2059
/*                             GetMinimum()                             */
2060
/************************************************************************/
2061

2062
double VRTAveragedSource::GetMinimum(int /* nXSize */, int /* nYSize */,
×
2063
                                     int *pbSuccess)
2064
{
2065
    *pbSuccess = FALSE;
×
2066
    return 0.0;
×
2067
}
2068

2069
/************************************************************************/
2070
/*                             GetMaximum()                             */
2071
/************************************************************************/
2072

2073
double VRTAveragedSource::GetMaximum(int /* nXSize */, int /* nYSize */,
×
2074
                                     int *pbSuccess)
2075
{
2076
    *pbSuccess = FALSE;
×
2077
    return 0.0;
×
2078
}
2079

2080
/************************************************************************/
2081
/*                            GetHistogram()                            */
2082
/************************************************************************/
2083

2084
CPLErr VRTAveragedSource::GetHistogram(
×
2085
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2086
    int /* nBuckets */, GUIntBig * /* panHistogram */,
2087
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
2088
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2089
{
2090
    return CE_Failure;
×
2091
}
2092

2093
/************************************************************************/
2094
/* ==================================================================== */
2095
/*                     VRTNoDataFromMaskSource                          */
2096
/* ==================================================================== */
2097
/************************************************************************/
2098

2099
/************************************************************************/
2100
/*                     VRTNoDataFromMaskSource()                        */
2101
/************************************************************************/
2102

2103
VRTNoDataFromMaskSource::VRTNoDataFromMaskSource()
23✔
2104
{
2105
}
23✔
2106

2107
/************************************************************************/
2108
/*                              XMLInit()                               */
2109
/************************************************************************/
2110

2111
CPLErr
2112
VRTNoDataFromMaskSource::XMLInit(const CPLXMLNode *psSrc,
8✔
2113
                                 const char *pszVRTPath,
2114
                                 VRTMapSharedResources &oMapSharedSources)
2115

2116
{
2117
    /* -------------------------------------------------------------------- */
2118
    /*      Do base initialization.                                         */
2119
    /* -------------------------------------------------------------------- */
2120
    {
2121
        const CPLErr eErr =
2122
            VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
8✔
2123
        if (eErr != CE_None)
8✔
2124
            return eErr;
×
2125
    }
2126

2127
    if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
8✔
2128
    {
2129
        m_bNoDataSet = true;
8✔
2130
        m_dfNoDataValue = CPLAtofM(pszNODATA);
8✔
2131
    }
2132

2133
    m_dfMaskValueThreshold =
8✔
2134
        CPLAtofM(CPLGetXMLValue(psSrc, "MaskValueThreshold", "0"));
8✔
2135

2136
    if (const char *pszRemappedValue =
8✔
2137
            CPLGetXMLValue(psSrc, "RemappedValue", nullptr))
8✔
2138
    {
2139
        m_bHasRemappedValue = true;
×
2140
        m_dfRemappedValue = CPLAtofM(pszRemappedValue);
×
2141
    }
2142

2143
    return CE_None;
8✔
2144
}
2145

2146
/************************************************************************/
2147
/*                           GetTypeStatic()                            */
2148
/************************************************************************/
2149

2150
const char *VRTNoDataFromMaskSource::GetTypeStatic()
27✔
2151
{
2152
    static const char *TYPE = "NoDataFromMaskSource";
2153
    return TYPE;
27✔
2154
}
2155

2156
/************************************************************************/
2157
/*                            GetType()                                 */
2158
/************************************************************************/
2159

2160
const char *VRTNoDataFromMaskSource::GetType() const
11✔
2161
{
2162
    return GetTypeStatic();
11✔
2163
}
2164

2165
/************************************************************************/
2166
/*                           SerializeToXML()                           */
2167
/************************************************************************/
2168

2169
CPLXMLNode *VRTNoDataFromMaskSource::SerializeToXML(const char *pszVRTPath)
8✔
2170

2171
{
2172
    CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
8✔
2173

2174
    if (psSrc == nullptr)
8✔
2175
        return nullptr;
×
2176

2177
    CPLFree(psSrc->pszValue);
8✔
2178
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
8✔
2179

2180
    if (m_bNoDataSet)
8✔
2181
    {
2182
        CPLSetXMLValue(psSrc, "MaskValueThreshold",
8✔
2183
                       CPLSPrintf("%.17g", m_dfMaskValueThreshold));
2184

2185
        GDALDataType eBandDT = GDT_Unknown;
8✔
2186
        double dfNoDataValue = m_dfNoDataValue;
8✔
2187
        const auto kMaxFloat = std::numeric_limits<float>::max();
8✔
2188
        if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
8✔
2189
            1e-10 * kMaxFloat)
2190
        {
2191
            auto l_band = GetRasterBand();
×
2192
            if (l_band)
×
2193
            {
2194
                eBandDT = l_band->GetRasterDataType();
×
2195
                if (eBandDT == GDT_Float32)
×
2196
                {
2197
                    dfNoDataValue =
2198
                        GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
×
2199
                }
2200
            }
2201
        }
2202
        CPLSetXMLValue(psSrc, "NODATA",
8✔
2203
                       VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
16✔
2204
    }
2205

2206
    if (m_bHasRemappedValue)
8✔
2207
    {
2208
        CPLSetXMLValue(psSrc, "RemappedValue",
×
2209
                       CPLSPrintf("%.17g", m_dfRemappedValue));
2210
    }
2211

2212
    return psSrc;
8✔
2213
}
2214

2215
/************************************************************************/
2216
/*                           SetParameters()                            */
2217
/************************************************************************/
2218

2219
void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
15✔
2220
                                            double dfMaskValueThreshold)
2221
{
2222
    m_bNoDataSet = true;
15✔
2223
    m_dfNoDataValue = dfNoDataValue;
15✔
2224
    m_dfMaskValueThreshold = dfMaskValueThreshold;
15✔
2225
    if (!m_bHasRemappedValue)
15✔
2226
        m_dfRemappedValue = m_dfNoDataValue;
15✔
2227
}
15✔
2228

2229
/************************************************************************/
2230
/*                           SetParameters()                            */
2231
/************************************************************************/
2232

2233
void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
×
2234
                                            double dfMaskValueThreshold,
2235
                                            double dfRemappedValue)
2236
{
2237
    SetParameters(dfNoDataValue, dfMaskValueThreshold);
×
2238
    m_bHasRemappedValue = true;
×
2239
    m_dfRemappedValue = dfRemappedValue;
×
2240
}
×
2241

2242
/************************************************************************/
2243
/*                              RasterIO()                              */
2244
/************************************************************************/
2245

2246
CPLErr VRTNoDataFromMaskSource::RasterIO(
13✔
2247
    GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
2248
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2249
    GSpacing nPixelSpace, GSpacing nLineSpace,
2250
    GDALRasterIOExtraArg *psExtraArgIn, WorkingState &oWorkingState)
2251

2252
{
2253
    if (!m_bNoDataSet)
13✔
2254
    {
2255
        return VRTSimpleSource::RasterIO(eVRTBandDataType, nXOff, nYOff, nXSize,
×
2256
                                         nYSize, pData, nBufXSize, nBufYSize,
2257
                                         eBufType, nPixelSpace, nLineSpace,
2258
                                         psExtraArgIn, oWorkingState);
×
2259
    }
2260

2261
    GDALRasterIOExtraArg sExtraArg;
2262
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
13✔
2263
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
13✔
2264

2265
    double dfXOff = nXOff;
13✔
2266
    double dfYOff = nYOff;
13✔
2267
    double dfXSize = nXSize;
13✔
2268
    double dfYSize = nYSize;
13✔
2269
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
13✔
2270
    {
2271
        dfXOff = psExtraArgIn->dfXOff;
×
2272
        dfYOff = psExtraArgIn->dfYOff;
×
2273
        dfXSize = psExtraArgIn->dfXSize;
×
2274
        dfYSize = psExtraArgIn->dfYSize;
×
2275
    }
2276

2277
    // The window we will actually request from the source raster band.
2278
    double dfReqXOff = 0.0;
13✔
2279
    double dfReqYOff = 0.0;
13✔
2280
    double dfReqXSize = 0.0;
13✔
2281
    double dfReqYSize = 0.0;
13✔
2282
    int nReqXOff = 0;
13✔
2283
    int nReqYOff = 0;
13✔
2284
    int nReqXSize = 0;
13✔
2285
    int nReqYSize = 0;
13✔
2286

2287
    // The window we will actual set _within_ the pData buffer.
2288
    int nOutXOff = 0;
13✔
2289
    int nOutYOff = 0;
13✔
2290
    int nOutXSize = 0;
13✔
2291
    int nOutYSize = 0;
13✔
2292

2293
    bool bError = false;
13✔
2294
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
13✔
2295
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
2296
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
2297
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
2298
    {
2299
        return bError ? CE_Failure : CE_None;
×
2300
    }
2301

2302
    auto l_band = GetRasterBand();
13✔
2303
    if (!l_band)
13✔
2304
        return CE_Failure;
×
2305

2306
    /* -------------------------------------------------------------------- */
2307
    /*      Allocate temporary buffer(s).                                   */
2308
    /* -------------------------------------------------------------------- */
2309
    const auto eSrcBandDT = l_band->GetRasterDataType();
13✔
2310
    const int nSrcBandDTSize = GDALGetDataTypeSizeBytes(eSrcBandDT);
13✔
2311
    const auto eSrcMaskBandDT = l_band->GetMaskBand()->GetRasterDataType();
13✔
2312
    const int nSrcMaskBandDTSize = GDALGetDataTypeSizeBytes(eSrcMaskBandDT);
13✔
2313
    double dfRemappedValue = m_dfRemappedValue;
13✔
2314
    if (!m_bHasRemappedValue)
13✔
2315
    {
2316
        if (eSrcBandDT == GDT_Byte &&
19✔
2317
            m_dfNoDataValue >= std::numeric_limits<GByte>::min() &&
6✔
2318
            m_dfNoDataValue <= std::numeric_limits<GByte>::max() &&
25✔
2319
            static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
6✔
2320
        {
2321
            if (m_dfNoDataValue == std::numeric_limits<GByte>::max())
6✔
2322
                dfRemappedValue = m_dfNoDataValue - 1;
1✔
2323
            else
2324
                dfRemappedValue = m_dfNoDataValue + 1;
5✔
2325
        }
2326
        else if (eSrcBandDT == GDT_UInt16 &&
10✔
2327
                 m_dfNoDataValue >= std::numeric_limits<uint16_t>::min() &&
3✔
2328
                 m_dfNoDataValue <= std::numeric_limits<uint16_t>::max() &&
13✔
2329
                 static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
3✔
2330
        {
2331
            if (m_dfNoDataValue == std::numeric_limits<uint16_t>::max())
3✔
2332
                dfRemappedValue = m_dfNoDataValue - 1;
1✔
2333
            else
2334
                dfRemappedValue = m_dfNoDataValue + 1;
2✔
2335
        }
2336
        else if (eSrcBandDT == GDT_Int16 &&
6✔
2337
                 m_dfNoDataValue >= std::numeric_limits<int16_t>::min() &&
2✔
2338
                 m_dfNoDataValue <= std::numeric_limits<int16_t>::max() &&
8✔
2339
                 static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2✔
2340
        {
2341
            if (m_dfNoDataValue == std::numeric_limits<int16_t>::max())
2✔
2342
                dfRemappedValue = m_dfNoDataValue - 1;
1✔
2343
            else
2344
                dfRemappedValue = m_dfNoDataValue + 1;
1✔
2345
        }
2346
        else
2347
        {
2348
            constexpr double EPS = 1e-3;
2✔
2349
            if (m_dfNoDataValue == 0)
2✔
2350
                dfRemappedValue = EPS;
1✔
2351
            else
2352
                dfRemappedValue = m_dfNoDataValue * (1 + EPS);
1✔
2353
        }
2354
    }
2355
    const bool bByteOptim =
13✔
2356
        (eSrcBandDT == GDT_Byte && eBufType == GDT_Byte &&
6✔
2357
         eSrcMaskBandDT == GDT_Byte && m_dfMaskValueThreshold >= 0 &&
5✔
2358
         m_dfMaskValueThreshold <= 255 &&
5✔
2359
         static_cast<int>(m_dfMaskValueThreshold) == m_dfMaskValueThreshold &&
5✔
2360
         m_dfNoDataValue >= 0 && m_dfNoDataValue <= 255 &&
4✔
2361
         static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue &&
4✔
2362
         dfRemappedValue >= 0 && dfRemappedValue <= 255 &&
23✔
2363
         static_cast<int>(dfRemappedValue) == dfRemappedValue);
4✔
2364
    GByte *pabyWrkBuffer;
2365
    try
2366
    {
2367
        if (bByteOptim && nOutXOff == 0 && nOutYOff == 0 &&
13✔
2368
            nOutXSize == nBufXSize && nOutYSize == nBufYSize &&
4✔
2369
            eSrcBandDT == eBufType && nPixelSpace == nSrcBandDTSize &&
4✔
2370
            nLineSpace == nPixelSpace * nBufXSize)
4✔
2371
        {
2372
            pabyWrkBuffer = static_cast<GByte *>(pData);
4✔
2373
        }
2374
        else
2375
        {
2376
            oWorkingState.m_abyWrkBuffer.resize(static_cast<size_t>(nOutXSize) *
9✔
2377
                                                nOutYSize * nSrcBandDTSize);
9✔
2378
            pabyWrkBuffer =
2379
                reinterpret_cast<GByte *>(oWorkingState.m_abyWrkBuffer.data());
9✔
2380
        }
2381
        oWorkingState.m_abyWrkBufferMask.resize(static_cast<size_t>(nOutXSize) *
13✔
2382
                                                nOutYSize * nSrcMaskBandDTSize);
13✔
2383
    }
2384
    catch (const std::exception &)
×
2385
    {
2386
        CPLError(CE_Failure, CPLE_OutOfMemory,
×
2387
                 "Out of memory when allocating buffers");
2388
        return CE_Failure;
×
2389
    }
2390

2391
    /* -------------------------------------------------------------------- */
2392
    /*      Load data.                                                      */
2393
    /* -------------------------------------------------------------------- */
2394
    if (!m_osResampling.empty())
13✔
2395
    {
2396
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
×
2397
    }
2398
    else if (psExtraArgIn != nullptr)
13✔
2399
    {
2400
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
13✔
2401
    }
2402

2403
    psExtraArg->bFloatingPointWindowValidity = TRUE;
13✔
2404
    psExtraArg->dfXOff = dfReqXOff;
13✔
2405
    psExtraArg->dfYOff = dfReqYOff;
13✔
2406
    psExtraArg->dfXSize = dfReqXSize;
13✔
2407
    psExtraArg->dfYSize = dfReqYSize;
13✔
2408
    if (psExtraArgIn)
13✔
2409
    {
2410
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
13✔
2411
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
13✔
2412
    }
2413

2414
    if (l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
13✔
2415
                         pabyWrkBuffer, nOutXSize, nOutYSize, eSrcBandDT, 0, 0,
2416
                         psExtraArg) != CE_None)
13✔
2417
    {
2418
        return CE_Failure;
×
2419
    }
2420

2421
    if (l_band->GetMaskBand()->RasterIO(
26✔
2422
            GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2423
            oWorkingState.m_abyWrkBufferMask.data(), nOutXSize, nOutYSize,
13✔
2424
            eSrcMaskBandDT, 0, 0, psExtraArg) != CE_None)
13✔
2425
    {
2426
        return CE_Failure;
×
2427
    }
2428

2429
    /* -------------------------------------------------------------------- */
2430
    /*      Do the processing.                                              */
2431
    /* -------------------------------------------------------------------- */
2432

2433
    GByte *const pabyOut = static_cast<GByte *>(pData) +
13✔
2434
                           nPixelSpace * nOutXOff +
13✔
2435
                           static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
13✔
2436
    if (bByteOptim)
13✔
2437
    {
2438
        // Special case when everything fits on Byte
2439
        const GByte nMaskValueThreshold =
4✔
2440
            static_cast<GByte>(m_dfMaskValueThreshold);
4✔
2441
        const GByte nNoDataValue = static_cast<GByte>(m_dfNoDataValue);
4✔
2442
        const GByte nRemappedValue = static_cast<GByte>(dfRemappedValue);
4✔
2443
        size_t nSrcIdx = 0;
4✔
2444
        for (int iY = 0; iY < nOutYSize; iY++)
8✔
2445
        {
2446
            GSpacing nDstOffset = iY * nLineSpace;
4✔
2447
            for (int iX = 0; iX < nOutXSize; iX++)
12✔
2448
            {
2449
                const GByte nMaskVal =
2450
                    oWorkingState.m_abyWrkBufferMask[nSrcIdx];
8✔
2451
                if (nMaskVal <= nMaskValueThreshold)
8✔
2452
                {
2453
                    pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] = nNoDataValue;
4✔
2454
                }
2455
                else
2456
                {
2457
                    if (pabyWrkBuffer[nSrcIdx] == nNoDataValue)
4✔
2458
                    {
2459
                        pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2✔
2460
                            nRemappedValue;
2461
                    }
2462
                    else
2463
                    {
2464
                        pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2✔
2465
                            pabyWrkBuffer[nSrcIdx];
2✔
2466
                    }
2467
                }
2468
                nDstOffset += nPixelSpace;
8✔
2469
                nSrcIdx++;
8✔
2470
            }
2471
        }
2472
    }
2473
    else
2474
    {
2475
        size_t nSrcIdx = 0;
9✔
2476
        double dfMaskVal = 0;
9✔
2477
        const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
9✔
2478
        std::vector<GByte> abyDstNoData(nBufDTSize);
18✔
2479
        GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, abyDstNoData.data(),
9✔
2480
                      eBufType, 0, 1);
2481
        std::vector<GByte> abyRemappedValue(nBufDTSize);
18✔
2482
        GDALCopyWords(&dfRemappedValue, GDT_Float64, 0, abyRemappedValue.data(),
9✔
2483
                      eBufType, 0, 1);
2484
        for (int iY = 0; iY < nOutYSize; iY++)
18✔
2485
        {
2486
            GSpacing nDstOffset = iY * nLineSpace;
9✔
2487
            for (int iX = 0; iX < nOutXSize; iX++)
28✔
2488
            {
2489
                if (eSrcMaskBandDT == GDT_Byte)
19✔
2490
                {
2491
                    dfMaskVal = oWorkingState.m_abyWrkBufferMask[nSrcIdx];
19✔
2492
                }
2493
                else
2494
                {
2495
                    GDALCopyWords(oWorkingState.m_abyWrkBufferMask.data() +
×
2496
                                      nSrcIdx * nSrcMaskBandDTSize,
×
2497
                                  eSrcMaskBandDT, 0, &dfMaskVal, GDT_Float64, 0,
2498
                                  1);
2499
                }
2500
                void *const pDst =
19✔
2501
                    pabyOut + static_cast<GPtrDiff_t>(nDstOffset);
19✔
2502
                if (!(dfMaskVal > m_dfMaskValueThreshold))
19✔
2503
                {
2504
                    memcpy(pDst, abyDstNoData.data(), nBufDTSize);
9✔
2505
                }
2506
                else
2507
                {
2508
                    const void *const pSrc =
10✔
2509
                        pabyWrkBuffer + nSrcIdx * nSrcBandDTSize;
10✔
2510
                    if (eSrcBandDT == eBufType)
10✔
2511
                    {
2512
                        // coverity[overrun-buffer-arg]
2513
                        memcpy(pDst, pSrc, nBufDTSize);
8✔
2514
                    }
2515
                    else
2516
                    {
2517
                        GDALCopyWords(pSrc, eSrcBandDT, 0, pDst, eBufType, 0,
2✔
2518
                                      1);
2519
                    }
2520
                    if (memcmp(pDst, abyDstNoData.data(), nBufDTSize) == 0)
10✔
2521
                        memcpy(pDst, abyRemappedValue.data(), nBufDTSize);
9✔
2522
                }
2523
                nDstOffset += nPixelSpace;
19✔
2524
                nSrcIdx++;
19✔
2525
            }
2526
        }
2527
    }
2528

2529
    if (psExtraArg->pfnProgress)
13✔
2530
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
×
2531

2532
    return CE_None;
13✔
2533
}
2534

2535
/************************************************************************/
2536
/*                             GetMinimum()                             */
2537
/************************************************************************/
2538

2539
double VRTNoDataFromMaskSource::GetMinimum(int /* nXSize */, int /* nYSize */,
×
2540
                                           int *pbSuccess)
2541
{
2542
    *pbSuccess = FALSE;
×
2543
    return 0.0;
×
2544
}
2545

2546
/************************************************************************/
2547
/*                             GetMaximum()                             */
2548
/************************************************************************/
2549

2550
double VRTNoDataFromMaskSource::GetMaximum(int /* nXSize */, int /* nYSize */,
×
2551
                                           int *pbSuccess)
2552
{
2553
    *pbSuccess = FALSE;
×
2554
    return 0.0;
×
2555
}
2556

2557
/************************************************************************/
2558
/*                            GetHistogram()                            */
2559
/************************************************************************/
2560

2561
CPLErr VRTNoDataFromMaskSource::GetHistogram(
×
2562
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2563
    int /* nBuckets */, GUIntBig * /* panHistogram */,
2564
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
2565
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2566
{
2567
    return CE_Failure;
×
2568
}
2569

2570
/************************************************************************/
2571
/* ==================================================================== */
2572
/*                          VRTComplexSource                            */
2573
/* ==================================================================== */
2574
/************************************************************************/
2575

2576
/************************************************************************/
2577
/*                          VRTComplexSource()                          */
2578
/************************************************************************/
2579

2580
VRTComplexSource::VRTComplexSource(const VRTComplexSource *poSrcSource,
5✔
2581
                                   double dfXDstRatio, double dfYDstRatio)
5✔
2582
    : VRTSimpleSource(poSrcSource, dfXDstRatio, dfYDstRatio),
2583
      m_nProcessingFlags(poSrcSource->m_nProcessingFlags),
5✔
2584
      m_dfNoDataValue(poSrcSource->m_dfNoDataValue),
5✔
2585
      m_osNoDataValueOri(poSrcSource->m_osNoDataValueOri),
5✔
2586
      m_dfScaleOff(poSrcSource->m_dfScaleOff),
5✔
2587
      m_dfScaleRatio(poSrcSource->m_dfScaleRatio),
5✔
2588
      m_bSrcMinMaxDefined(poSrcSource->m_bSrcMinMaxDefined),
5✔
2589
      m_dfSrcMin(poSrcSource->m_dfSrcMin), m_dfSrcMax(poSrcSource->m_dfSrcMax),
5✔
2590
      m_dfDstMin(poSrcSource->m_dfDstMin), m_dfDstMax(poSrcSource->m_dfDstMax),
5✔
2591
      m_dfExponent(poSrcSource->m_dfExponent), m_bClip(poSrcSource->m_bClip),
5✔
2592
      m_nColorTableComponent(poSrcSource->m_nColorTableComponent),
5✔
2593
      m_adfLUTInputs(poSrcSource->m_adfLUTInputs),
5✔
2594
      m_adfLUTOutputs(poSrcSource->m_adfLUTOutputs)
5✔
2595
{
2596
}
5✔
2597

2598
/************************************************************************/
2599
/*                           GetTypeStatic()                            */
2600
/************************************************************************/
2601

2602
const char *VRTComplexSource::GetTypeStatic()
13,745✔
2603
{
2604
    static const char *TYPE = "ComplexSource";
2605
    return TYPE;
13,745✔
2606
}
2607

2608
/************************************************************************/
2609
/*                            GetType()                                 */
2610
/************************************************************************/
2611

2612
const char *VRTComplexSource::GetType() const
3,991✔
2613
{
2614
    return GetTypeStatic();
3,991✔
2615
}
2616

2617
/************************************************************************/
2618
/*                           SetNoDataValue()                           */
2619
/************************************************************************/
2620

2621
void VRTComplexSource::SetNoDataValue(double dfNewNoDataValue)
86✔
2622

2623
{
2624
    if (dfNewNoDataValue == VRT_NODATA_UNSET)
86✔
2625
    {
2626
        m_nProcessingFlags &= ~PROCESSING_FLAG_NODATA;
×
2627
        m_dfNoDataValue = VRT_NODATA_UNSET;
×
2628
        return;
×
2629
    }
2630

2631
    m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
86✔
2632
    m_dfNoDataValue = dfNewNoDataValue;
86✔
2633
}
2634

2635
/************************************************************************/
2636
/*                      GetAdjustedNoDataValue()                        */
2637
/************************************************************************/
2638

2639
double VRTComplexSource::GetAdjustedNoDataValue() const
5,005✔
2640
{
2641
    if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
5,005✔
2642
    {
2643
        auto l_band = GetRasterBand();
47✔
2644
        if (l_band && l_band->GetRasterDataType() == GDT_Float32)
47✔
2645
        {
2646
            return GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
21✔
2647
        }
2648
    }
2649
    return m_dfNoDataValue;
4,984✔
2650
}
2651

2652
/************************************************************************/
2653
/*                           SerializeToXML()                           */
2654
/************************************************************************/
2655

2656
CPLXMLNode *VRTComplexSource::SerializeToXML(const char *pszVRTPath)
67✔
2657

2658
{
2659
    CPLXMLNode *psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
67✔
2660

2661
    if (psSrc == nullptr)
67✔
2662
        return nullptr;
×
2663

2664
    CPLFree(psSrc->pszValue);
67✔
2665
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
67✔
2666

2667
    if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0)
67✔
2668
    {
2669
        CPLSetXMLValue(psSrc, "UseMaskBand", "true");
33✔
2670
    }
2671

2672
    if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
67✔
2673
    {
2674
        if (!m_osNoDataValueOri.empty() && GetRasterBandNoOpen() == nullptr)
24✔
2675
        {
2676
            CPLSetXMLValue(psSrc, "NODATA", m_osNoDataValueOri.c_str());
1✔
2677
        }
2678
        else
2679
        {
2680
            GDALDataType eBandDT = GDT_Unknown;
23✔
2681
            double dfNoDataValue = m_dfNoDataValue;
23✔
2682
            const auto kMaxFloat = std::numeric_limits<float>::max();
23✔
2683
            if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
23✔
2684
                1e-10 * kMaxFloat)
2685
            {
2686
                auto l_band = GetRasterBand();
1✔
2687
                if (l_band)
1✔
2688
                {
2689
                    dfNoDataValue = GetAdjustedNoDataValue();
1✔
2690
                    eBandDT = l_band->GetRasterDataType();
1✔
2691
                }
2692
            }
2693
            CPLSetXMLValue(
23✔
2694
                psSrc, "NODATA",
2695
                VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
46✔
2696
        }
2697
    }
2698

2699
    if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
67✔
2700
    {
2701
        CPLSetXMLValue(psSrc, "ScaleOffset", CPLSPrintf("%g", m_dfScaleOff));
1✔
2702
        CPLSetXMLValue(psSrc, "ScaleRatio", CPLSPrintf("%g", m_dfScaleRatio));
1✔
2703
    }
2704
    else if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
66✔
2705
    {
2706
        CPLSetXMLValue(psSrc, "Exponent", CPLSPrintf("%g", m_dfExponent));
×
2707
        if (m_bSrcMinMaxDefined)
×
2708
        {
2709
            CPLSetXMLValue(psSrc, "SrcMin", CPLSPrintf("%g", m_dfSrcMin));
×
2710
            CPLSetXMLValue(psSrc, "SrcMax", CPLSPrintf("%g", m_dfSrcMax));
×
2711
        }
2712
        CPLSetXMLValue(psSrc, "DstMin", CPLSPrintf("%g", m_dfDstMin));
×
2713
        CPLSetXMLValue(psSrc, "DstMax", CPLSPrintf("%g", m_dfDstMax));
×
2714
        CPLSetXMLValue(psSrc, "Clip", m_bClip ? "true" : "false");
×
2715
    }
2716

2717
    if (!m_adfLUTInputs.empty())
67✔
2718
    {
2719
        // Make sure we print with sufficient precision to address really close
2720
        // entries (#6422).
2721
        CPLString osLUT;
×
2722
        if (m_adfLUTInputs.size() >= 2 &&
×
2723
            CPLString().Printf("%g", m_adfLUTInputs[0]) ==
×
2724
                CPLString().Printf("%g", m_adfLUTInputs[1]))
×
2725
        {
2726
            osLUT = CPLString().Printf("%.17g:%g", m_adfLUTInputs[0],
×
2727
                                       m_adfLUTOutputs[0]);
×
2728
        }
2729
        else
2730
        {
2731
            osLUT = CPLString().Printf("%g:%g", m_adfLUTInputs[0],
×
2732
                                       m_adfLUTOutputs[0]);
×
2733
        }
2734
        for (size_t i = 1; i < m_adfLUTInputs.size(); i++)
×
2735
        {
2736
            if (CPLString().Printf("%g", m_adfLUTInputs[i]) ==
×
2737
                    CPLString().Printf("%g", m_adfLUTInputs[i - 1]) ||
×
2738
                (i + 1 < m_adfLUTInputs.size() &&
×
2739
                 CPLString().Printf("%g", m_adfLUTInputs[i]) ==
×
2740
                     CPLString().Printf("%g", m_adfLUTInputs[i + 1])))
×
2741
            {
2742
                // TODO(schwehr): An explanation of the 18 would be helpful.
2743
                // Can someone distill the issue down to a quick comment?
2744
                // https://trac.osgeo.org/gdal/ticket/6422
2745
                osLUT += CPLString().Printf(",%.17g:%g", m_adfLUTInputs[i],
×
2746
                                            m_adfLUTOutputs[i]);
×
2747
            }
2748
            else
2749
            {
2750
                osLUT += CPLString().Printf(",%g:%g", m_adfLUTInputs[i],
×
2751
                                            m_adfLUTOutputs[i]);
×
2752
            }
2753
        }
2754
        CPLSetXMLValue(psSrc, "LUT", osLUT);
×
2755
    }
2756

2757
    if (m_nColorTableComponent)
67✔
2758
    {
2759
        CPLSetXMLValue(psSrc, "ColorTableComponent",
7✔
2760
                       CPLSPrintf("%d", m_nColorTableComponent));
2761
    }
2762

2763
    return psSrc;
67✔
2764
}
2765

2766
/************************************************************************/
2767
/*                              XMLInit()                               */
2768
/************************************************************************/
2769

2770
CPLErr VRTComplexSource::XMLInit(const CPLXMLNode *psSrc,
259✔
2771
                                 const char *pszVRTPath,
2772
                                 VRTMapSharedResources &oMapSharedSources)
2773

2774
{
2775
    /* -------------------------------------------------------------------- */
2776
    /*      Do base initialization.                                         */
2777
    /* -------------------------------------------------------------------- */
2778
    {
2779
        const CPLErr eErr =
2780
            VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
259✔
2781
        if (eErr != CE_None)
259✔
2782
            return eErr;
×
2783
    }
2784

2785
    /* -------------------------------------------------------------------- */
2786
    /*      Complex parameters.                                             */
2787
    /* -------------------------------------------------------------------- */
2788
    const char *pszScaleOffset = CPLGetXMLValue(psSrc, "ScaleOffset", nullptr);
259✔
2789
    const char *pszScaleRatio = CPLGetXMLValue(psSrc, "ScaleRatio", nullptr);
259✔
2790
    if (pszScaleOffset || pszScaleRatio)
259✔
2791
    {
2792
        m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
28✔
2793
        if (pszScaleOffset)
28✔
2794
            m_dfScaleOff = CPLAtof(pszScaleOffset);
28✔
2795
        if (pszScaleRatio)
28✔
2796
            m_dfScaleRatio = CPLAtof(pszScaleRatio);
25✔
2797
    }
2798
    else if (CPLGetXMLValue(psSrc, "Exponent", nullptr) != nullptr &&
231✔
2799
             CPLGetXMLValue(psSrc, "DstMin", nullptr) != nullptr &&
232✔
2800
             CPLGetXMLValue(psSrc, "DstMax", nullptr) != nullptr)
1✔
2801
    {
2802
        m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
1✔
2803
        m_dfExponent = CPLAtof(CPLGetXMLValue(psSrc, "Exponent", "1.0"));
1✔
2804

2805
        const char *pszSrcMin = CPLGetXMLValue(psSrc, "SrcMin", nullptr);
1✔
2806
        const char *pszSrcMax = CPLGetXMLValue(psSrc, "SrcMax", nullptr);
1✔
2807
        if (pszSrcMin && pszSrcMax)
1✔
2808
        {
2809
            m_dfSrcMin = CPLAtof(pszSrcMin);
×
2810
            m_dfSrcMax = CPLAtof(pszSrcMax);
×
2811
            m_bSrcMinMaxDefined = true;
×
2812
        }
2813

2814
        m_dfDstMin = CPLAtof(CPLGetXMLValue(psSrc, "DstMin", "0.0"));
1✔
2815
        m_dfDstMax = CPLAtof(CPLGetXMLValue(psSrc, "DstMax", "0.0"));
1✔
2816
        m_bClip = CPLTestBool(CPLGetXMLValue(psSrc, "Clip", "true"));
1✔
2817
    }
2818

2819
    if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
259✔
2820
    {
2821
        m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
63✔
2822
        m_osNoDataValueOri = pszNODATA;
63✔
2823
        m_dfNoDataValue = CPLAtofM(m_osNoDataValueOri.c_str());
63✔
2824
    }
2825

2826
    const char *pszUseMaskBand = CPLGetXMLValue(psSrc, "UseMaskBand", nullptr);
259✔
2827
    if (pszUseMaskBand && CPLTestBool(pszUseMaskBand))
259✔
2828
    {
2829
        m_nProcessingFlags |= PROCESSING_FLAG_USE_MASK_BAND;
41✔
2830
    }
2831

2832
    const char *pszLUT = CPLGetXMLValue(psSrc, "LUT", nullptr);
259✔
2833
    if (pszLUT)
259✔
2834
    {
2835
        const CPLStringList aosValues(
2836
            CSLTokenizeString2(pszLUT, ",:", CSLT_ALLOWEMPTYTOKENS));
75✔
2837

2838
        const int nLUTItemCount = aosValues.size() / 2;
75✔
2839
        try
2840
        {
2841
            m_adfLUTInputs.resize(nLUTItemCount);
75✔
2842
            m_adfLUTOutputs.resize(nLUTItemCount);
75✔
2843
        }
2844
        catch (const std::bad_alloc &e)
×
2845
        {
2846
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
2847
            m_adfLUTInputs.clear();
×
2848
            m_adfLUTOutputs.clear();
×
2849
            return CE_Failure;
×
2850
        }
2851

2852
        for (int nIndex = 0; nIndex < nLUTItemCount; nIndex++)
732✔
2853
        {
2854
            m_adfLUTInputs[nIndex] = CPLAtof(aosValues[nIndex * 2]);
657✔
2855
            m_adfLUTOutputs[nIndex] = CPLAtof(aosValues[nIndex * 2 + 1]);
657✔
2856

2857
            // Enforce the requirement that the LUT input array is
2858
            // monotonically non-decreasing.
2859
            if (std::isnan(m_adfLUTInputs[nIndex]) && nIndex != 0)
657✔
2860
            {
2861
                CPLError(CE_Failure, CPLE_AppDefined,
×
2862
                         "A Not-A-Number (NaN) source value should be the "
2863
                         "first one of the LUT.");
2864
                m_adfLUTInputs.clear();
×
2865
                m_adfLUTOutputs.clear();
×
2866
                return CE_Failure;
×
2867
            }
2868
            else if (nIndex > 0 &&
1,239✔
2869
                     m_adfLUTInputs[nIndex] < m_adfLUTInputs[nIndex - 1])
582✔
2870
            {
2871
                CPLError(CE_Failure, CPLE_AppDefined,
×
2872
                         "Source values of the LUT are not listed in a "
2873
                         "monotonically non-decreasing order");
2874
                m_adfLUTInputs.clear();
×
2875
                m_adfLUTOutputs.clear();
×
2876
                return CE_Failure;
×
2877
            }
2878
        }
2879

2880
        m_nProcessingFlags |= PROCESSING_FLAG_LUT;
75✔
2881
    }
2882

2883
    const char *pszColorTableComponent =
2884
        CPLGetXMLValue(psSrc, "ColorTableComponent", nullptr);
259✔
2885
    if (pszColorTableComponent)
259✔
2886
    {
2887
        m_nColorTableComponent = atoi(pszColorTableComponent);
15✔
2888
        m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
15✔
2889
    }
2890

2891
    return CE_None;
259✔
2892
}
2893

2894
/************************************************************************/
2895
/*                              LookupValue()                           */
2896
/************************************************************************/
2897

2898
double VRTComplexSource::LookupValue(double dfInput)
817,592✔
2899
{
2900
    auto beginIter = m_adfLUTInputs.begin();
817,592✔
2901
    auto endIter = m_adfLUTInputs.end();
817,592✔
2902
    size_t offset = 0;
817,592✔
2903
    if (std::isnan(m_adfLUTInputs[0]))
817,592✔
2904
    {
2905
        if (std::isnan(dfInput) || m_adfLUTInputs.size() == 1)
6✔
2906
            return m_adfLUTOutputs[0];
1✔
2907
        ++beginIter;
5✔
2908
        offset = 1;
5✔
2909
    }
2910

2911
    // Find the index of the first element in the LUT input array that
2912
    // is not smaller than the input value.
2913
    const size_t i =
2914
        offset +
2915
        std::distance(beginIter, std::lower_bound(beginIter, endIter, dfInput));
817,591✔
2916

2917
    if (i == offset)
817,591✔
2918
        return m_adfLUTOutputs[offset];
129,039✔
2919

2920
    // If the index is beyond the end of the LUT input array, the input
2921
    // value is larger than all the values in the array.
2922
    if (i == m_adfLUTInputs.size())
688,552✔
2923
        return m_adfLUTOutputs.back();
8✔
2924

2925
    if (m_adfLUTInputs[i] == dfInput)
688,544✔
2926
        return m_adfLUTOutputs[i];
240,268✔
2927

2928
    // Otherwise, interpolate.
2929
    return m_adfLUTOutputs[i - 1] +
448,276✔
2930
           (dfInput - m_adfLUTInputs[i - 1]) *
448,276✔
2931
               ((m_adfLUTOutputs[i] - m_adfLUTOutputs[i - 1]) /
448,276✔
2932
                (m_adfLUTInputs[i] - m_adfLUTInputs[i - 1]));
448,276✔
2933
}
2934

2935
/************************************************************************/
2936
/*                         SetLinearScaling()                           */
2937
/************************************************************************/
2938

2939
void VRTComplexSource::SetLinearScaling(double dfOffset, double dfScale)
106✔
2940
{
2941
    m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_EXPONENTIAL;
106✔
2942
    m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
106✔
2943
    m_dfScaleOff = dfOffset;
106✔
2944
    m_dfScaleRatio = dfScale;
106✔
2945
}
106✔
2946

2947
/************************************************************************/
2948
/*                         SetPowerScaling()                           */
2949
/************************************************************************/
2950

2951
void VRTComplexSource::SetPowerScaling(double dfExponentIn, double dfSrcMinIn,
26✔
2952
                                       double dfSrcMaxIn, double dfDstMinIn,
2953
                                       double dfDstMaxIn, bool bClip)
2954
{
2955
    m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_LINEAR;
26✔
2956
    m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
26✔
2957
    m_dfExponent = dfExponentIn;
26✔
2958
    m_dfSrcMin = dfSrcMinIn;
26✔
2959
    m_dfSrcMax = dfSrcMaxIn;
26✔
2960
    m_dfDstMin = dfDstMinIn;
26✔
2961
    m_dfDstMax = dfDstMaxIn;
26✔
2962
    m_bSrcMinMaxDefined = true;
26✔
2963
    m_bClip = bClip;
26✔
2964
}
26✔
2965

2966
/************************************************************************/
2967
/*                    SetColorTableComponent()                          */
2968
/************************************************************************/
2969

2970
void VRTComplexSource::SetColorTableComponent(int nComponent)
245✔
2971
{
2972
    m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
245✔
2973
    m_nColorTableComponent = nComponent;
245✔
2974
}
245✔
2975

2976
/************************************************************************/
2977
/*                              RasterIO()                              */
2978
/************************************************************************/
2979

2980
CPLErr VRTComplexSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
16,001✔
2981
                                  int nYOff, int nXSize, int nYSize,
2982
                                  void *pData, int nBufXSize, int nBufYSize,
2983
                                  GDALDataType eBufType, GSpacing nPixelSpace,
2984
                                  GSpacing nLineSpace,
2985
                                  GDALRasterIOExtraArg *psExtraArgIn,
2986
                                  WorkingState &oWorkingState)
2987

2988
{
2989
    GDALRasterIOExtraArg sExtraArg;
2990
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
16,001✔
2991
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
16,001✔
2992

2993
    double dfXOff = nXOff;
16,001✔
2994
    double dfYOff = nYOff;
16,001✔
2995
    double dfXSize = nXSize;
16,001✔
2996
    double dfYSize = nYSize;
16,001✔
2997
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
16,001✔
2998
    {
2999
        dfXOff = psExtraArgIn->dfXOff;
87✔
3000
        dfYOff = psExtraArgIn->dfYOff;
87✔
3001
        dfXSize = psExtraArgIn->dfXSize;
87✔
3002
        dfYSize = psExtraArgIn->dfYSize;
87✔
3003
    }
3004

3005
    // The window we will actually request from the source raster band.
3006
    double dfReqXOff = 0.0;
16,001✔
3007
    double dfReqYOff = 0.0;
16,001✔
3008
    double dfReqXSize = 0.0;
16,001✔
3009
    double dfReqYSize = 0.0;
16,001✔
3010
    int nReqXOff = 0;
16,001✔
3011
    int nReqYOff = 0;
16,001✔
3012
    int nReqXSize = 0;
16,001✔
3013
    int nReqYSize = 0;
16,001✔
3014

3015
    // The window we will actual set _within_ the pData buffer.
3016
    int nOutXOff = 0;
16,001✔
3017
    int nOutYOff = 0;
16,001✔
3018
    int nOutXSize = 0;
16,001✔
3019
    int nOutYSize = 0;
16,001✔
3020

3021
    bool bError = false;
16,001✔
3022
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
16,001✔
3023
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
3024
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
3025
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
3026
    {
3027
        return bError ? CE_Failure : CE_None;
10,949✔
3028
    }
3029
#if DEBUG_VERBOSE
3030
    CPLDebug("VRT",
3031
             "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
3032
             "nBufYSize=%d,\n"
3033
             "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
3034
             "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
3035
             "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
3036
             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
3037
             dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
3038
             nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
3039
#endif
3040

3041
    auto poSourceBand = GetRasterBand();
5,052✔
3042
    if (!poSourceBand)
5,052✔
3043
        return CE_Failure;
×
3044

3045
    if (!m_osResampling.empty())
5,052✔
3046
    {
3047
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
28✔
3048
    }
3049
    else if (psExtraArgIn != nullptr)
5,024✔
3050
    {
3051
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
5,024✔
3052
    }
3053
    psExtraArg->bFloatingPointWindowValidity = TRUE;
5,052✔
3054
    psExtraArg->dfXOff = dfReqXOff;
5,052✔
3055
    psExtraArg->dfYOff = dfReqYOff;
5,052✔
3056
    psExtraArg->dfXSize = dfReqXSize;
5,052✔
3057
    psExtraArg->dfYSize = dfReqYSize;
5,052✔
3058
    if (psExtraArgIn)
5,052✔
3059
    {
3060
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
5,052✔
3061
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
5,052✔
3062
    }
3063

3064
    GByte *const pabyOut = static_cast<GByte *>(pData) +
5,052✔
3065
                           nPixelSpace * nOutXOff +
5,052✔
3066
                           static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
5,052✔
3067
    const auto eSourceType = poSourceBand->GetRasterDataType();
5,052✔
3068
    if (m_nProcessingFlags == PROCESSING_FLAG_NODATA)
5,052✔
3069
    {
3070
        // Optimization if doing only nodata processing
3071
        if (eSourceType == GDT_Byte)
85✔
3072
        {
3073
            if (!GDALIsValueInRange<GByte>(m_dfNoDataValue))
45✔
3074
            {
3075
                return VRTSimpleSource::RasterIO(
7✔
3076
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3077
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3078
                    psExtraArgIn, oWorkingState);
7✔
3079
            }
3080

3081
            return RasterIOProcessNoData<GByte, GDT_Byte>(
38✔
3082
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3083
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3084
                nLineSpace, psExtraArg, oWorkingState);
38✔
3085
        }
3086
        else if (eSourceType == GDT_Int16)
40✔
3087
        {
3088
            if (!GDALIsValueInRange<int16_t>(m_dfNoDataValue))
6✔
3089
            {
3090
                return VRTSimpleSource::RasterIO(
1✔
3091
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3092
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3093
                    psExtraArgIn, oWorkingState);
1✔
3094
            }
3095

3096
            return RasterIOProcessNoData<int16_t, GDT_Int16>(
5✔
3097
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3098
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3099
                nLineSpace, psExtraArg, oWorkingState);
5✔
3100
        }
3101
        else if (eSourceType == GDT_UInt16)
34✔
3102
        {
3103
            if (!GDALIsValueInRange<uint16_t>(m_dfNoDataValue))
11✔
3104
            {
3105
                return VRTSimpleSource::RasterIO(
1✔
3106
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3107
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3108
                    psExtraArgIn, oWorkingState);
1✔
3109
            }
3110

3111
            return RasterIOProcessNoData<uint16_t, GDT_UInt16>(
10✔
3112
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3113
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3114
                nLineSpace, psExtraArg, oWorkingState);
10✔
3115
        }
3116
    }
3117

3118
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
4,990✔
3119
    CPLErr eErr;
3120
    // For Int32, float32 isn't sufficiently precise as working data type
3121
    if (eVRTBandDataType == GDT_CInt32 || eVRTBandDataType == GDT_CFloat64 ||
4,990✔
3122
        eVRTBandDataType == GDT_Int32 || eVRTBandDataType == GDT_UInt32 ||
4,986✔
3123
        eVRTBandDataType == GDT_Int64 || eVRTBandDataType == GDT_UInt64 ||
4,982✔
3124
        eVRTBandDataType == GDT_Float64 || eSourceType == GDT_Int32 ||
4,958✔
3125
        eSourceType == GDT_UInt32 || eSourceType == GDT_Int64 ||
4,957✔
3126
        eSourceType == GDT_UInt64)
3127
    {
3128
        eErr = RasterIOInternal<double>(
34✔
3129
            poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3130
            nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3131
            nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat64 : GDT_Float64,
3132
            oWorkingState);
3133
    }
3134
    else
3135
    {
3136
        eErr = RasterIOInternal<float>(
4,956✔
3137
            poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3138
            nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3139
            nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32,
3140
            oWorkingState);
3141
    }
3142

3143
    if (psExtraArg->pfnProgress)
4,990✔
3144
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
43✔
3145

3146
    return eErr;
4,990✔
3147
}
3148

3149
/************************************************************************/
3150
/*                              hasZeroByte()                           */
3151
/************************************************************************/
3152

3153
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
3154
static inline bool hasZeroByte(uint32_t v)
3,437,720✔
3155
{
3156
    // Cf https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
3157
    return (((v)-0x01010101U) & ~(v)&0x80808080U) != 0;
3,437,720✔
3158
}
3159

3160
/************************************************************************/
3161
/*                                CopyWord()                            */
3162
/************************************************************************/
3163

3164
template <class SrcType>
3165
static void CopyWord(const SrcType *pSrcVal, GDALDataType eSrcType,
6,677,648✔
3166
                     void *pDstVal, GDALDataType eDstType)
3167
{
3168
    switch (eDstType)
6,677,648✔
3169
    {
3170
        case GDT_Byte:
2,383,720✔
3171
            GDALCopyWord(*pSrcVal, *static_cast<uint8_t *>(pDstVal));
2,383,720✔
3172
            break;
2,383,720✔
3173
        case GDT_Int8:
82✔
3174
            GDALCopyWord(*pSrcVal, *static_cast<int8_t *>(pDstVal));
82✔
3175
            break;
82✔
3176
        case GDT_UInt16:
1,353,720✔
3177
            GDALCopyWord(*pSrcVal, *static_cast<uint16_t *>(pDstVal));
1,353,720✔
3178
            break;
1,353,720✔
3179
        case GDT_Int16:
2,925,180✔
3180
            GDALCopyWord(*pSrcVal, *static_cast<int16_t *>(pDstVal));
2,925,180✔
3181
            break;
2,925,180✔
3182
        case GDT_UInt32:
22✔
3183
            GDALCopyWord(*pSrcVal, *static_cast<uint32_t *>(pDstVal));
22✔
3184
            break;
22✔
3185
        case GDT_Int32:
641✔
3186
            GDALCopyWord(*pSrcVal, *static_cast<int32_t *>(pDstVal));
641✔
3187
            break;
641✔
3188
        case GDT_UInt64:
22✔
3189
            GDALCopyWord(*pSrcVal, *static_cast<uint64_t *>(pDstVal));
22✔
3190
            break;
22✔
3191
        case GDT_Int64:
42✔
3192
            GDALCopyWord(*pSrcVal, *static_cast<int64_t *>(pDstVal));
42✔
3193
            break;
42✔
3194
        case GDT_Float32:
6,660✔
3195
            GDALCopyWord(*pSrcVal, *static_cast<float *>(pDstVal));
6,660✔
3196
            break;
6,660✔
3197
        case GDT_Float64:
6,539✔
3198
            GDALCopyWord(*pSrcVal, *static_cast<double *>(pDstVal));
6,539✔
3199
            break;
6,539✔
3200
        default:
1,019✔
3201
            GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1);
1,019✔
3202
            break;
1,019✔
3203
    }
3204
}
6,677,648✔
3205

3206
/************************************************************************/
3207
/*                       RasterIOProcessNoData()                        */
3208
/************************************************************************/
3209

3210
// This method is an optimization of the generic RasterIOInternal()
3211
// that deals with a VRTComplexSource with only a NODATA value in it, and
3212
// no other processing flags.
3213

3214
// nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3215
// referential.
3216
template <class SourceDT, GDALDataType eSourceType>
3217
CPLErr VRTComplexSource::RasterIOProcessNoData(
53✔
3218
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3219
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3220
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3221
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3222
    WorkingState &oWorkingState)
3223
{
3224
    CPLAssert(m_nProcessingFlags == PROCESSING_FLAG_NODATA);
53✔
3225
    CPLAssert(GDALIsValueInRange<SourceDT>(m_dfNoDataValue));
53✔
3226

3227
    /* -------------------------------------------------------------------- */
3228
    /*      Read into a temporary buffer.                                   */
3229
    /* -------------------------------------------------------------------- */
3230
    try
3231
    {
3232
        // Cannot overflow since pData should at least have that number of
3233
        // elements
3234
        const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
53✔
3235
        if (nPixelCount >
53✔
3236
            static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
53✔
3237
                sizeof(SourceDT))
3238
        {
3239
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
3240
                     "Too large temporary buffer");
3241
            return CE_Failure;
×
3242
        }
3243
        oWorkingState.m_abyWrkBuffer.resize(sizeof(SourceDT) * nPixelCount);
53✔
3244
    }
3245
    catch (const std::bad_alloc &e)
×
3246
    {
3247
        CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
3248
        return CE_Failure;
×
3249
    }
3250
    const auto paSrcData =
3251
        reinterpret_cast<const SourceDT *>(oWorkingState.m_abyWrkBuffer.data());
53✔
3252

3253
    const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
53✔
3254
    if (!m_osResampling.empty())
53✔
3255
    {
3256
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
×
3257
    }
3258

3259
    const CPLErr eErr = poSourceBand->RasterIO(
53✔
3260
        GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3261
        oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize, eSourceType,
53✔
3262
        sizeof(SourceDT), sizeof(SourceDT) * static_cast<GSpacing>(nOutXSize),
15✔
3263
        psExtraArg);
3264
    if (!m_osResampling.empty())
53✔
3265
        psExtraArg->eResampleAlg = eResampleAlgBack;
×
3266

3267
    if (eErr != CE_None)
53✔
3268
    {
3269
        return eErr;
×
3270
    }
3271

3272
    const auto nNoDataValue = static_cast<SourceDT>(m_dfNoDataValue);
53✔
3273
    size_t idxBuffer = 0;
53✔
3274
    if (eSourceType == eBufType &&
88✔
3275
        !GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
35✔
3276
    {
3277
        // Most optimized case: the output type is the same as the source type,
3278
        // and conversion from the source type to the VRT band data type is
3279
        // not lossy
3280
        for (int iY = 0; iY < nOutYSize; iY++)
32✔
3281
        {
3282
            GByte *pDstLocation = static_cast<GByte *>(pData) +
19,613✔
3283
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
19,613✔
3284

3285
            int iX = 0;
19,613✔
3286
            if (sizeof(SourceDT) == 1 && nPixelSpace == 1)
19,586✔
3287
            {
3288
                // Optimization to detect more quickly if source pixels are
3289
                // at nodata.
3290
                const GByte byNoDataValue = static_cast<GByte>(nNoDataValue);
19,588✔
3291
                const uint32_t wordNoData =
19,588✔
3292
                    (static_cast<uint32_t>(byNoDataValue) << 24) |
19,588✔
3293
                    (byNoDataValue << 16) | (byNoDataValue << 8) |
19,588✔
3294
                    byNoDataValue;
19,588✔
3295

3296
                // Warning: hasZeroByte() assumes WORD_SIZE = 4
3297
                constexpr int WORD_SIZE = 4;
19,588✔
3298
                for (; iX < nOutXSize - (WORD_SIZE - 1); iX += WORD_SIZE)
3,522,540✔
3299
                {
3300
                    uint32_t v;
3301
                    static_assert(sizeof(v) == WORD_SIZE,
3302
                                  "sizeof(v) == WORD_SIZE");
3303
                    memcpy(&v, paSrcData + idxBuffer, sizeof(v));
3,605,590✔
3304
                    // Cf https://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
3305
                    if (!hasZeroByte(v ^ wordNoData))
3,605,590✔
3306
                    {
3307
                        // No bytes are at nodata
3308
                        memcpy(pDstLocation, &v, WORD_SIZE);
3,527,720✔
3309
                        idxBuffer += WORD_SIZE;
3,527,720✔
3310
                        pDstLocation += WORD_SIZE;
3,527,720✔
3311
                    }
UNCOV
3312
                    else if (v == wordNoData)
×
3313
                    {
3314
                        // All bytes are at nodata
3315
                        idxBuffer += WORD_SIZE;
131,075✔
3316
                        pDstLocation += WORD_SIZE;
131,075✔
3317
                    }
3318
                    else
3319
                    {
3320
                        // There are both bytes at nodata and valid bytes
3321
                        for (int k = 0; k < WORD_SIZE; ++k)
×
3322
                        {
3323
                            if (paSrcData[idxBuffer] != nNoDataValue)
48✔
3324
                            {
3325
                                memcpy(pDstLocation, &paSrcData[idxBuffer],
36✔
3326
                                       sizeof(SourceDT));
3327
                            }
3328
                            idxBuffer++;
48✔
3329
                            pDstLocation += nPixelSpace;
48✔
3330
                        }
3331
                    }
3332
                }
3333
            }
3334

3335
            for (; iX < nOutXSize;
222✔
3336
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
3,845✔
3337
            {
3338
                if (paSrcData[idxBuffer] != nNoDataValue)
3,845✔
3339
                {
3340
                    memcpy(pDstLocation, &paSrcData[idxBuffer],
3,815✔
3341
                           sizeof(SourceDT));
3342
                }
3343
            }
3344
        }
3345
    }
3346
    else if (!GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
19✔
3347
    {
3348
        // Conversion from the source type to the VRT band data type is
3349
        // not lossy, so we can directly convert from the source type to
3350
        // the the output type
3351
        for (int iY = 0; iY < nOutYSize; iY++)
122✔
3352
        {
3353
            GByte *pDstLocation = static_cast<GByte *>(pData) +
104✔
3354
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
104✔
3355

3356
            for (int iX = 0; iX < nOutXSize;
1,584✔
3357
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
1,480✔
3358
            {
3359
                if (paSrcData[idxBuffer] != nNoDataValue)
1,480✔
3360
                {
3361
                    CopyWord(&paSrcData[idxBuffer], eSourceType, pDstLocation,
671✔
3362
                             eBufType);
3363
                }
3364
            }
3365
        }
3366
    }
3367
    else
3368
    {
3369
        GByte abyTemp[2 * sizeof(double)];
3370
        for (int iY = 0; iY < nOutYSize; iY++)
7✔
3371
        {
3372
            GByte *pDstLocation = static_cast<GByte *>(pData) +
6✔
3373
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
6✔
3374

3375
            for (int iX = 0; iX < nOutXSize;
36✔
3376
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
30✔
3377
            {
3378
                if (paSrcData[idxBuffer] != nNoDataValue)
30✔
3379
                {
3380
                    // Convert first to the VRTRasterBand data type
3381
                    // to get its clamping, before outputting to buffer data type
3382
                    CopyWord(&paSrcData[idxBuffer], eSourceType, abyTemp,
20✔
3383
                             eVRTBandDataType);
3384
                    GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
20✔
3385
                                  eBufType, 0, 1);
3386
                }
3387
            }
3388
        }
3389
    }
3390

3391
    return CE_None;
15✔
3392
}
3393

3394
/************************************************************************/
3395
/*                          RasterIOInternal()                          */
3396
/************************************************************************/
3397

3398
// nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3399
// referential.
3400
template <class WorkingDT>
3401
CPLErr VRTComplexSource::RasterIOInternal(
5,004✔
3402
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3403
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3404
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3405
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3406
    GDALDataType eWrkDataType, WorkingState &oWorkingState)
3407
{
3408
    const GDALColorTable *poColorTable = nullptr;
5,004✔
3409
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
5,004✔
3410
    const int nWordSize = GDALGetDataTypeSizeBytes(eWrkDataType);
5,004✔
3411
    assert(nWordSize != 0);
5,004✔
3412

3413
    // If no explicit <NODATA> is set, but UseMaskBand is set, and the band
3414
    // has a nodata value, then use it as if it was set as <NODATA>
3415
    int bNoDataSet = (m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0;
5,004✔
3416
    double dfNoDataValue = GetAdjustedNoDataValue();
5,004✔
3417

3418
    if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
5,111✔
3419
        poSourceBand->GetMaskFlags() == GMF_NODATA)
107✔
3420
    {
3421
        dfNoDataValue = poSourceBand->GetNoDataValue(&bNoDataSet);
×
3422
    }
3423

3424
    const bool bNoDataSetIsNan = bNoDataSet && std::isnan(dfNoDataValue);
5,004✔
3425
    const bool bNoDataSetAndNotNan =
5,004✔
3426
        bNoDataSet && !std::isnan(dfNoDataValue) &&
5,041✔
3427
        GDALIsValueInRange<WorkingDT>(dfNoDataValue);
37✔
3428
    const auto fWorkingDataTypeNoData = static_cast<WorkingDT>(dfNoDataValue);
5,004✔
3429

3430
    const GByte *pabyMask = nullptr;
5,004✔
3431
    const WorkingDT *pafData = nullptr;
5,004✔
3432
    if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0 &&
5,004✔
3433
        m_dfScaleRatio == 0 && bNoDataSet == FALSE &&
4,449✔
3434
        (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) == 0)
4,051✔
3435
    {
3436
        /* ------------------------------------------------------------------ */
3437
        /*      Optimization when writing a constant value */
3438
        /*      (used by the -addalpha option of gdalbuildvrt) */
3439
        /* ------------------------------------------------------------------ */
3440
        // Already set to NULL when defined.
3441
        // pafData = NULL;
3442
    }
3443
    else
3444
    {
3445
        /* ---------------------------------------------------------------- */
3446
        /*      Read into a temporary buffer.                               */
3447
        /* ---------------------------------------------------------------- */
3448
        const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
953✔
3449
        try
3450
        {
3451
            // Cannot overflow since pData should at least have that number of
3452
            // elements
3453
            if (nPixelCount >
953✔
3454
                static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
953✔
3455
                    static_cast<size_t>(nWordSize))
953✔
3456
            {
3457
                CPLError(CE_Failure, CPLE_OutOfMemory,
×
3458
                         "Too large temporary buffer");
3459
                return CE_Failure;
×
3460
            }
3461
            oWorkingState.m_abyWrkBuffer.resize(nWordSize * nPixelCount);
953✔
3462
        }
3463
        catch (const std::bad_alloc &e)
×
3464
        {
3465
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
3466
            return CE_Failure;
×
3467
        }
3468
        pafData = reinterpret_cast<const WorkingDT *>(
3469
            oWorkingState.m_abyWrkBuffer.data());
953✔
3470

3471
        const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
953✔
3472
        if (!m_osResampling.empty())
953✔
3473
        {
3474
            psExtraArg->eResampleAlg =
28✔
3475
                GDALRasterIOGetResampleAlg(m_osResampling);
28✔
3476
        }
3477

3478
        const CPLErr eErr = poSourceBand->RasterIO(
953✔
3479
            GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3480
            oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize,
953✔
3481
            eWrkDataType, nWordSize,
3482
            nWordSize * static_cast<GSpacing>(nOutXSize), psExtraArg);
953✔
3483
        if (!m_osResampling.empty())
953✔
3484
            psExtraArg->eResampleAlg = eResampleAlgBack;
28✔
3485

3486
        if (eErr != CE_None)
953✔
3487
        {
3488
            return eErr;
×
3489
        }
3490

3491
        // Allocate and read mask band if needed
3492
        if (!bNoDataSet &&
2,813✔
3493
            (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
1,060✔
3494
            (poSourceBand->GetMaskFlags() != GMF_ALL_VALID ||
107✔
3495
             poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
52✔
3496
             GetMaskBandMainBand() != nullptr))
32✔
3497
        {
3498
            try
3499
            {
3500
                oWorkingState.m_abyWrkBufferMask.resize(nPixelCount);
107✔
3501
            }
3502
            catch (const std::exception &)
×
3503
            {
3504
                CPLError(CE_Failure, CPLE_OutOfMemory,
×
3505
                         "Out of memory when allocating mask buffer");
3506
                return CE_Failure;
×
3507
            }
3508
            pabyMask = reinterpret_cast<const GByte *>(
3509
                oWorkingState.m_abyWrkBufferMask.data());
107✔
3510
            auto poMaskBand =
52✔
3511
                (poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
107✔
3512
                 GetMaskBandMainBand() != nullptr)
87✔
3513
                    ? poSourceBand
3514
                    : poSourceBand->GetMaskBand();
55✔
3515
            if (poMaskBand->RasterIO(
107✔
3516
                    GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3517
                    oWorkingState.m_abyWrkBufferMask.data(), nOutXSize,
107✔
3518
                    nOutYSize, GDT_Byte, 1, static_cast<GSpacing>(nOutXSize),
3519
                    psExtraArg) != CE_None)
107✔
3520
            {
3521
                return CE_Failure;
×
3522
            }
3523
        }
3524

3525
        if (m_nColorTableComponent != 0)
953✔
3526
        {
3527
            poColorTable = poSourceBand->GetColorTable();
274✔
3528
            if (poColorTable == nullptr)
274✔
3529
            {
3530
                CPLError(CE_Failure, CPLE_AppDefined,
×
3531
                         "Source band has no color table.");
3532
                return CE_Failure;
×
3533
            }
3534
        }
3535
    }
3536

3537
    /* -------------------------------------------------------------------- */
3538
    /*      Selectively copy into output buffer with nodata masking,        */
3539
    /*      and/or scaling.                                                 */
3540
    /* -------------------------------------------------------------------- */
3541

3542
    const bool bTwoStepDataTypeConversion =
5,004✔
3543
        CPL_TO_BOOL(
5,004✔
3544
            GDALDataTypeIsConversionLossy(eWrkDataType, eVRTBandDataType)) &&
9,932✔
3545
        !CPL_TO_BOOL(GDALDataTypeIsConversionLossy(eVRTBandDataType, eBufType));
4,928✔
3546

3547
    size_t idxBuffer = 0;
5,004✔
3548
    for (int iY = 0; iY < nOutYSize; iY++)
78,379✔
3549
    {
3550
        GByte *pDstLocation = static_cast<GByte *>(pData) +
73,375✔
3551
                              static_cast<GPtrDiff_t>(nLineSpace) * iY;
73,375✔
3552

3553
        for (int iX = 0; iX < nOutXSize;
12,247,864✔
3554
             iX++, pDstLocation += nPixelSpace, idxBuffer++)
12,174,559✔
3555
        {
3556
            WorkingDT afResult[2];
3557
            if (pafData && !bIsComplex)
12,174,559✔
3558
            {
3559
                WorkingDT fResult = pafData[idxBuffer];
6,539,866✔
3560
                if (bNoDataSetIsNan && std::isnan(fResult))
6,539,866✔
3561
                    continue;
1,188,642✔
3562
                if (bNoDataSetAndNotNan &&
6,541,126✔
3563
                    ARE_REAL_EQUAL(fResult, fWorkingDataTypeNoData))
1,284✔
3564
                    continue;
269✔
3565
                if (pabyMask && pabyMask[idxBuffer] == 0)
6,539,574✔
3566
                    continue;
1,188,350✔
3567

3568
                if (poColorTable)
5,351,224✔
3569
                {
3570
                    const GDALColorEntry *poEntry =
3571
                        poColorTable->GetColorEntry(static_cast<int>(fResult));
1,933,900✔
3572
                    if (poEntry)
1,933,900✔
3573
                    {
3574
                        if (m_nColorTableComponent == 1)
1,933,900✔
3575
                            fResult = poEntry->c1;
685,985✔
3576
                        else if (m_nColorTableComponent == 2)
1,247,920✔
3577
                            fResult = poEntry->c2;
531,408✔
3578
                        else if (m_nColorTableComponent == 3)
716,509✔
3579
                            fResult = poEntry->c3;
531,408✔
3580
                        else if (m_nColorTableComponent == 4)
185,101✔
3581
                            fResult = poEntry->c4;
185,101✔
3582
                    }
3583
                    else
3584
                    {
3585
                        CPLErrorOnce(CE_Failure, CPLE_AppDefined,
×
3586
                                     "No entry %d.", static_cast<int>(fResult));
3587
                        continue;
×
3588
                    }
3589
                }
3590

3591
                if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
5,351,224✔
3592
                {
3593
                    fResult = static_cast<WorkingDT>(fResult * m_dfScaleRatio +
1,649,622✔
3594
                                                     m_dfScaleOff);
1,649,622✔
3595
                }
3596
                else if ((m_nProcessingFlags &
3,701,602✔
3597
                          PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
3598
                {
3599
                    if (!m_bSrcMinMaxDefined)
3,579✔
3600
                    {
3601
                        int bSuccessMin = FALSE;
1✔
3602
                        int bSuccessMax = FALSE;
1✔
3603
                        double adfMinMax[2] = {
2✔
3604
                            poSourceBand->GetMinimum(&bSuccessMin),
1✔
3605
                            poSourceBand->GetMaximum(&bSuccessMax)};
1✔
3606
                        if ((bSuccessMin && bSuccessMax) ||
2✔
3607
                            poSourceBand->ComputeRasterMinMax(
1✔
3608
                                TRUE, adfMinMax) == CE_None)
3609
                        {
3610
                            m_dfSrcMin = adfMinMax[0];
1✔
3611
                            m_dfSrcMax = adfMinMax[1];
1✔
3612
                            m_bSrcMinMaxDefined = true;
1✔
3613
                        }
3614
                        else
3615
                        {
3616
                            CPLError(CE_Failure, CPLE_AppDefined,
×
3617
                                     "Cannot determine source min/max value");
3618
                            return CE_Failure;
×
3619
                        }
3620
                    }
3621

3622
                    double dfPowVal = (m_dfSrcMin == m_dfSrcMax)
7,158✔
3623
                                          ? 0
3,579✔
3624
                                          : (fResult - m_dfSrcMin) /
3,579✔
3625
                                                (m_dfSrcMax - m_dfSrcMin);
3,579✔
3626
                    if (m_bClip)
3,579✔
3627
                    {
3628
                        if (dfPowVal < 0.0)
3,574✔
3629
                            dfPowVal = 0.0;
1✔
3630
                        else if (dfPowVal > 1.0)
3,573✔
3631
                            dfPowVal = 1.0;
700✔
3632
                    }
3633
                    fResult =
3,579✔
3634
                        static_cast<WorkingDT>((m_dfDstMax - m_dfDstMin) *
3,579✔
3635
                                                   pow(dfPowVal, m_dfExponent) +
3,579✔
3636
                                               m_dfDstMin);
3,579✔
3637
                }
3638

3639
                if (!m_adfLUTInputs.empty())
5,351,224✔
3640
                    fResult = static_cast<WorkingDT>(LookupValue(fResult));
817,592✔
3641

3642
                if (m_nMaxValue != 0 && fResult > m_nMaxValue)
5,351,224✔
3643
                    fResult = static_cast<WorkingDT>(m_nMaxValue);
800✔
3644

3645
                afResult[0] = fResult;
5,351,224✔
3646
                afResult[1] = 0;
5,351,224✔
3647
            }
3648
            else if (pafData && bIsComplex)
5,634,663✔
3649
            {
3650
                afResult[0] = pafData[2 * idxBuffer];
1,018✔
3651
                afResult[1] = pafData[2 * idxBuffer + 1];
1,018✔
3652

3653
                // Do not use color table.
3654
                if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
1,018✔
3655
                {
3656
                    afResult[0] = static_cast<WorkingDT>(
4✔
3657
                        afResult[0] * m_dfScaleRatio + m_dfScaleOff);
4✔
3658
                    afResult[1] = static_cast<WorkingDT>(
4✔
3659
                        afResult[1] * m_dfScaleRatio + m_dfScaleOff);
4✔
3660
                }
3661

3662
                /* Do not use LUT */
3663
            }
3664
            else
3665
            {
3666
                afResult[0] = static_cast<WorkingDT>(m_dfScaleOff);
5,633,642✔
3667
                afResult[1] = 0;
5,633,642✔
3668

3669
                if (!m_adfLUTInputs.empty())
5,633,642✔
3670
                    afResult[0] =
×
3671
                        static_cast<WorkingDT>(LookupValue(afResult[0]));
×
3672

3673
                if (m_nMaxValue != 0 && afResult[0] > m_nMaxValue)
5,633,642✔
3674
                    afResult[0] = static_cast<WorkingDT>(m_nMaxValue);
×
3675
            }
3676

3677
            if (eBufType == GDT_Byte && eVRTBandDataType == GDT_Byte)
10,985,857✔
3678
            {
3679
                *pDstLocation = static_cast<GByte>(std::min(
4,308,910✔
3680
                    255.0f,
8,617,820✔
3681
                    std::max(0.0f, static_cast<float>(afResult[0]) + 0.5f)));
4,308,910✔
3682
            }
3683
            else if (!bTwoStepDataTypeConversion)
6,676,977✔
3684
            {
3685
                CopyWord<WorkingDT>(afResult, eWrkDataType, pDstLocation,
14,036✔
3686
                                    eBufType);
3687
            }
3688
            else if (eVRTBandDataType == GDT_Float32 && eBufType == GDT_Float64)
6,662,938✔
3689
            {
3690
                // Particular case of the below 2-step conversion.
3691
                // Helps a bit for some geolocation based warping with Sentinel3
3692
                // data where the longitude/latitude arrays are Int32 bands,
3693
                // rescaled in VRT as Float32 and requested as Float64
3694
                float fVal;
3695
                GDALCopyWord(afResult[0], fVal);
20✔
3696
                *reinterpret_cast<double *>(pDstLocation) = fVal;
20✔
3697
            }
3698
            else
3699
            {
3700
                GByte abyTemp[2 * sizeof(double)];
3701
                // Convert first to the VRTRasterBand data type
3702
                // to get its clamping, before outputting to buffer data type
3703
                CopyWord<WorkingDT>(afResult, eWrkDataType, abyTemp,
6,662,918✔
3704
                                    eVRTBandDataType);
3705
                GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
6,662,918✔
3706
                              eBufType, 0, 1);
3707
            }
3708
        }
3709
    }
3710

3711
    return CE_None;
5,004✔
3712
}
3713

3714
// Explicitly instantiate template method, as it is used in another file.
3715
template CPLErr VRTComplexSource::RasterIOInternal<float>(
3716
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3717
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3718
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3719
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3720
    GDALDataType eWrkDataType, WorkingState &oWorkingState);
3721

3722
/************************************************************************/
3723
/*                        AreValuesUnchanged()                          */
3724
/************************************************************************/
3725

3726
bool VRTComplexSource::AreValuesUnchanged() const
9✔
3727
{
3728
    return m_dfScaleOff == 0.0 && m_dfScaleRatio == 1.0 &&
10✔
3729
           m_adfLUTInputs.empty() && m_nColorTableComponent == 0 &&
24✔
3730
           (m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) == 0;
14✔
3731
}
3732

3733
/************************************************************************/
3734
/*                             GetMinimum()                             */
3735
/************************************************************************/
3736

3737
double VRTComplexSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
2✔
3738
{
3739
    if (AreValuesUnchanged())
2✔
3740
    {
3741
        return VRTSimpleSource::GetMinimum(nXSize, nYSize, pbSuccess);
1✔
3742
    }
3743

3744
    *pbSuccess = FALSE;
1✔
3745
    return 0;
1✔
3746
}
3747

3748
/************************************************************************/
3749
/*                             GetMaximum()                             */
3750
/************************************************************************/
3751

3752
double VRTComplexSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
2✔
3753
{
3754
    if (AreValuesUnchanged())
2✔
3755
    {
3756
        return VRTSimpleSource::GetMaximum(nXSize, nYSize, pbSuccess);
1✔
3757
    }
3758

3759
    *pbSuccess = FALSE;
1✔
3760
    return 0;
1✔
3761
}
3762

3763
/************************************************************************/
3764
/*                            GetHistogram()                            */
3765
/************************************************************************/
3766

3767
CPLErr VRTComplexSource::GetHistogram(int nXSize, int nYSize, double dfMin,
×
3768
                                      double dfMax, int nBuckets,
3769
                                      GUIntBig *panHistogram,
3770
                                      int bIncludeOutOfRange, int bApproxOK,
3771
                                      GDALProgressFunc pfnProgress,
3772
                                      void *pProgressData)
3773
{
3774
    if (AreValuesUnchanged())
×
3775
    {
3776
        return VRTSimpleSource::GetHistogram(
×
3777
            nXSize, nYSize, dfMin, dfMax, nBuckets, panHistogram,
3778
            bIncludeOutOfRange, bApproxOK, pfnProgress, pProgressData);
×
3779
    }
3780

3781
    return CE_Failure;
×
3782
}
3783

3784
/************************************************************************/
3785
/* ==================================================================== */
3786
/*                          VRTFuncSource                               */
3787
/* ==================================================================== */
3788
/************************************************************************/
3789

3790
/************************************************************************/
3791
/*                           VRTFuncSource()                            */
3792
/************************************************************************/
3793

3794
VRTFuncSource::VRTFuncSource()
12✔
3795
    : pfnReadFunc(nullptr), pCBData(nullptr), eType(GDT_Byte),
3796
      fNoDataValue(static_cast<float>(VRT_NODATA_UNSET))
12✔
3797
{
3798
}
12✔
3799

3800
/************************************************************************/
3801
/*                           ~VRTFuncSource()                           */
3802
/************************************************************************/
3803

3804
VRTFuncSource::~VRTFuncSource()
24✔
3805
{
3806
}
24✔
3807

3808
/************************************************************************/
3809
/*                            GetType()                                 */
3810
/************************************************************************/
3811

3812
const char *VRTFuncSource::GetType() const
×
3813
{
3814
    static const char *TYPE = "FuncSource";
3815
    return TYPE;
×
3816
}
3817

3818
/************************************************************************/
3819
/*                           SerializeToXML()                           */
3820
/************************************************************************/
3821

3822
CPLXMLNode *VRTFuncSource::SerializeToXML(CPL_UNUSED const char *pszVRTPath)
×
3823
{
3824
    return nullptr;
×
3825
}
3826

3827
/************************************************************************/
3828
/*                              RasterIO()                              */
3829
/************************************************************************/
3830

3831
CPLErr VRTFuncSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
10✔
3832
                               int nYOff, int nXSize, int nYSize, void *pData,
3833
                               int nBufXSize, int nBufYSize,
3834
                               GDALDataType eBufType, GSpacing nPixelSpace,
3835
                               GSpacing nLineSpace,
3836
                               GDALRasterIOExtraArg * /* psExtraArg */,
3837
                               WorkingState & /* oWorkingState */)
3838
{
3839
    if (nPixelSpace == GDALGetDataTypeSizeBytes(eBufType) &&
10✔
3840
        nLineSpace == nPixelSpace * nXSize && nBufXSize == nXSize &&
10✔
3841
        nBufYSize == nYSize && eBufType == eType)
20✔
3842
    {
3843
        return pfnReadFunc(pCBData, nXOff, nYOff, nXSize, nYSize, pData);
10✔
3844
    }
3845
    else
3846
    {
3847
        CPLError(CE_Failure, CPLE_AppDefined,
×
3848
                 "VRTFuncSource::RasterIO() - Irregular request.");
3849
        CPLDebug("VRT", "Irregular request: %d,%d  %d,%d, %d,%d %d,%d %d,%d",
×
3850
                 static_cast<int>(nPixelSpace),
3851
                 GDALGetDataTypeSizeBytes(eBufType),
3852
                 static_cast<int>(nLineSpace),
3853
                 static_cast<int>(nPixelSpace) * nXSize, nBufXSize, nXSize,
3854
                 nBufYSize, nYSize, static_cast<int>(eBufType),
3855
                 static_cast<int>(eType));
×
3856

3857
        return CE_Failure;
×
3858
    }
3859
}
3860

3861
/************************************************************************/
3862
/*                             GetMinimum()                             */
3863
/************************************************************************/
3864

3865
double VRTFuncSource::GetMinimum(int /* nXSize */, int /* nYSize */,
×
3866
                                 int *pbSuccess)
3867
{
3868
    *pbSuccess = FALSE;
×
3869
    return 0;
×
3870
}
3871

3872
/************************************************************************/
3873
/*                             GetMaximum()                             */
3874
/************************************************************************/
3875

3876
double VRTFuncSource::GetMaximum(int /* nXSize */, int /* nYSize */,
×
3877
                                 int *pbSuccess)
3878
{
3879
    *pbSuccess = FALSE;
×
3880
    return 0;
×
3881
}
3882

3883
/************************************************************************/
3884
/*                            GetHistogram()                            */
3885
/************************************************************************/
3886

3887
CPLErr VRTFuncSource::GetHistogram(
×
3888
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
3889
    int /* nBuckets */, GUIntBig * /* panHistogram */,
3890
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
3891
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
3892
{
3893
    return CE_Failure;
×
3894
}
3895

3896
/************************************************************************/
3897
/*                        VRTParseCoreSources()                         */
3898
/************************************************************************/
3899

3900
VRTSource *VRTParseCoreSources(const CPLXMLNode *psChild,
104,106✔
3901
                               const char *pszVRTPath,
3902
                               VRTMapSharedResources &oMapSharedSources)
3903

3904
{
3905
    VRTSource *poSource = nullptr;
104,106✔
3906

3907
    if (EQUAL(psChild->pszValue, VRTAveragedSource::GetTypeStatic()) ||
208,205✔
3908
        (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()) &&
104,099✔
3909
         STARTS_WITH_CI(CPLGetXMLValue(psChild, "Resampling", "Nearest"),
103,846✔
3910
                        "Aver")))
3911
    {
3912
        poSource = new VRTAveragedSource();
16✔
3913
    }
3914
    else if (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()))
104,090✔
3915
    {
3916
        poSource = new VRTSimpleSource();
103,837✔
3917
    }
3918
    else if (EQUAL(psChild->pszValue, VRTComplexSource::GetTypeStatic()))
253✔
3919
    {
3920
        poSource = new VRTComplexSource();
245✔
3921
    }
3922
    else if (EQUAL(psChild->pszValue, VRTNoDataFromMaskSource::GetTypeStatic()))
8✔
3923
    {
3924
        poSource = new VRTNoDataFromMaskSource();
8✔
3925
    }
3926
    else
3927
    {
3928
        CPLError(CE_Failure, CPLE_AppDefined,
×
3929
                 "VRTParseCoreSources() - Unknown source : %s",
3930
                 psChild->pszValue);
×
3931
        return nullptr;
×
3932
    }
3933

3934
    if (poSource->XMLInit(psChild, pszVRTPath, oMapSharedSources) == CE_None)
104,106✔
3935
        return poSource;
104,103✔
3936

3937
    delete poSource;
3✔
3938
    return nullptr;
3✔
3939
}
3940

3941
/*! @endcond */
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc