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

OSGeo / gdal / 12706066811

10 Jan 2025 08:38AM UTC coverage: 70.084% (-2.5%) from 72.549%
12706066811

Pull #11629

github

web-flow
Merge 9418dc48f into 0df468c56
Pull Request #11629: add uv documentation for python package

563296 of 803749 relevant lines covered (70.08%)

223434.74 hits per line

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

86.0
/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
// See #5459
46
#ifdef isnan
47
#define HAS_ISNAN_MACRO
48
#endif
49
#include <algorithm>
50
#if defined(HAS_ISNAN_MACRO) && !defined(isnan)
51
#define isnan std::isnan
52
#endif
53

54
/************************************************************************/
55
/* ==================================================================== */
56
/*                             VRTSource                                */
57
/* ==================================================================== */
58
/************************************************************************/
59

60
VRTSource::~VRTSource()
13,269✔
61
{
62
}
13,269✔
63

64
/************************************************************************/
65
/*                             GetFileList()                            */
66
/************************************************************************/
67

68
void VRTSource::GetFileList(char *** /* ppapszFileList */, int * /* pnSize */,
×
69
                            int * /* pnMaxSize */, CPLHashSet * /* hSetFiles */)
70
{
71
}
×
72

73
/************************************************************************/
74
/* ==================================================================== */
75
/*                          VRTSimpleSource                             */
76
/* ==================================================================== */
77
/************************************************************************/
78

79
/************************************************************************/
80
/*                          VRTSimpleSource()                           */
81
/************************************************************************/
82

83
VRTSimpleSource::VRTSimpleSource() = default;
84

85
/************************************************************************/
86
/*                          VRTSimpleSource()                           */
87
/************************************************************************/
88

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

133
/************************************************************************/
134
/*                          ~VRTSimpleSource()                          */
135
/************************************************************************/
136

137
VRTSimpleSource::~VRTSimpleSource()
27,825✔
138

139
{
140
    if (!m_bDropRefOnSrcBand)
13,225✔
141
        return;
396✔
142

143
    if (m_poMaskBandMainBand != nullptr)
12,829✔
144
    {
145
        if (m_poMaskBandMainBand->GetDataset() != nullptr)
51✔
146
        {
147
            m_poMaskBandMainBand->GetDataset()->ReleaseRef();
51✔
148
        }
149
    }
150
    else if (m_poRasterBand != nullptr &&
23,014✔
151
             m_poRasterBand->GetDataset() != nullptr)
10,236✔
152
    {
153
        m_poRasterBand->GetDataset()->ReleaseRef();
10,236✔
154
    }
155
}
25,847✔
156

157
/************************************************************************/
158
/*                           GetTypeStatic()                            */
159
/************************************************************************/
160

161
const char *VRTSimpleSource::GetTypeStatic()
35,259✔
162
{
163
    static const char *TYPE = "SimpleSource";
164
    return TYPE;
35,259✔
165
}
166

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

171
const char *VRTSimpleSource::GetType() const
16,075✔
172
{
173
    return GetTypeStatic();
16,075✔
174
}
175

176
/************************************************************************/
177
/*                           FlushCache()                               */
178
/************************************************************************/
179

180
CPLErr VRTSimpleSource::FlushCache(bool bAtClosing)
13,284✔
181

182
{
183
    if (m_poMaskBandMainBand != nullptr)
13,284✔
184
    {
185
        return m_poMaskBandMainBand->FlushCache(bAtClosing);
5✔
186
    }
187
    else if (m_poRasterBand != nullptr)
13,279✔
188
    {
189
        return m_poRasterBand->FlushCache(bAtClosing);
10,726✔
190
    }
191
    return CE_None;
2,553✔
192
}
193

194
/************************************************************************/
195
/*                    UnsetPreservedRelativeFilenames()                 */
196
/************************************************************************/
197

198
void VRTSimpleSource::UnsetPreservedRelativeFilenames()
5✔
199
{
200
    if (!STARTS_WITH(m_osSourceFileNameOri.c_str(), "http://") &&
9✔
201
        !STARTS_WITH(m_osSourceFileNameOri.c_str(), "https://"))
4✔
202
    {
203
        m_bRelativeToVRTOri = -1;
4✔
204
        m_osSourceFileNameOri = "";
4✔
205
    }
206
}
5✔
207

208
/************************************************************************/
209
/*                             SetSrcBand()                             */
210
/************************************************************************/
211

212
void VRTSimpleSource::SetSrcBand(const char *pszFilename, int nBand)
446✔
213

214
{
215
    m_nBand = nBand;
446✔
216
    m_osSrcDSName = pszFilename;
446✔
217
}
446✔
218

219
/************************************************************************/
220
/*                             SetSrcBand()                             */
221
/************************************************************************/
222

223
void VRTSimpleSource::SetSrcBand(GDALRasterBand *poNewSrcBand)
9,250✔
224

225
{
226
    m_poRasterBand = poNewSrcBand;
9,250✔
227
    m_nBand = m_poRasterBand->GetBand();
9,250✔
228
    auto poDS = poNewSrcBand->GetDataset();
9,250✔
229
    if (poDS != nullptr)
9,250✔
230
    {
231
        m_osSrcDSName = poDS->GetDescription();
9,250✔
232
        m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
9,250✔
233
        m_aosOpenOptionsOri = m_aosOpenOptions;
9,250✔
234
    }
235
}
9,250✔
236

237
/************************************************************************/
238
/*                          SetSrcMaskBand()                            */
239
/************************************************************************/
240

241
// poSrcBand is not the mask band, but the band from which the mask band is
242
// taken.
243
void VRTSimpleSource::SetSrcMaskBand(GDALRasterBand *poNewSrcBand)
32✔
244

245
{
246
    m_poRasterBand = poNewSrcBand->GetMaskBand();
32✔
247
    m_poMaskBandMainBand = poNewSrcBand;
32✔
248
    m_nBand = poNewSrcBand->GetBand();
32✔
249
    auto poDS = poNewSrcBand->GetDataset();
32✔
250
    if (poDS != nullptr)
32✔
251
    {
252
        m_osSrcDSName = poDS->GetDescription();
32✔
253
        m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
32✔
254
        m_aosOpenOptionsOri = m_aosOpenOptions;
32✔
255
    }
256
    m_bGetMaskBand = true;
32✔
257
}
32✔
258

259
/************************************************************************/
260
/*                         RoundIfCloseToInt()                          */
261
/************************************************************************/
262

263
static double RoundIfCloseToInt(double dfValue)
298,144✔
264
{
265
    double dfClosestInt = floor(dfValue + 0.5);
298,144✔
266
    return (fabs(dfValue - dfClosestInt) < 1e-3) ? dfClosestInt : dfValue;
298,144✔
267
}
268

269
/************************************************************************/
270
/*                            SetSrcWindow()                            */
271
/************************************************************************/
272

273
void VRTSimpleSource::SetSrcWindow(double dfNewXOff, double dfNewYOff,
12,627✔
274
                                   double dfNewXSize, double dfNewYSize)
275

276
{
277
    m_dfSrcXOff = RoundIfCloseToInt(dfNewXOff);
12,627✔
278
    m_dfSrcYOff = RoundIfCloseToInt(dfNewYOff);
12,627✔
279
    m_dfSrcXSize = RoundIfCloseToInt(dfNewXSize);
12,627✔
280
    m_dfSrcYSize = RoundIfCloseToInt(dfNewYSize);
12,627✔
281
}
12,627✔
282

283
/************************************************************************/
284
/*                            SetDstWindow()                            */
285
/************************************************************************/
286

287
void VRTSimpleSource::SetDstWindow(double dfNewXOff, double dfNewYOff,
12,626✔
288
                                   double dfNewXSize, double dfNewYSize)
289

290
{
291
    m_dfDstXOff = RoundIfCloseToInt(dfNewXOff);
12,626✔
292
    m_dfDstYOff = RoundIfCloseToInt(dfNewYOff);
12,626✔
293
    m_dfDstXSize = RoundIfCloseToInt(dfNewXSize);
12,626✔
294
    m_dfDstYSize = RoundIfCloseToInt(dfNewYSize);
12,626✔
295
}
12,626✔
296

297
/************************************************************************/
298
/*                            GetDstWindow()                            */
299
/************************************************************************/
300

301
void VRTSimpleSource::GetDstWindow(double &dfDstXOff, double &dfDstYOff,
517✔
302
                                   double &dfDstXSize, double &dfDstYSize) const
303
{
304
    dfDstXOff = m_dfDstXOff;
517✔
305
    dfDstYOff = m_dfDstYOff;
517✔
306
    dfDstXSize = m_dfDstXSize;
517✔
307
    dfDstYSize = m_dfDstYSize;
517✔
308
}
517✔
309

310
/************************************************************************/
311
/*                        DstWindowIntersects()                         */
312
/************************************************************************/
313

314
bool VRTSimpleSource::DstWindowIntersects(double dfXOff, double dfYOff,
1,073✔
315
                                          double dfXSize, double dfYSize) const
316
{
317
    return IsDstWinSet() && m_dfDstXOff + m_dfDstXSize > dfXOff &&
2,137✔
318
           m_dfDstYOff + m_dfDstYSize > dfYOff &&
1,064✔
319
           m_dfDstXOff < dfXOff + dfXSize && m_dfDstYOff < dfYOff + dfYSize;
2,137✔
320
}
321

322
/************************************************************************/
323
/*                            IsSlowSource()                            */
324
/************************************************************************/
325

326
static bool IsSlowSource(const char *pszSrcName)
2,498✔
327
{
328
    return strstr(pszSrcName, "/vsicurl/http") != nullptr ||
4,996✔
329
           strstr(pszSrcName, "/vsicurl/ftp") != nullptr ||
4,996✔
330
           (strstr(pszSrcName, "/vsicurl?") != nullptr &&
2,498✔
331
            strstr(pszSrcName, "&url=http") != nullptr);
2,498✔
332
}
333

334
/************************************************************************/
335
/*                         AddSourceFilenameNode()                      */
336
/************************************************************************/
337

338
void VRTSimpleSource::AddSourceFilenameNode(const char *pszVRTPath,
2,530✔
339
                                            CPLXMLNode *psSrc)
340
{
341

342
    VSIStatBufL sStat;
343
    int bRelativeToVRT = FALSE;  // TODO(schwehr): Make this a bool?
2,530✔
344
    std::string osSourceFilename;
5,060✔
345

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

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

457
    CPLSetXMLValue(psSrc, "SourceFilename", osSourceFilename.c_str());
2,530✔
458

459
    CPLCreateXMLNode(CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
2,530✔
460
                                      CXT_Attribute, "relativeToVRT"),
461
                     CXT_Text, bRelativeToVRT ? "1" : "0");
2,530✔
462

463
    // Determine if we must write the shared attribute. The config option
464
    // will override the m_nExplicitSharedStatus value
465
    const char *pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
2,530✔
466
    if ((pszShared == nullptr && m_nExplicitSharedStatus == 0) ||
2,530✔
467
        (pszShared != nullptr && !CPLTestBool(pszShared)))
×
468
    {
469
        CPLCreateXMLNode(
×
470
            CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
471
                             CXT_Attribute, "shared"),
472
            CXT_Text, "0");
473
    }
474
}
2,530✔
475

476
/************************************************************************/
477
/*                           SerializeToXML()                           */
478
/************************************************************************/
479

480
CPLXMLNode *VRTSimpleSource::SerializeToXML(const char *pszVRTPath)
2,531✔
481

482
{
483
    CPLXMLNode *const psSrc =
484
        CPLCreateXMLNode(nullptr, CXT_Element, GetTypeStatic());
2,531✔
485

486
    if (!m_osResampling.empty())
2,531✔
487
    {
488
        CPLCreateXMLNode(CPLCreateXMLNode(psSrc, CXT_Attribute, "resampling"),
24✔
489
                         CXT_Text, m_osResampling.c_str());
490
    }
491

492
    if (m_bSrcDSNameFromVRT)
2,531✔
493
    {
494
        CPLAddXMLChild(psSrc, CPLParseXMLString(m_osSrcDSName.c_str()));
1✔
495
    }
496
    else
497
    {
498
        AddSourceFilenameNode(pszVRTPath, psSrc);
2,530✔
499
    }
500

501
    GDALSerializeOpenOptionsToXML(psSrc, m_aosOpenOptionsOri.List());
2,531✔
502

503
    if (m_bGetMaskBand)
2,531✔
504
        CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("mask,%d", m_nBand));
18✔
505
    else
506
        CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("%d", m_nBand));
2,513✔
507

508
    // TODO: in a later version, no longer emit SourceProperties, which
509
    // is no longer used by GDAL 3.4
510
    if (m_poRasterBand)
2,531✔
511
    {
512
        /* Write a few additional useful properties of the dataset */
513
        /* so that we can use a proxy dataset when re-opening. See XMLInit() */
514
        /* below */
515
        CPLSetXMLValue(psSrc, "SourceProperties.#RasterXSize",
2,423✔
516
                       CPLSPrintf("%d", m_poRasterBand->GetXSize()));
2,423✔
517
        CPLSetXMLValue(psSrc, "SourceProperties.#RasterYSize",
2,423✔
518
                       CPLSPrintf("%d", m_poRasterBand->GetYSize()));
2,423✔
519
        CPLSetXMLValue(
2,423✔
520
            psSrc, "SourceProperties.#DataType",
521
            GDALGetDataTypeName(m_poRasterBand->GetRasterDataType()));
2,423✔
522

523
        int nBlockXSize = 0;
2,423✔
524
        int nBlockYSize = 0;
2,423✔
525
        m_poRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
2,423✔
526

527
        CPLSetXMLValue(psSrc, "SourceProperties.#BlockXSize",
2,423✔
528
                       CPLSPrintf("%d", nBlockXSize));
529
        CPLSetXMLValue(psSrc, "SourceProperties.#BlockYSize",
2,423✔
530
                       CPLSPrintf("%d", nBlockYSize));
531
    }
532

533
    if (IsSrcWinSet())
2,531✔
534
    {
535
        CPLSetXMLValue(psSrc, "SrcRect.#xOff",
2,518✔
536
                       CPLSPrintf("%.15g", m_dfSrcXOff));
537
        CPLSetXMLValue(psSrc, "SrcRect.#yOff",
2,518✔
538
                       CPLSPrintf("%.15g", m_dfSrcYOff));
539
        CPLSetXMLValue(psSrc, "SrcRect.#xSize",
2,518✔
540
                       CPLSPrintf("%.15g", m_dfSrcXSize));
541
        CPLSetXMLValue(psSrc, "SrcRect.#ySize",
2,518✔
542
                       CPLSPrintf("%.15g", m_dfSrcYSize));
543
    }
544

545
    if (IsDstWinSet())
2,531✔
546
    {
547
        CPLSetXMLValue(psSrc, "DstRect.#xOff",
2,518✔
548
                       CPLSPrintf("%.15g", m_dfDstXOff));
549
        CPLSetXMLValue(psSrc, "DstRect.#yOff",
2,518✔
550
                       CPLSPrintf("%.15g", m_dfDstYOff));
551
        CPLSetXMLValue(psSrc, "DstRect.#xSize",
2,518✔
552
                       CPLSPrintf("%.15g", m_dfDstXSize));
553
        CPLSetXMLValue(psSrc, "DstRect.#ySize",
2,518✔
554
                       CPLSPrintf("%.15g", m_dfDstYSize));
555
    }
556

557
    return psSrc;
2,531✔
558
}
559

560
/************************************************************************/
561
/*                              XMLInit()                               */
562
/************************************************************************/
563

564
CPLErr VRTSimpleSource::XMLInit(const CPLXMLNode *psSrc, const char *pszVRTPath,
3,075✔
565
                                VRTMapSharedResources &oMapSharedSources)
566

567
{
568
    m_poMapSharedSources = &oMapSharedSources;
3,075✔
569

570
    m_osResampling = CPLGetXMLValue(psSrc, "resampling", "");
3,075✔
571

572
    /* -------------------------------------------------------------------- */
573
    /*      Prepare filename.                                               */
574
    /* -------------------------------------------------------------------- */
575
    const CPLXMLNode *psSourceFileNameNode =
576
        CPLGetXMLNode(psSrc, "SourceFilename");
3,075✔
577
    const CPLXMLNode *psSourceVRTDataset = CPLGetXMLNode(psSrc, "VRTDataset");
3,075✔
578
    const char *pszFilename =
579
        psSourceFileNameNode ? CPLGetXMLValue(psSourceFileNameNode, nullptr, "")
3,075✔
580
                             : "";
3,075✔
581

582
    if (pszFilename[0] == '\0' && !psSourceVRTDataset)
3,075✔
583
    {
584
        CPLError(CE_Warning, CPLE_AppDefined,
1✔
585
                 "Missing <SourceFilename> or <VRTDataset> element in <%s>.",
586
                 psSrc->pszValue);
1✔
587
        return CE_Failure;
1✔
588
    }
589

590
    // Backup original filename and relativeToVRT so as to be able to
591
    // serialize them identically again (#5985)
592
    m_osSourceFileNameOri = pszFilename;
3,074✔
593
    if (pszFilename[0])
3,074✔
594
    {
595
        m_bRelativeToVRTOri =
3,071✔
596
            atoi(CPLGetXMLValue(psSourceFileNameNode, "relativetoVRT", "0"));
3,071✔
597
        const char *pszShared =
598
            CPLGetXMLValue(psSourceFileNameNode, "shared", nullptr);
3,071✔
599
        if (pszShared == nullptr)
3,071✔
600
        {
601
            pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
3,069✔
602
        }
603
        if (pszShared != nullptr)
3,071✔
604
        {
605
            m_nExplicitSharedStatus = CPLTestBool(pszShared);
8✔
606
        }
607

608
        m_osSrcDSName = VRTDataset::BuildSourceFilename(
6,142✔
609
            pszFilename, pszVRTPath, CPL_TO_BOOL(m_bRelativeToVRTOri));
6,142✔
610
    }
611
    else if (psSourceVRTDataset)
3✔
612
    {
613
        CPLXMLNode sNode;
614
        sNode.eType = psSourceVRTDataset->eType;
3✔
615
        sNode.pszValue = psSourceVRTDataset->pszValue;
3✔
616
        sNode.psNext = nullptr;
3✔
617
        sNode.psChild = psSourceVRTDataset->psChild;
3✔
618
        char *pszXML = CPLSerializeXMLTree(&sNode);
3✔
619
        if (pszXML)
3✔
620
        {
621
            m_bSrcDSNameFromVRT = true;
3✔
622
            m_osSrcDSName = pszXML;
3✔
623
            CPLFree(pszXML);
3✔
624
        }
625
    }
626

627
    const char *pszSourceBand = CPLGetXMLValue(psSrc, "SourceBand", "1");
3,074✔
628
    m_bGetMaskBand = false;
3,074✔
629
    if (STARTS_WITH_CI(pszSourceBand, "mask"))
3,074✔
630
    {
631
        m_bGetMaskBand = true;
22✔
632
        if (pszSourceBand[4] == ',')
22✔
633
            m_nBand = atoi(pszSourceBand + 5);
22✔
634
        else
635
            m_nBand = 1;
×
636
    }
637
    else
638
    {
639
        m_nBand = atoi(pszSourceBand);
3,052✔
640
    }
641
    if (!GDALCheckBandCount(m_nBand, 0))
3,074✔
642
    {
643
        CPLError(CE_Warning, CPLE_AppDefined,
×
644
                 "Invalid <SourceBand> element in VRTRasterBand.");
645
        return CE_Failure;
×
646
    }
647

648
    m_aosOpenOptions = GDALDeserializeOpenOptionsFromXML(psSrc);
3,074✔
649
    m_aosOpenOptionsOri = m_aosOpenOptions;
3,074✔
650
    if (strstr(m_osSrcDSName.c_str(), "<VRTDataset") != nullptr)
3,074✔
651
        m_aosOpenOptions.SetNameValue("ROOT_PATH", pszVRTPath);
5✔
652

653
    return ParseSrcRectAndDstRect(psSrc);
3,074✔
654
}
655

656
/************************************************************************/
657
/*                        ParseSrcRectAndDstRect()                      */
658
/************************************************************************/
659

660
CPLErr VRTSimpleSource::ParseSrcRectAndDstRect(const CPLXMLNode *psSrc)
3,088✔
661
{
662
    const auto GetAttrValue = [](const CPLXMLNode *psNode,
23,204✔
663
                                 const char *pszAttrName, double dfDefaultVal)
664
    {
665
        if (const char *pszVal = CPLGetXMLValue(psNode, pszAttrName, nullptr))
23,204✔
666
            return CPLAtof(pszVal);
23,204✔
667
        else
668
            return dfDefaultVal;
×
669
    };
670

671
    /* -------------------------------------------------------------------- */
672
    /*      Set characteristics.                                            */
673
    /* -------------------------------------------------------------------- */
674
    const CPLXMLNode *const psSrcRect = CPLGetXMLNode(psSrc, "SrcRect");
3,088✔
675
    if (psSrcRect)
3,088✔
676
    {
677
        double xOff = GetAttrValue(psSrcRect, "xOff", UNINIT_WINDOW);
2,901✔
678
        double yOff = GetAttrValue(psSrcRect, "yOff", UNINIT_WINDOW);
2,901✔
679
        double xSize = GetAttrValue(psSrcRect, "xSize", UNINIT_WINDOW);
2,901✔
680
        double ySize = GetAttrValue(psSrcRect, "ySize", UNINIT_WINDOW);
2,901✔
681
        // Test written that way to catch NaN values
682
        if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
2,901✔
683
            !(yOff >= INT_MIN && yOff <= INT_MAX) ||
2,901✔
684
            !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
2,901✔
685
            !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
2,900✔
686
        {
687
            CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in SrcRect");
1✔
688
            return CE_Failure;
1✔
689
        }
690
        SetSrcWindow(xOff, yOff, xSize, ySize);
2,900✔
691
    }
692
    else
693
    {
694
        m_dfSrcXOff = UNINIT_WINDOW;
187✔
695
        m_dfSrcYOff = UNINIT_WINDOW;
187✔
696
        m_dfSrcXSize = UNINIT_WINDOW;
187✔
697
        m_dfSrcYSize = UNINIT_WINDOW;
187✔
698
    }
699

700
    const CPLXMLNode *const psDstRect = CPLGetXMLNode(psSrc, "DstRect");
3,087✔
701
    if (psDstRect)
3,087✔
702
    {
703
        double xOff = GetAttrValue(psDstRect, "xOff", UNINIT_WINDOW);
2,900✔
704
        ;
705
        double yOff = GetAttrValue(psDstRect, "yOff", UNINIT_WINDOW);
2,900✔
706
        double xSize = GetAttrValue(psDstRect, "xSize", UNINIT_WINDOW);
2,900✔
707
        ;
708
        double ySize = GetAttrValue(psDstRect, "ySize", UNINIT_WINDOW);
2,900✔
709
        // Test written that way to catch NaN values
710
        if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
2,900✔
711
            !(yOff >= INT_MIN && yOff <= INT_MAX) ||
2,900✔
712
            !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
2,900✔
713
            !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
2,900✔
714
        {
715
            CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in DstRect");
1✔
716
            return CE_Failure;
1✔
717
        }
718
        SetDstWindow(xOff, yOff, xSize, ySize);
2,899✔
719
    }
720
    else
721
    {
722
        m_dfDstXOff = UNINIT_WINDOW;
187✔
723
        m_dfDstYOff = UNINIT_WINDOW;
187✔
724
        m_dfDstXSize = UNINIT_WINDOW;
187✔
725
        m_dfDstYSize = UNINIT_WINDOW;
187✔
726
    }
727

728
    return CE_None;
3,086✔
729
}
730

731
/************************************************************************/
732
/*                             GetFileList()                            */
733
/************************************************************************/
734

735
void VRTSimpleSource::GetFileList(char ***ppapszFileList, int *pnSize,
112✔
736
                                  int *pnMaxSize, CPLHashSet *hSetFiles)
737
{
738
    if (!m_osSrcDSName.empty() && !m_bSrcDSNameFromVRT)
112✔
739
    {
740
        const char *pszFilename = m_osSrcDSName.c_str();
112✔
741

742
        /* --------------------------------------------------------------------
743
         */
744
        /*      Is it already in the list ? */
745
        /* --------------------------------------------------------------------
746
         */
747
        if (CPLHashSetLookup(hSetFiles, pszFilename) != nullptr)
112✔
748
            return;
15✔
749

750
        /* --------------------------------------------------------------------
751
         */
752
        /*      Grow array if necessary */
753
        /* --------------------------------------------------------------------
754
         */
755
        if (*pnSize + 1 >= *pnMaxSize)
97✔
756
        {
757
            *pnMaxSize = std::max(*pnSize + 2, 2 + 2 * (*pnMaxSize));
66✔
758
            *ppapszFileList = static_cast<char **>(
66✔
759
                CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
66✔
760
        }
761

762
        /* --------------------------------------------------------------------
763
         */
764
        /*      Add the string to the list */
765
        /* --------------------------------------------------------------------
766
         */
767
        (*ppapszFileList)[*pnSize] = CPLStrdup(pszFilename);
97✔
768
        (*ppapszFileList)[(*pnSize + 1)] = nullptr;
97✔
769
        CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
97✔
770

771
        (*pnSize)++;
97✔
772
    }
773
}
774

775
/************************************************************************/
776
/*                           OpenSource()                               */
777
/************************************************************************/
778

779
void VRTSimpleSource::OpenSource() const
1,204✔
780
{
781
    CPLAssert(m_poRasterBand == nullptr);
1,204✔
782

783
    /* ----------------------------------------------------------------- */
784
    /*      Create a proxy dataset                                       */
785
    /* ----------------------------------------------------------------- */
786
    GDALProxyPoolDataset *proxyDS = nullptr;
1,204✔
787
    std::string osKeyMapSharedSources;
1,204✔
788
    if (m_poMapSharedSources)
1,204✔
789
    {
790
        osKeyMapSharedSources = m_osSrcDSName;
1,157✔
791
        for (int i = 0; i < m_aosOpenOptions.size(); ++i)
1,167✔
792
        {
793
            osKeyMapSharedSources += "||";
9✔
794
            osKeyMapSharedSources += m_aosOpenOptions[i];
9✔
795
        }
796

797
        proxyDS = cpl::down_cast<GDALProxyPoolDataset *>(
1,158✔
798
            m_poMapSharedSources->Get(osKeyMapSharedSources));
1,158✔
799
    }
800

801
    if (proxyDS == nullptr)
1,205✔
802
    {
803
        int bShared = true;
1,034✔
804
        if (m_nExplicitSharedStatus != -1)
1,034✔
805
            bShared = m_nExplicitSharedStatus;
8✔
806

807
        const CPLString osUniqueHandle(CPLSPrintf("%p", m_poMapSharedSources));
1,034✔
808
        proxyDS = GDALProxyPoolDataset::Create(
1,034✔
809
            m_osSrcDSName, m_aosOpenOptions.List(), GA_ReadOnly, bShared,
810
            osUniqueHandle.c_str());
811
        if (proxyDS == nullptr)
1,034✔
812
            return;
213✔
813
    }
814
    else
815
    {
816
        proxyDS->Reference();
171✔
817
    }
818

819
    if (m_bGetMaskBand)
992✔
820
    {
821
        GDALProxyPoolRasterBand *poMaskBand =
822
            cpl::down_cast<GDALProxyPoolRasterBand *>(
15✔
823
                proxyDS->GetRasterBand(m_nBand));
15✔
824
        poMaskBand->AddSrcMaskBandDescriptionFromUnderlying();
15✔
825
    }
826

827
    /* -------------------------------------------------------------------- */
828
    /*      Get the raster band.                                            */
829
    /* -------------------------------------------------------------------- */
830

831
    m_poRasterBand = proxyDS->GetRasterBand(m_nBand);
992✔
832
    if (m_poRasterBand == nullptr || !ValidateOpenedBand(m_poRasterBand))
992✔
833
    {
834
        proxyDS->ReleaseRef();
2✔
835
        return;
2✔
836
    }
837

838
    if (m_bGetMaskBand)
990✔
839
    {
840
        m_poRasterBand = m_poRasterBand->GetMaskBand();
15✔
841
        if (m_poRasterBand == nullptr)
15✔
842
        {
843
            proxyDS->ReleaseRef();
×
844
            return;
×
845
        }
846
        m_poMaskBandMainBand = m_poRasterBand;
15✔
847
    }
848

849
    if (m_poMapSharedSources)
990✔
850
    {
851
        m_poMapSharedSources->Insert(osKeyMapSharedSources, proxyDS);
943✔
852
    }
853
}
854

855
/************************************************************************/
856
/*                         GetRasterBand()                              */
857
/************************************************************************/
858

859
GDALRasterBand *VRTSimpleSource::GetRasterBand() const
104,755✔
860
{
861
    if (m_poRasterBand == nullptr)
104,755✔
862
        OpenSource();
1,203✔
863
    return m_poRasterBand;
104,756✔
864
}
865

866
/************************************************************************/
867
/*                        GetMaskBandMainBand()                         */
868
/************************************************************************/
869

870
GDALRasterBand *VRTSimpleSource::GetMaskBandMainBand()
1,232✔
871
{
872
    if (m_poRasterBand == nullptr)
1,232✔
873
        OpenSource();
2✔
874
    return m_poMaskBandMainBand;
1,232✔
875
}
876

877
/************************************************************************/
878
/*                       IsSameExceptBandNumber()                       */
879
/************************************************************************/
880

881
bool VRTSimpleSource::IsSameExceptBandNumber(
971✔
882
    const VRTSimpleSource *poOtherSource) const
883
{
884
    return m_dfSrcXOff == poOtherSource->m_dfSrcXOff &&
1,942✔
885
           m_dfSrcYOff == poOtherSource->m_dfSrcYOff &&
971✔
886
           m_dfSrcXSize == poOtherSource->m_dfSrcXSize &&
971✔
887
           m_dfSrcYSize == poOtherSource->m_dfSrcYSize &&
971✔
888
           m_dfDstXOff == poOtherSource->m_dfDstXOff &&
971✔
889
           m_dfDstYOff == poOtherSource->m_dfDstYOff &&
971✔
890
           m_dfDstXSize == poOtherSource->m_dfDstXSize &&
971✔
891
           m_dfDstYSize == poOtherSource->m_dfDstYSize &&
971✔
892
           !m_osSrcDSName.empty() &&
2,913✔
893
           m_osSrcDSName == poOtherSource->m_osSrcDSName;
1,942✔
894
}
895

896
/************************************************************************/
897
/*                              SrcToDst()                              */
898
/*                                                                      */
899
/*      Note: this is a no-op if the both src and dst windows are unset */
900
/************************************************************************/
901

902
void VRTSimpleSource::SrcToDst(double dfX, double dfY, double &dfXOut,
6,487✔
903
                               double &dfYOut) const
904

905
{
906
    dfXOut = ((dfX - m_dfSrcXOff) / m_dfSrcXSize) * m_dfDstXSize + m_dfDstXOff;
6,487✔
907
    dfYOut = ((dfY - m_dfSrcYOff) / m_dfSrcYSize) * m_dfDstYSize + m_dfDstYOff;
6,487✔
908
}
6,487✔
909

910
/************************************************************************/
911
/*                              DstToSrc()                              */
912
/*                                                                      */
913
/*      Note: this is a no-op if the both src and dst windows are unset */
914
/************************************************************************/
915

916
void VRTSimpleSource::DstToSrc(double dfX, double dfY, double &dfXOut,
4,022,310✔
917
                               double &dfYOut) const
918

919
{
920
    dfXOut = ((dfX - m_dfDstXOff) / m_dfDstXSize) * m_dfSrcXSize + m_dfSrcXOff;
4,022,310✔
921
    dfYOut = ((dfY - m_dfDstYOff) / m_dfDstYSize) * m_dfSrcYSize + m_dfSrcYOff;
4,022,310✔
922
}
4,022,310✔
923

924
/************************************************************************/
925
/*                          GetSrcDstWindow()                           */
926
/************************************************************************/
927

928
int VRTSimpleSource::GetSrcDstWindow(
69,711✔
929
    double dfXOff, double dfYOff, double dfXSize, double dfYSize, int nBufXSize,
930
    int nBufYSize, double *pdfReqXOff, double *pdfReqYOff, double *pdfReqXSize,
931
    double *pdfReqYSize, int *pnReqXOff, int *pnReqYOff, int *pnReqXSize,
932
    int *pnReqYSize, int *pnOutXOff, int *pnOutYOff, int *pnOutXSize,
933
    int *pnOutYSize, bool &bErrorOut)
934

935
{
936
    bErrorOut = false;
69,711✔
937

938
    if (m_dfSrcXSize == 0.0 || m_dfSrcYSize == 0.0 || m_dfDstXSize == 0.0 ||
69,711✔
939
        m_dfDstYSize == 0.0)
69,711✔
940
    {
941
        return FALSE;
×
942
    }
943

944
    const bool bDstWinSet = IsDstWinSet();
69,711✔
945

946
#ifdef DEBUG
947
    const bool bSrcWinSet = IsSrcWinSet();
69,711✔
948

949
    if (bSrcWinSet != bDstWinSet)
69,710✔
950
    {
951
        return FALSE;
×
952
    }
953
#endif
954

955
    /* -------------------------------------------------------------------- */
956
    /*      If the input window completely misses the portion of the        */
957
    /*      virtual dataset provided by this source we have nothing to do.  */
958
    /* -------------------------------------------------------------------- */
959
    if (bDstWinSet)
69,710✔
960
    {
961
        if (dfXOff >= m_dfDstXOff + m_dfDstXSize ||
69,423✔
962
            dfYOff >= m_dfDstYOff + m_dfDstYSize ||
58,995✔
963
            dfXOff + dfXSize <= m_dfDstXOff || dfYOff + dfYSize <= m_dfDstYOff)
58,459✔
964
            return FALSE;
20,311✔
965
    }
966

967
    /* -------------------------------------------------------------------- */
968
    /*      This request window corresponds to the whole output buffer.     */
969
    /* -------------------------------------------------------------------- */
970
    *pnOutXOff = 0;
49,399✔
971
    *pnOutYOff = 0;
49,399✔
972
    *pnOutXSize = nBufXSize;
49,399✔
973
    *pnOutYSize = nBufYSize;
49,399✔
974

975
    /* -------------------------------------------------------------------- */
976
    /*      If the input window extents outside the portion of the on       */
977
    /*      the virtual file that this source can set, then clip down       */
978
    /*      the requested window.                                           */
979
    /* -------------------------------------------------------------------- */
980
    bool bModifiedX = false;
49,399✔
981
    bool bModifiedY = false;
49,399✔
982
    double dfRXOff = dfXOff;
49,399✔
983
    double dfRYOff = dfYOff;
49,399✔
984
    double dfRXSize = dfXSize;
49,399✔
985
    double dfRYSize = dfYSize;
49,399✔
986

987
    if (bDstWinSet)
49,399✔
988
    {
989
        if (dfRXOff < m_dfDstXOff)
49,112✔
990
        {
991
            dfRXSize = dfRXSize + dfRXOff - m_dfDstXOff;
1,857✔
992
            dfRXOff = m_dfDstXOff;
1,857✔
993
            bModifiedX = true;
1,857✔
994
        }
995

996
        if (dfRYOff < m_dfDstYOff)
49,112✔
997
        {
998
            dfRYSize = dfRYSize + dfRYOff - m_dfDstYOff;
164✔
999
            dfRYOff = m_dfDstYOff;
164✔
1000
            bModifiedY = true;
164✔
1001
        }
1002

1003
        if (dfRXOff + dfRXSize > m_dfDstXOff + m_dfDstXSize)
49,112✔
1004
        {
1005
            dfRXSize = m_dfDstXOff + m_dfDstXSize - dfRXOff;
1,930✔
1006
            bModifiedX = true;
1,930✔
1007
        }
1008

1009
        if (dfRYOff + dfRYSize > m_dfDstYOff + m_dfDstYSize)
49,112✔
1010
        {
1011
            dfRYSize = m_dfDstYOff + m_dfDstYSize - dfRYOff;
256✔
1012
            bModifiedY = true;
256✔
1013
        }
1014
    }
1015

1016
    /* -------------------------------------------------------------------- */
1017
    /*      Translate requested region in virtual file into the source      */
1018
    /*      band coordinates.                                               */
1019
    /* -------------------------------------------------------------------- */
1020
    const double dfScaleX = m_dfSrcXSize / m_dfDstXSize;
49,399✔
1021
    const double dfScaleY = m_dfSrcYSize / m_dfDstYSize;
49,399✔
1022

1023
    *pdfReqXOff = (dfRXOff - m_dfDstXOff) * dfScaleX + m_dfSrcXOff;
49,399✔
1024
    *pdfReqYOff = (dfRYOff - m_dfDstYOff) * dfScaleY + m_dfSrcYOff;
49,399✔
1025
    *pdfReqXSize = dfRXSize * dfScaleX;
49,399✔
1026
    *pdfReqYSize = dfRYSize * dfScaleY;
49,399✔
1027

1028
    if (!std::isfinite(*pdfReqXOff) || !std::isfinite(*pdfReqYOff) ||
98,798✔
1029
        !std::isfinite(*pdfReqXSize) || !std::isfinite(*pdfReqYSize) ||
49,398✔
1030
        *pdfReqXOff > INT_MAX || *pdfReqYOff > INT_MAX || *pdfReqXSize < 0 ||
148,197✔
1031
        *pdfReqYSize < 0)
49,399✔
1032
    {
1033
        return FALSE;
×
1034
    }
1035

1036
    /* -------------------------------------------------------------------- */
1037
    /*      Clamp within the bounds of the available source data.           */
1038
    /* -------------------------------------------------------------------- */
1039
    if (*pdfReqXOff < 0)
49,399✔
1040
    {
1041
        *pdfReqXSize += *pdfReqXOff;
6✔
1042
        *pdfReqXOff = 0;
6✔
1043
        bModifiedX = true;
6✔
1044
    }
1045
    if (*pdfReqYOff < 0)
49,399✔
1046
    {
1047
        *pdfReqYSize += *pdfReqYOff;
6✔
1048
        *pdfReqYOff = 0;
6✔
1049
        bModifiedY = true;
6✔
1050
    }
1051

1052
    *pnReqXOff = static_cast<int>(floor(*pdfReqXOff));
49,399✔
1053
    *pnReqYOff = static_cast<int>(floor(*pdfReqYOff));
49,399✔
1054

1055
    constexpr double EPS = 1e-3;
49,399✔
1056
    constexpr double ONE_MINUS_EPS = 1.0 - EPS;
49,399✔
1057
    if (*pdfReqXOff - *pnReqXOff > ONE_MINUS_EPS)
49,399✔
1058
    {
1059
        (*pnReqXOff)++;
2✔
1060
        *pdfReqXOff = *pnReqXOff;
2✔
1061
    }
1062
    if (*pdfReqYOff - *pnReqYOff > ONE_MINUS_EPS)
49,399✔
1063
    {
1064
        (*pnReqYOff)++;
18✔
1065
        *pdfReqYOff = *pnReqYOff;
18✔
1066
    }
1067

1068
    if (*pdfReqXSize > INT_MAX)
49,399✔
1069
        *pnReqXSize = INT_MAX;
×
1070
    else
1071
        *pnReqXSize = static_cast<int>(floor(*pdfReqXSize + 0.5));
49,399✔
1072

1073
    if (*pdfReqYSize > INT_MAX)
49,399✔
1074
        *pnReqYSize = INT_MAX;
×
1075
    else
1076
        *pnReqYSize = static_cast<int>(floor(*pdfReqYSize + 0.5));
49,399✔
1077

1078
    /* -------------------------------------------------------------------- */
1079
    /*      Clamp within the bounds of the available source data.           */
1080
    /* -------------------------------------------------------------------- */
1081

1082
    if (*pnReqXSize == 0)
49,399✔
1083
        *pnReqXSize = 1;
675✔
1084
    if (*pnReqYSize == 0)
49,399✔
1085
        *pnReqYSize = 1;
22,678✔
1086

1087
    auto l_band = GetRasterBand();
49,399✔
1088
    if (!l_band)
49,399✔
1089
    {
1090
        bErrorOut = true;
106✔
1091
        return FALSE;
106✔
1092
    }
1093
    if (*pnReqXSize > INT_MAX - *pnReqXOff ||
98,587✔
1094
        *pnReqXOff + *pnReqXSize > l_band->GetXSize())
49,293✔
1095
    {
1096
        *pnReqXSize = l_band->GetXSize() - *pnReqXOff;
44✔
1097
        bModifiedX = true;
44✔
1098
    }
1099
    if (*pdfReqXOff + *pdfReqXSize > l_band->GetXSize())
49,294✔
1100
    {
1101
        *pdfReqXSize = l_band->GetXSize() - *pdfReqXOff;
42✔
1102
        bModifiedX = true;
44✔
1103
    }
1104

1105
    if (*pnReqYSize > INT_MAX - *pnReqYOff ||
98,587✔
1106
        *pnReqYOff + *pnReqYSize > l_band->GetYSize())
49,294✔
1107
    {
1108
        *pnReqYSize = l_band->GetYSize() - *pnReqYOff;
44✔
1109
        bModifiedY = true;
44✔
1110
    }
1111
    if (*pdfReqYOff + *pdfReqYSize > l_band->GetYSize())
49,293✔
1112
    {
1113
        *pdfReqYSize = l_band->GetYSize() - *pdfReqYOff;
56✔
1114
        bModifiedY = true;
56✔
1115
    }
1116

1117
    /* -------------------------------------------------------------------- */
1118
    /*      Don't do anything if the requesting region is completely off    */
1119
    /*      the source image.                                               */
1120
    /* -------------------------------------------------------------------- */
1121
    if (*pnReqXOff >= l_band->GetXSize() || *pnReqYOff >= l_band->GetYSize() ||
98,581✔
1122
        *pnReqXSize <= 0 || *pnReqYSize <= 0)
98,580✔
1123
    {
1124
        return FALSE;
9✔
1125
    }
1126

1127
    /* -------------------------------------------------------------------- */
1128
    /*      If we haven't had to modify the source rectangle, then the      */
1129
    /*      destination rectangle must be the whole region.                 */
1130
    /* -------------------------------------------------------------------- */
1131
    if (bModifiedX || bModifiedY)
49,283✔
1132
    {
1133
        /* --------------------------------------------------------------------
1134
         */
1135
        /*      Now transform this possibly reduced request back into the */
1136
        /*      destination buffer coordinates in case the output region is */
1137
        /*      less than the whole buffer. */
1138
        /* --------------------------------------------------------------------
1139
         */
1140
        double dfDstULX = 0.0;
3,243✔
1141
        double dfDstULY = 0.0;
3,243✔
1142
        double dfDstLRX = 0.0;
3,243✔
1143
        double dfDstLRY = 0.0;
3,243✔
1144

1145
        SrcToDst(*pdfReqXOff, *pdfReqYOff, dfDstULX, dfDstULY);
3,243✔
1146
        SrcToDst(*pdfReqXOff + *pdfReqXSize, *pdfReqYOff + *pdfReqYSize,
3,242✔
1147
                 dfDstLRX, dfDstLRY);
1148
#if DEBUG_VERBOSE
1149
        CPLDebug("VRT", "dfDstULX=%g dfDstULY=%g dfDstLRX=%g dfDstLRY=%g",
1150
                 dfDstULX, dfDstULY, dfDstLRX, dfDstLRY);
1151
#endif
1152

1153
        if (bModifiedX)
3,242✔
1154
        {
1155
            const double dfScaleWinToBufX = nBufXSize / dfXSize;
3,202✔
1156

1157
            const double dfOutXOff = (dfDstULX - dfXOff) * dfScaleWinToBufX;
3,202✔
1158
            if (dfOutXOff <= 0)
3,202✔
1159
                *pnOutXOff = 0;
1,347✔
1160
            else if (dfOutXOff > INT_MAX)
1,855✔
1161
                *pnOutXOff = INT_MAX;
×
1162
            else
1163
                *pnOutXOff = static_cast<int>(dfOutXOff + EPS);
1,855✔
1164

1165
            // Apply correction on floating-point source window
1166
            {
1167
                double dfDstDeltaX =
3,202✔
1168
                    (dfOutXOff - *pnOutXOff) / dfScaleWinToBufX;
3,202✔
1169
                double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
3,202✔
1170
                *pdfReqXOff -= dfSrcDeltaX;
3,202✔
1171
                *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
6,407✔
1172
                                        static_cast<double>(INT_MAX));
3,202✔
1173
            }
1174

1175
            double dfOutRightXOff = (dfDstLRX - dfXOff) * dfScaleWinToBufX;
3,205✔
1176
            if (dfOutRightXOff < dfOutXOff)
3,205✔
1177
                return FALSE;
2✔
1178
            if (dfOutRightXOff > INT_MAX)
3,205✔
1179
                dfOutRightXOff = INT_MAX;
×
1180
            const int nOutRightXOff =
3,205✔
1181
                static_cast<int>(ceil(dfOutRightXOff - EPS));
3,205✔
1182
            *pnOutXSize = nOutRightXOff - *pnOutXOff;
3,205✔
1183

1184
            if (*pnOutXSize > INT_MAX - *pnOutXOff ||
3,205✔
1185
                *pnOutXOff + *pnOutXSize > nBufXSize)
3,202✔
1186
                *pnOutXSize = nBufXSize - *pnOutXOff;
×
1187

1188
            // Apply correction on floating-point source window
1189
            {
1190
                double dfDstDeltaX =
3,205✔
1191
                    (nOutRightXOff - dfOutRightXOff) / dfScaleWinToBufX;
3,205✔
1192
                double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
3,205✔
1193
                *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
6,410✔
1194
                                        static_cast<double>(INT_MAX));
3,205✔
1195
            }
1196
        }
1197

1198
        if (bModifiedY)
3,245✔
1199
        {
1200
            const double dfScaleWinToBufY = nBufYSize / dfYSize;
358✔
1201

1202
            const double dfOutYOff = (dfDstULY - dfYOff) * dfScaleWinToBufY;
358✔
1203
            if (dfOutYOff <= 0)
358✔
1204
                *pnOutYOff = 0;
183✔
1205
            else if (dfOutYOff > INT_MAX)
175✔
1206
                *pnOutYOff = INT_MAX;
×
1207
            else
1208
                *pnOutYOff = static_cast<int>(dfOutYOff + EPS);
175✔
1209

1210
            // Apply correction on floating-point source window
1211
            {
1212
                double dfDstDeltaY =
358✔
1213
                    (dfOutYOff - *pnOutYOff) / dfScaleWinToBufY;
358✔
1214
                double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
358✔
1215
                *pdfReqYOff -= dfSrcDeltaY;
358✔
1216
                *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
716✔
1217
                                        static_cast<double>(INT_MAX));
358✔
1218
            }
1219

1220
            double dfOutTopYOff = (dfDstLRY - dfYOff) * dfScaleWinToBufY;
358✔
1221
            if (dfOutTopYOff < dfOutYOff)
358✔
1222
                return FALSE;
×
1223
            if (dfOutTopYOff > INT_MAX)
358✔
1224
                dfOutTopYOff = INT_MAX;
×
1225
            const int nOutTopYOff = static_cast<int>(ceil(dfOutTopYOff - EPS));
358✔
1226
            *pnOutYSize = nOutTopYOff - *pnOutYOff;
358✔
1227

1228
            if (*pnOutYSize > INT_MAX - *pnOutYOff ||
358✔
1229
                *pnOutYOff + *pnOutYSize > nBufYSize)
358✔
1230
                *pnOutYSize = nBufYSize - *pnOutYOff;
×
1231

1232
            // Apply correction on floating-point source window
1233
            {
1234
                double dfDstDeltaY =
358✔
1235
                    (nOutTopYOff - dfOutTopYOff) / dfScaleWinToBufY;
358✔
1236
                double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
358✔
1237
                *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
716✔
1238
                                        static_cast<double>(INT_MAX));
358✔
1239
            }
1240
        }
1241

1242
        if (*pnOutXSize < 1 || *pnOutYSize < 1)
3,245✔
1243
            return FALSE;
2✔
1244
    }
1245

1246
    *pdfReqXOff = RoundIfCloseToInt(*pdfReqXOff);
49,283✔
1247
    *pdfReqYOff = RoundIfCloseToInt(*pdfReqYOff);
49,282✔
1248
    *pdfReqXSize = RoundIfCloseToInt(*pdfReqXSize);
49,283✔
1249
    *pdfReqYSize = RoundIfCloseToInt(*pdfReqYSize);
49,283✔
1250

1251
    return TRUE;
49,283✔
1252
}
1253

1254
/************************************************************************/
1255
/*                          NeedMaxValAdjustment()                      */
1256
/************************************************************************/
1257

1258
int VRTSimpleSource::NeedMaxValAdjustment() const
41,992✔
1259
{
1260
    if (!m_nMaxValue)
41,992✔
1261
        return FALSE;
41,970✔
1262

1263
    auto l_band = GetRasterBand();
22✔
1264
    if (!l_band)
22✔
1265
        return FALSE;
×
1266
    const char *pszNBITS = l_band->GetMetadataItem("NBITS", "IMAGE_STRUCTURE");
22✔
1267
    const int nBits = (pszNBITS) ? atoi(pszNBITS) : 0;
22✔
1268
    if (nBits >= 1 && nBits <= 31)
22✔
1269
    {
1270
        const int nBandMaxValue = static_cast<int>((1U << nBits) - 1);
×
1271
        return nBandMaxValue > m_nMaxValue;
×
1272
    }
1273
    return TRUE;
22✔
1274
}
1275

1276
/************************************************************************/
1277
/*                              RasterIO()                              */
1278
/************************************************************************/
1279

1280
CPLErr VRTSimpleSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
50,219✔
1281
                                 int nYOff, int nXSize, int nYSize, void *pData,
1282
                                 int nBufXSize, int nBufYSize,
1283
                                 GDALDataType eBufType, GSpacing nPixelSpace,
1284
                                 GSpacing nLineSpace,
1285
                                 GDALRasterIOExtraArg *psExtraArgIn,
1286
                                 WorkingState & /*oWorkingState*/)
1287

1288
{
1289
    GDALRasterIOExtraArg sExtraArg;
1290
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
50,219✔
1291
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
50,219✔
1292

1293
    double dfXOff = nXOff;
50,219✔
1294
    double dfYOff = nYOff;
50,219✔
1295
    double dfXSize = nXSize;
50,219✔
1296
    double dfYSize = nYSize;
50,219✔
1297
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
50,219✔
1298
    {
1299
        dfXOff = psExtraArgIn->dfXOff;
62✔
1300
        dfYOff = psExtraArgIn->dfYOff;
62✔
1301
        dfXSize = psExtraArgIn->dfXSize;
62✔
1302
        dfYSize = psExtraArgIn->dfYSize;
62✔
1303
    }
1304

1305
    // The window we will actually request from the source raster band.
1306
    double dfReqXOff = 0.0;
50,219✔
1307
    double dfReqYOff = 0.0;
50,219✔
1308
    double dfReqXSize = 0.0;
50,219✔
1309
    double dfReqYSize = 0.0;
50,219✔
1310
    int nReqXOff = 0;
50,219✔
1311
    int nReqYOff = 0;
50,219✔
1312
    int nReqXSize = 0;
50,219✔
1313
    int nReqYSize = 0;
50,219✔
1314

1315
    // The window we will actual set _within_ the pData buffer.
1316
    int nOutXOff = 0;
50,219✔
1317
    int nOutYOff = 0;
50,219✔
1318
    int nOutXSize = 0;
50,219✔
1319
    int nOutYSize = 0;
50,219✔
1320

1321
    bool bError = false;
50,219✔
1322
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
50,219✔
1323
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1324
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1325
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1326
    {
1327
        return bError ? CE_Failure : CE_None;
9,313✔
1328
    }
1329
#if DEBUG_VERBOSE
1330
    CPLDebug("VRT",
1331
             "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
1332
             "nBufYSize=%d,\n"
1333
             "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
1334
             "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
1335
             "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
1336
             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
1337
             dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
1338
             nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
1339
#endif
1340

1341
    /* -------------------------------------------------------------------- */
1342
    /*      Actually perform the IO request.                                */
1343
    /* -------------------------------------------------------------------- */
1344
    if (!m_osResampling.empty())
40,906✔
1345
    {
1346
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
2,050✔
1347
    }
1348
    else if (psExtraArgIn != nullptr)
38,856✔
1349
    {
1350
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
38,856✔
1351
    }
1352
    psExtraArg->bFloatingPointWindowValidity = TRUE;
40,906✔
1353
    psExtraArg->dfXOff = dfReqXOff;
40,906✔
1354
    psExtraArg->dfYOff = dfReqYOff;
40,906✔
1355
    psExtraArg->dfXSize = dfReqXSize;
40,906✔
1356
    psExtraArg->dfYSize = dfReqYSize;
40,906✔
1357
    if (psExtraArgIn)
40,906✔
1358
    {
1359
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
40,906✔
1360
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
40,906✔
1361
    }
1362

1363
    GByte *pabyOut = static_cast<unsigned char *>(pData) +
40,906✔
1364
                     nOutXOff * nPixelSpace +
40,906✔
1365
                     static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
40,906✔
1366

1367
    auto l_band = GetRasterBand();
40,906✔
1368
    if (!l_band)
40,906✔
1369
        return CE_Failure;
×
1370

1371
    CPLErr eErr = CE_Failure;
40,906✔
1372
    if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
40,906✔
1373
                                      eVRTBandDataType))
40,905✔
1374
    {
1375
        const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
49✔
1376
        void *pTemp = VSI_MALLOC3_VERBOSE(nOutXSize, nOutYSize, nBandDTSize);
49✔
1377
        if (pTemp)
49✔
1378
        {
1379
            eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
49✔
1380
                                    nReqYSize, pTemp, nOutXSize, nOutYSize,
1381
                                    eVRTBandDataType, 0, 0, psExtraArg);
1382
            if (eErr == CE_None)
49✔
1383
            {
1384
                GByte *pabyTemp = static_cast<GByte *>(pTemp);
49✔
1385
                for (int iY = 0; iY < nOutYSize; iY++)
779✔
1386
                {
1387
                    GDALCopyWords(
730✔
1388
                        pabyTemp +
730✔
1389
                            static_cast<size_t>(iY) * nBandDTSize * nOutXSize,
730✔
1390
                        eVRTBandDataType, nBandDTSize,
1391
                        pabyOut + static_cast<GPtrDiff_t>(iY * nLineSpace),
730✔
1392
                        eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1393
                }
1394
            }
1395
            VSIFree(pTemp);
49✔
1396
        }
1397
    }
1398
    else
1399
    {
1400
        eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
40,856✔
1401
                                nReqYSize, pabyOut, nOutXSize, nOutYSize,
1402
                                eBufType, nPixelSpace, nLineSpace, psExtraArg);
1403
    }
1404

1405
    if (NeedMaxValAdjustment())
40,906✔
1406
    {
1407
        for (int j = 0; j < nOutYSize; j++)
234✔
1408
        {
1409
            for (int i = 0; i < nOutXSize; i++)
4,620✔
1410
            {
1411
                int nVal = 0;
4,400✔
1412
                GDALCopyWords(pabyOut + j * nLineSpace + i * nPixelSpace,
4,400✔
1413
                              eBufType, 0, &nVal, GDT_Int32, 0, 1);
1414
                if (nVal > m_nMaxValue)
4,400✔
1415
                    nVal = m_nMaxValue;
800✔
1416
                GDALCopyWords(&nVal, GDT_Int32, 0,
4,400✔
1417
                              pabyOut + j * nLineSpace + i * nPixelSpace,
4,400✔
1418
                              eBufType, 0, 1);
1419
            }
1420
        }
1421
    }
1422

1423
    if (psExtraArg->pfnProgress)
40,906✔
1424
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
2,925✔
1425

1426
    return eErr;
40,906✔
1427
}
1428

1429
/************************************************************************/
1430
/*                             GetMinimum()                             */
1431
/************************************************************************/
1432

1433
double VRTSimpleSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
52✔
1434
{
1435
    // The window we will actually request from the source raster band.
1436
    double dfReqXOff = 0.0;
52✔
1437
    double dfReqYOff = 0.0;
52✔
1438
    double dfReqXSize = 0.0;
52✔
1439
    double dfReqYSize = 0.0;
52✔
1440
    int nReqXOff = 0;
52✔
1441
    int nReqYOff = 0;
52✔
1442
    int nReqXSize = 0;
52✔
1443
    int nReqYSize = 0;
52✔
1444

1445
    // The window we will actual set _within_ the pData buffer.
1446
    int nOutXOff = 0;
52✔
1447
    int nOutYOff = 0;
52✔
1448
    int nOutXSize = 0;
52✔
1449
    int nOutYSize = 0;
52✔
1450

1451
    bool bError = false;
52✔
1452
    auto l_band = GetRasterBand();
52✔
1453
    if (!l_band ||
104✔
1454
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
52✔
1455
                         &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1456
                         &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1457
                         &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
52✔
1458
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
156✔
1459
        nReqYSize != l_band->GetYSize())
52✔
1460
    {
1461
        *pbSuccess = FALSE;
×
1462
        return 0;
×
1463
    }
1464

1465
    const double dfVal = l_band->GetMinimum(pbSuccess);
52✔
1466
    if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
52✔
1467
        return m_nMaxValue;
2✔
1468
    return dfVal;
50✔
1469
}
1470

1471
/************************************************************************/
1472
/*                             GetMaximum()                             */
1473
/************************************************************************/
1474

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

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

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

1507
    const double dfVal = l_band->GetMaximum(pbSuccess);
51✔
1508
    if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
51✔
1509
        return m_nMaxValue;
2✔
1510
    return dfVal;
49✔
1511
}
1512

1513
/************************************************************************/
1514
/*                            GetHistogram()                            */
1515
/************************************************************************/
1516

1517
CPLErr VRTSimpleSource::GetHistogram(int nXSize, int nYSize, double dfMin,
4✔
1518
                                     double dfMax, int nBuckets,
1519
                                     GUIntBig *panHistogram,
1520
                                     int bIncludeOutOfRange, int bApproxOK,
1521
                                     GDALProgressFunc pfnProgress,
1522
                                     void *pProgressData)
1523
{
1524
    // The window we will actually request from the source raster band.
1525
    double dfReqXOff = 0.0;
4✔
1526
    double dfReqYOff = 0.0;
4✔
1527
    double dfReqXSize = 0.0;
4✔
1528
    double dfReqYSize = 0.0;
4✔
1529
    int nReqXOff = 0;
4✔
1530
    int nReqYOff = 0;
4✔
1531
    int nReqXSize = 0;
4✔
1532
    int nReqYSize = 0;
4✔
1533

1534
    // The window we will actual set _within_ the pData buffer.
1535
    int nOutXOff = 0;
4✔
1536
    int nOutYOff = 0;
4✔
1537
    int nOutXSize = 0;
4✔
1538
    int nOutYSize = 0;
4✔
1539

1540
    bool bError = false;
4✔
1541
    auto l_band = GetRasterBand();
4✔
1542
    if (!l_band || NeedMaxValAdjustment() ||
4✔
1543
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize, &dfReqXOff,
4✔
1544
                         &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1545
                         &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff,
1546
                         &nOutYOff, &nOutXSize, &nOutYSize, bError) ||
4✔
1547
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
12✔
1548
        nReqYSize != l_band->GetYSize())
4✔
1549
    {
1550
        return CE_Failure;
×
1551
    }
1552

1553
    return l_band->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
4✔
1554
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
1555
                                pProgressData);
4✔
1556
}
1557

1558
/************************************************************************/
1559
/*                          DatasetRasterIO()                           */
1560
/************************************************************************/
1561

1562
CPLErr VRTSimpleSource::DatasetRasterIO(
992✔
1563
    GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
1564
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1565
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
1566
    GSpacing nLineSpace, GSpacing nBandSpace,
1567
    GDALRasterIOExtraArg *psExtraArgIn)
1568
{
1569
    if (GetType() != VRTSimpleSource::GetTypeStatic())
992✔
1570
    {
1571
        CPLError(CE_Failure, CPLE_NotSupported,
×
1572
                 "DatasetRasterIO() not implemented for %s", GetType());
×
1573
        return CE_Failure;
×
1574
    }
1575

1576
    GDALRasterIOExtraArg sExtraArg;
1577
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
992✔
1578
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
992✔
1579

1580
    double dfXOff = nXOff;
992✔
1581
    double dfYOff = nYOff;
992✔
1582
    double dfXSize = nXSize;
992✔
1583
    double dfYSize = nYSize;
992✔
1584
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
992✔
1585
    {
1586
        dfXOff = psExtraArgIn->dfXOff;
11✔
1587
        dfYOff = psExtraArgIn->dfYOff;
11✔
1588
        dfXSize = psExtraArgIn->dfXSize;
11✔
1589
        dfYSize = psExtraArgIn->dfYSize;
11✔
1590
    }
1591

1592
    // The window we will actually request from the source raster band.
1593
    double dfReqXOff = 0.0;
992✔
1594
    double dfReqYOff = 0.0;
992✔
1595
    double dfReqXSize = 0.0;
992✔
1596
    double dfReqYSize = 0.0;
992✔
1597
    int nReqXOff = 0;
992✔
1598
    int nReqYOff = 0;
992✔
1599
    int nReqXSize = 0;
992✔
1600
    int nReqYSize = 0;
992✔
1601

1602
    // The window we will actual set _within_ the pData buffer.
1603
    int nOutXOff = 0;
992✔
1604
    int nOutYOff = 0;
992✔
1605
    int nOutXSize = 0;
992✔
1606
    int nOutYSize = 0;
992✔
1607

1608
    bool bError = false;
992✔
1609
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
992✔
1610
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1611
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1612
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1613
    {
1614
        return bError ? CE_Failure : CE_None;
71✔
1615
    }
1616

1617
    auto l_band = GetRasterBand();
919✔
1618
    if (!l_band)
920✔
1619
        return CE_Failure;
×
1620

1621
    GDALDataset *poDS = l_band->GetDataset();
920✔
1622
    if (poDS == nullptr)
919✔
1623
        return CE_Failure;
×
1624

1625
    if (!m_osResampling.empty())
919✔
1626
    {
1627
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
6✔
1628
    }
1629
    else if (psExtraArgIn != nullptr)
915✔
1630
    {
1631
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
912✔
1632
    }
1633
    psExtraArg->bFloatingPointWindowValidity = TRUE;
921✔
1634
    psExtraArg->dfXOff = dfReqXOff;
921✔
1635
    psExtraArg->dfYOff = dfReqYOff;
921✔
1636
    psExtraArg->dfXSize = dfReqXSize;
921✔
1637
    psExtraArg->dfYSize = dfReqYSize;
921✔
1638
    if (psExtraArgIn)
921✔
1639
    {
1640
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
921✔
1641
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
921✔
1642
    }
1643

1644
    GByte *pabyOut = static_cast<unsigned char *>(pData) +
921✔
1645
                     nOutXOff * nPixelSpace +
921✔
1646
                     static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
921✔
1647

1648
    CPLErr eErr = CE_Failure;
921✔
1649

1650
    if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
921✔
1651
                                      eVRTBandDataType))
919✔
1652
    {
1653
        const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
1✔
1654
        void *pTemp = VSI_MALLOC3_VERBOSE(
1✔
1655
            nOutXSize, nOutYSize, cpl::fits_on<int>(nBandDTSize * nBandCount));
1656
        if (pTemp)
1✔
1657
        {
1658
            eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1✔
1659
                                  nReqYSize, pTemp, nOutXSize, nOutYSize,
1660
                                  eVRTBandDataType, nBandCount, panBandMap, 0,
1661
                                  0, 0, psExtraArg);
1662
            if (eErr == CE_None)
1✔
1663
            {
1664
                GByte *pabyTemp = static_cast<GByte *>(pTemp);
1✔
1665
                const size_t nSrcBandSpace =
1✔
1666
                    static_cast<size_t>(nOutYSize) * nOutXSize * nBandDTSize;
1✔
1667
                for (int iBand = 0; iBand < nBandCount; iBand++)
2✔
1668
                {
1669
                    for (int iY = 0; iY < nOutYSize; iY++)
21✔
1670
                    {
1671
                        GDALCopyWords(
20✔
1672
                            pabyTemp + iBand * nSrcBandSpace +
20✔
1673
                                static_cast<size_t>(iY) * nBandDTSize *
20✔
1674
                                    nOutXSize,
20✔
1675
                            eVRTBandDataType, nBandDTSize,
1676
                            pabyOut + static_cast<GPtrDiff_t>(
20✔
1677
                                          iY * nLineSpace + iBand * nBandSpace),
20✔
1678
                            eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1679
                    }
1680
                }
1681
            }
1682
            VSIFree(pTemp);
1✔
1683
        }
1684
    }
1685
    else
1686
    {
1687
        eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
918✔
1688
                              pabyOut, nOutXSize, nOutYSize, eBufType,
1689
                              nBandCount, panBandMap, nPixelSpace, nLineSpace,
1690
                              nBandSpace, psExtraArg);
1691
    }
1692

1693
    if (NeedMaxValAdjustment())
921✔
1694
    {
1695
        for (int k = 0; k < nBandCount; k++)
×
1696
        {
1697
            for (int j = 0; j < nOutYSize; j++)
×
1698
            {
1699
                for (int i = 0; i < nOutXSize; i++)
×
1700
                {
1701
                    int nVal = 0;
×
1702
                    GDALCopyWords(pabyOut + k * nBandSpace + j * nLineSpace +
×
1703
                                      i * nPixelSpace,
×
1704
                                  eBufType, 0, &nVal, GDT_Int32, 0, 1);
1705

1706
                    if (nVal > m_nMaxValue)
×
1707
                        nVal = m_nMaxValue;
×
1708

1709
                    GDALCopyWords(&nVal, GDT_Int32, 0,
×
1710
                                  pabyOut + k * nBandSpace + j * nLineSpace +
×
1711
                                      i * nPixelSpace,
×
1712
                                  eBufType, 0, 1);
1713
                }
1714
            }
1715
        }
1716
    }
1717

1718
    if (psExtraArg->pfnProgress)
921✔
1719
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
460✔
1720

1721
    return eErr;
920✔
1722
}
1723

1724
/************************************************************************/
1725
/*                          SetResampling()                             */
1726
/************************************************************************/
1727

1728
void VRTSimpleSource::SetResampling(const char *pszResampling)
4,034✔
1729
{
1730
    m_osResampling = (pszResampling) ? pszResampling : "";
4,034✔
1731
}
4,034✔
1732

1733
/************************************************************************/
1734
/* ==================================================================== */
1735
/*                         VRTAveragedSource                            */
1736
/* ==================================================================== */
1737
/************************************************************************/
1738

1739
/************************************************************************/
1740
/*                         VRTAveragedSource()                          */
1741
/************************************************************************/
1742

1743
VRTAveragedSource::VRTAveragedSource()
16✔
1744
{
1745
}
16✔
1746

1747
/************************************************************************/
1748
/*                           GetTypeStatic()                            */
1749
/************************************************************************/
1750

1751
const char *VRTAveragedSource::GetTypeStatic()
3,072✔
1752
{
1753
    static const char *TYPE = "AveragedSource";
1754
    return TYPE;
3,072✔
1755
}
1756

1757
/************************************************************************/
1758
/*                            GetType()                                 */
1759
/************************************************************************/
1760

1761
const char *VRTAveragedSource::GetType() const
11✔
1762
{
1763
    return GetTypeStatic();
11✔
1764
}
1765

1766
/************************************************************************/
1767
/*                           SerializeToXML()                           */
1768
/************************************************************************/
1769

1770
CPLXMLNode *VRTAveragedSource::SerializeToXML(const char *pszVRTPath)
×
1771

1772
{
1773
    CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
×
1774

1775
    if (psSrc == nullptr)
×
1776
        return nullptr;
×
1777

1778
    CPLFree(psSrc->pszValue);
×
1779
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
×
1780

1781
    return psSrc;
×
1782
}
1783

1784
/************************************************************************/
1785
/*                           SetNoDataValue()                           */
1786
/************************************************************************/
1787

1788
void VRTAveragedSource::SetNoDataValue(double dfNewNoDataValue)
×
1789

1790
{
1791
    if (dfNewNoDataValue == VRT_NODATA_UNSET)
×
1792
    {
1793
        m_bNoDataSet = FALSE;
×
1794
        m_dfNoDataValue = VRT_NODATA_UNSET;
×
1795
        return;
×
1796
    }
1797

1798
    m_bNoDataSet = TRUE;
×
1799
    m_dfNoDataValue = dfNewNoDataValue;
×
1800
}
1801

1802
/************************************************************************/
1803
/*                              RasterIO()                              */
1804
/************************************************************************/
1805

1806
CPLErr VRTAveragedSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
33✔
1807
                                   int nYOff, int nXSize, int nYSize,
1808
                                   void *pData, int nBufXSize, int nBufYSize,
1809
                                   GDALDataType eBufType, GSpacing nPixelSpace,
1810
                                   GSpacing nLineSpace,
1811
                                   GDALRasterIOExtraArg *psExtraArgIn,
1812
                                   WorkingState & /*oWorkingState*/)
1813

1814
{
1815
    GDALRasterIOExtraArg sExtraArg;
1816
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
33✔
1817
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
33✔
1818

1819
    double dfXOff = nXOff;
33✔
1820
    double dfYOff = nYOff;
33✔
1821
    double dfXSize = nXSize;
33✔
1822
    double dfYSize = nYSize;
33✔
1823
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
33✔
1824
    {
1825
        dfXOff = psExtraArgIn->dfXOff;
×
1826
        dfYOff = psExtraArgIn->dfYOff;
×
1827
        dfXSize = psExtraArgIn->dfXSize;
×
1828
        dfYSize = psExtraArgIn->dfYSize;
×
1829
    }
1830

1831
    // The window we will actually request from the source raster band.
1832
    double dfReqXOff = 0.0;
33✔
1833
    double dfReqYOff = 0.0;
33✔
1834
    double dfReqXSize = 0.0;
33✔
1835
    double dfReqYSize = 0.0;
33✔
1836
    int nReqXOff = 0;
33✔
1837
    int nReqYOff = 0;
33✔
1838
    int nReqXSize = 0;
33✔
1839
    int nReqYSize = 0;
33✔
1840

1841
    // The window we will actual set _within_ the pData buffer.
1842
    int nOutXOff = 0;
33✔
1843
    int nOutYOff = 0;
33✔
1844
    int nOutXSize = 0;
33✔
1845
    int nOutYSize = 0;
33✔
1846

1847
    bool bError = false;
33✔
1848
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
33✔
1849
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
1850
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
1851
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
1852
    {
1853
        return bError ? CE_Failure : CE_None;
×
1854
    }
1855

1856
    auto l_band = GetRasterBand();
33✔
1857
    if (!l_band)
33✔
1858
        return CE_Failure;
×
1859

1860
    /* -------------------------------------------------------------------- */
1861
    /*      Allocate a temporary buffer to whole the full resolution        */
1862
    /*      data from the area of interest.                                 */
1863
    /* -------------------------------------------------------------------- */
1864
    float *const pafSrc = static_cast<float *>(
1865
        VSI_MALLOC3_VERBOSE(sizeof(float), nReqXSize, nReqYSize));
33✔
1866
    if (pafSrc == nullptr)
33✔
1867
    {
1868
        return CE_Failure;
×
1869
    }
1870

1871
    /* -------------------------------------------------------------------- */
1872
    /*      Load it.                                                        */
1873
    /* -------------------------------------------------------------------- */
1874
    if (!m_osResampling.empty())
33✔
1875
    {
1876
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
28✔
1877
    }
1878
    else if (psExtraArgIn != nullptr)
5✔
1879
    {
1880
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
5✔
1881
    }
1882

1883
    psExtraArg->bFloatingPointWindowValidity = TRUE;
33✔
1884
    psExtraArg->dfXOff = dfReqXOff;
33✔
1885
    psExtraArg->dfYOff = dfReqYOff;
33✔
1886
    psExtraArg->dfXSize = dfReqXSize;
33✔
1887
    psExtraArg->dfYSize = dfReqYSize;
33✔
1888
    if (psExtraArgIn)
33✔
1889
    {
1890
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
33✔
1891
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
33✔
1892
    }
1893

1894
    const CPLErr eErr = l_band->RasterIO(
33✔
1895
        GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize, pafSrc, nReqXSize,
1896
        nReqYSize, GDT_Float32, 0, 0, psExtraArg);
1897

1898
    if (eErr != CE_None)
33✔
1899
    {
1900
        VSIFree(pafSrc);
×
1901
        return eErr;
×
1902
    }
1903

1904
    /* -------------------------------------------------------------------- */
1905
    /*      Do the averaging.                                               */
1906
    /* -------------------------------------------------------------------- */
1907
    for (int iBufLine = nOutYOff; iBufLine < nOutYOff + nOutYSize; iBufLine++)
5,956✔
1908
    {
1909
        const double dfYDst =
5,923✔
1910
            (iBufLine / static_cast<double>(nBufYSize)) * nYSize + nYOff;
5,923✔
1911

1912
        for (int iBufPixel = nOutXOff; iBufPixel < nOutXOff + nOutXSize;
2,017,080✔
1913
             iBufPixel++)
1914
        {
1915
            double dfXSrcStart, dfXSrcEnd, dfYSrcStart, dfYSrcEnd;
1916
            int iXSrcStart, iYSrcStart, iXSrcEnd, iYSrcEnd;
1917

1918
            const double dfXDst =
2,011,160✔
1919
                (iBufPixel / static_cast<double>(nBufXSize)) * nXSize + nXOff;
2,011,160✔
1920

1921
            // Compute the source image rectangle needed for this pixel.
1922
            DstToSrc(dfXDst, dfYDst, dfXSrcStart, dfYSrcStart);
2,011,160✔
1923
            DstToSrc(dfXDst + 1.0, dfYDst + 1.0, dfXSrcEnd, dfYSrcEnd);
2,011,160✔
1924

1925
            // Convert to integers, assuming that the center of the source
1926
            // pixel must be in our rect to get included.
1927
            if (dfXSrcEnd >= dfXSrcStart + 1)
2,011,160✔
1928
            {
1929
                iXSrcStart = static_cast<int>(floor(dfXSrcStart + 0.5));
1,049,560✔
1930
                iXSrcEnd = static_cast<int>(floor(dfXSrcEnd + 0.5));
1,049,560✔
1931
            }
1932
            else
1933
            {
1934
                /* If the resampling factor is less than 100%, the distance */
1935
                /* between the source pixel is < 1, so we stick to nearest */
1936
                /* neighbour */
1937
                iXSrcStart = static_cast<int>(floor(dfXSrcStart));
961,600✔
1938
                iXSrcEnd = iXSrcStart + 1;
961,600✔
1939
            }
1940
            if (dfYSrcEnd >= dfYSrcStart + 1)
2,011,160✔
1941
            {
1942
                iYSrcStart = static_cast<int>(floor(dfYSrcStart + 0.5));
1,049,560✔
1943
                iYSrcEnd = static_cast<int>(floor(dfYSrcEnd + 0.5));
1,049,560✔
1944
            }
1945
            else
1946
            {
1947
                iYSrcStart = static_cast<int>(floor(dfYSrcStart));
961,600✔
1948
                iYSrcEnd = iYSrcStart + 1;
961,600✔
1949
            }
1950

1951
            // Transform into the coordinate system of the source *buffer*
1952
            iXSrcStart -= nReqXOff;
2,011,160✔
1953
            iYSrcStart -= nReqYOff;
2,011,160✔
1954
            iXSrcEnd -= nReqXOff;
2,011,160✔
1955
            iYSrcEnd -= nReqYOff;
2,011,160✔
1956

1957
            double dfSum = 0.0;
2,011,160✔
1958
            int nPixelCount = 0;
2,011,160✔
1959

1960
            for (int iY = iYSrcStart; iY < iYSrcEnd; iY++)
4,022,510✔
1961
            {
1962
                if (iY < 0 || iY >= nReqYSize)
2,011,360✔
1963
                    continue;
×
1964

1965
                for (int iX = iXSrcStart; iX < iXSrcEnd; iX++)
4,023,130✔
1966
                {
1967
                    if (iX < 0 || iX >= nReqXSize)
2,011,780✔
1968
                        continue;
×
1969

1970
                    const float fSampledValue =
2,011,780✔
1971
                        pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
2,011,780✔
1972
                    if (std::isnan(fSampledValue))
2,011,780✔
1973
                        continue;
×
1974

1975
                    if (m_bNoDataSet &&
×
1976
                        GDALIsValueInRange<float>(m_dfNoDataValue) &&
2,011,780✔
1977
                        ARE_REAL_EQUAL(fSampledValue,
×
1978
                                       static_cast<float>(m_dfNoDataValue)))
×
1979
                        continue;
×
1980

1981
                    nPixelCount++;
2,011,780✔
1982
                    dfSum += pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
2,011,780✔
1983
                }
1984
            }
1985

1986
            if (nPixelCount == 0)
2,011,160✔
1987
                continue;
×
1988

1989
            // Compute output value.
1990
            const float dfOutputValue = static_cast<float>(dfSum / nPixelCount);
2,011,160✔
1991

1992
            // Put it in the output buffer.
1993
            GByte *pDstLocation =
2,011,160✔
1994
                static_cast<GByte *>(pData) + nPixelSpace * iBufPixel +
2,011,160✔
1995
                static_cast<GPtrDiff_t>(nLineSpace) * iBufLine;
2,011,160✔
1996

1997
            if (eBufType == GDT_Byte)
2,011,160✔
1998
                *pDstLocation = static_cast<GByte>(
2,008,660✔
1999
                    std::min(255.0, std::max(0.0, dfOutputValue + 0.5)));
2,008,660✔
2000
            else
2001
                GDALCopyWords(&dfOutputValue, GDT_Float32, 4, pDstLocation,
2,500✔
2002
                              eBufType, 8, 1);
2003
        }
2004
    }
2005

2006
    VSIFree(pafSrc);
33✔
2007

2008
    if (psExtraArg->pfnProgress)
33✔
2009
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
×
2010

2011
    return CE_None;
33✔
2012
}
2013

2014
/************************************************************************/
2015
/*                             GetMinimum()                             */
2016
/************************************************************************/
2017

2018
double VRTAveragedSource::GetMinimum(int /* nXSize */, int /* nYSize */,
×
2019
                                     int *pbSuccess)
2020
{
2021
    *pbSuccess = FALSE;
×
2022
    return 0.0;
×
2023
}
2024

2025
/************************************************************************/
2026
/*                             GetMaximum()                             */
2027
/************************************************************************/
2028

2029
double VRTAveragedSource::GetMaximum(int /* nXSize */, int /* nYSize */,
×
2030
                                     int *pbSuccess)
2031
{
2032
    *pbSuccess = FALSE;
×
2033
    return 0.0;
×
2034
}
2035

2036
/************************************************************************/
2037
/*                            GetHistogram()                            */
2038
/************************************************************************/
2039

2040
CPLErr VRTAveragedSource::GetHistogram(
×
2041
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2042
    int /* nBuckets */, GUIntBig * /* panHistogram */,
2043
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
2044
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2045
{
2046
    return CE_Failure;
×
2047
}
2048

2049
/************************************************************************/
2050
/* ==================================================================== */
2051
/*                     VRTNoDataFromMaskSource                          */
2052
/* ==================================================================== */
2053
/************************************************************************/
2054

2055
/************************************************************************/
2056
/*                     VRTNoDataFromMaskSource()                        */
2057
/************************************************************************/
2058

2059
VRTNoDataFromMaskSource::VRTNoDataFromMaskSource()
23✔
2060
{
2061
}
23✔
2062

2063
/************************************************************************/
2064
/*                              XMLInit()                               */
2065
/************************************************************************/
2066

2067
CPLErr
2068
VRTNoDataFromMaskSource::XMLInit(const CPLXMLNode *psSrc,
8✔
2069
                                 const char *pszVRTPath,
2070
                                 VRTMapSharedResources &oMapSharedSources)
2071

2072
{
2073
    /* -------------------------------------------------------------------- */
2074
    /*      Do base initialization.                                         */
2075
    /* -------------------------------------------------------------------- */
2076
    {
2077
        const CPLErr eErr =
2078
            VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
8✔
2079
        if (eErr != CE_None)
8✔
2080
            return eErr;
×
2081
    }
2082

2083
    if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
8✔
2084
    {
2085
        m_bNoDataSet = true;
8✔
2086
        m_dfNoDataValue = CPLAtofM(pszNODATA);
8✔
2087
    }
2088

2089
    m_dfMaskValueThreshold =
8✔
2090
        CPLAtofM(CPLGetXMLValue(psSrc, "MaskValueThreshold", "0"));
8✔
2091

2092
    if (const char *pszRemappedValue =
8✔
2093
            CPLGetXMLValue(psSrc, "RemappedValue", nullptr))
8✔
2094
    {
2095
        m_bHasRemappedValue = true;
×
2096
        m_dfRemappedValue = CPLAtofM(pszRemappedValue);
×
2097
    }
2098

2099
    return CE_None;
8✔
2100
}
2101

2102
/************************************************************************/
2103
/*                           GetTypeStatic()                            */
2104
/************************************************************************/
2105

2106
const char *VRTNoDataFromMaskSource::GetTypeStatic()
27✔
2107
{
2108
    static const char *TYPE = "NoDataFromMaskSource";
2109
    return TYPE;
27✔
2110
}
2111

2112
/************************************************************************/
2113
/*                            GetType()                                 */
2114
/************************************************************************/
2115

2116
const char *VRTNoDataFromMaskSource::GetType() const
11✔
2117
{
2118
    return GetTypeStatic();
11✔
2119
}
2120

2121
/************************************************************************/
2122
/*                           SerializeToXML()                           */
2123
/************************************************************************/
2124

2125
CPLXMLNode *VRTNoDataFromMaskSource::SerializeToXML(const char *pszVRTPath)
8✔
2126

2127
{
2128
    CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
8✔
2129

2130
    if (psSrc == nullptr)
8✔
2131
        return nullptr;
×
2132

2133
    CPLFree(psSrc->pszValue);
8✔
2134
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
8✔
2135

2136
    if (m_bNoDataSet)
8✔
2137
    {
2138
        CPLSetXMLValue(psSrc, "MaskValueThreshold",
8✔
2139
                       CPLSPrintf("%.17g", m_dfMaskValueThreshold));
2140

2141
        GDALDataType eBandDT = GDT_Unknown;
8✔
2142
        double dfNoDataValue = m_dfNoDataValue;
8✔
2143
        const auto kMaxFloat = std::numeric_limits<float>::max();
8✔
2144
        if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
8✔
2145
            1e-10 * kMaxFloat)
2146
        {
2147
            auto l_band = GetRasterBand();
×
2148
            if (l_band)
×
2149
            {
2150
                eBandDT = l_band->GetRasterDataType();
×
2151
                if (eBandDT == GDT_Float32)
×
2152
                {
2153
                    dfNoDataValue =
2154
                        GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
×
2155
                }
2156
            }
2157
        }
2158
        CPLSetXMLValue(psSrc, "NODATA",
8✔
2159
                       VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
16✔
2160
    }
2161

2162
    if (m_bHasRemappedValue)
8✔
2163
    {
2164
        CPLSetXMLValue(psSrc, "RemappedValue",
×
2165
                       CPLSPrintf("%.17g", m_dfRemappedValue));
2166
    }
2167

2168
    return psSrc;
8✔
2169
}
2170

2171
/************************************************************************/
2172
/*                           SetParameters()                            */
2173
/************************************************************************/
2174

2175
void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
15✔
2176
                                            double dfMaskValueThreshold)
2177
{
2178
    m_bNoDataSet = true;
15✔
2179
    m_dfNoDataValue = dfNoDataValue;
15✔
2180
    m_dfMaskValueThreshold = dfMaskValueThreshold;
15✔
2181
    if (!m_bHasRemappedValue)
15✔
2182
        m_dfRemappedValue = m_dfNoDataValue;
15✔
2183
}
15✔
2184

2185
/************************************************************************/
2186
/*                           SetParameters()                            */
2187
/************************************************************************/
2188

2189
void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
×
2190
                                            double dfMaskValueThreshold,
2191
                                            double dfRemappedValue)
2192
{
2193
    SetParameters(dfNoDataValue, dfMaskValueThreshold);
×
2194
    m_bHasRemappedValue = true;
×
2195
    m_dfRemappedValue = dfRemappedValue;
×
2196
}
×
2197

2198
/************************************************************************/
2199
/*                              RasterIO()                              */
2200
/************************************************************************/
2201

2202
CPLErr VRTNoDataFromMaskSource::RasterIO(
13✔
2203
    GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
2204
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2205
    GSpacing nPixelSpace, GSpacing nLineSpace,
2206
    GDALRasterIOExtraArg *psExtraArgIn, WorkingState &oWorkingState)
2207

2208
{
2209
    if (!m_bNoDataSet)
13✔
2210
    {
2211
        return VRTSimpleSource::RasterIO(eVRTBandDataType, nXOff, nYOff, nXSize,
×
2212
                                         nYSize, pData, nBufXSize, nBufYSize,
2213
                                         eBufType, nPixelSpace, nLineSpace,
2214
                                         psExtraArgIn, oWorkingState);
×
2215
    }
2216

2217
    GDALRasterIOExtraArg sExtraArg;
2218
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
13✔
2219
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
13✔
2220

2221
    double dfXOff = nXOff;
13✔
2222
    double dfYOff = nYOff;
13✔
2223
    double dfXSize = nXSize;
13✔
2224
    double dfYSize = nYSize;
13✔
2225
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
13✔
2226
    {
2227
        dfXOff = psExtraArgIn->dfXOff;
×
2228
        dfYOff = psExtraArgIn->dfYOff;
×
2229
        dfXSize = psExtraArgIn->dfXSize;
×
2230
        dfYSize = psExtraArgIn->dfYSize;
×
2231
    }
2232

2233
    // The window we will actually request from the source raster band.
2234
    double dfReqXOff = 0.0;
13✔
2235
    double dfReqYOff = 0.0;
13✔
2236
    double dfReqXSize = 0.0;
13✔
2237
    double dfReqYSize = 0.0;
13✔
2238
    int nReqXOff = 0;
13✔
2239
    int nReqYOff = 0;
13✔
2240
    int nReqXSize = 0;
13✔
2241
    int nReqYSize = 0;
13✔
2242

2243
    // The window we will actual set _within_ the pData buffer.
2244
    int nOutXOff = 0;
13✔
2245
    int nOutYOff = 0;
13✔
2246
    int nOutXSize = 0;
13✔
2247
    int nOutYSize = 0;
13✔
2248

2249
    bool bError = false;
13✔
2250
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
13✔
2251
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
2252
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
2253
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
2254
    {
2255
        return bError ? CE_Failure : CE_None;
×
2256
    }
2257

2258
    auto l_band = GetRasterBand();
13✔
2259
    if (!l_band)
13✔
2260
        return CE_Failure;
×
2261

2262
    /* -------------------------------------------------------------------- */
2263
    /*      Allocate temporary buffer(s).                                   */
2264
    /* -------------------------------------------------------------------- */
2265
    const auto eSrcBandDT = l_band->GetRasterDataType();
13✔
2266
    const int nSrcBandDTSize = GDALGetDataTypeSizeBytes(eSrcBandDT);
13✔
2267
    const auto eSrcMaskBandDT = l_band->GetMaskBand()->GetRasterDataType();
13✔
2268
    const int nSrcMaskBandDTSize = GDALGetDataTypeSizeBytes(eSrcMaskBandDT);
13✔
2269
    double dfRemappedValue = m_dfRemappedValue;
13✔
2270
    if (!m_bHasRemappedValue)
13✔
2271
    {
2272
        if (eSrcBandDT == GDT_Byte &&
19✔
2273
            m_dfNoDataValue >= std::numeric_limits<GByte>::min() &&
6✔
2274
            m_dfNoDataValue <= std::numeric_limits<GByte>::max() &&
25✔
2275
            static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
6✔
2276
        {
2277
            if (m_dfNoDataValue == std::numeric_limits<GByte>::max())
6✔
2278
                dfRemappedValue = m_dfNoDataValue - 1;
1✔
2279
            else
2280
                dfRemappedValue = m_dfNoDataValue + 1;
5✔
2281
        }
2282
        else if (eSrcBandDT == GDT_UInt16 &&
10✔
2283
                 m_dfNoDataValue >= std::numeric_limits<uint16_t>::min() &&
3✔
2284
                 m_dfNoDataValue <= std::numeric_limits<uint16_t>::max() &&
13✔
2285
                 static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
3✔
2286
        {
2287
            if (m_dfNoDataValue == std::numeric_limits<uint16_t>::max())
3✔
2288
                dfRemappedValue = m_dfNoDataValue - 1;
1✔
2289
            else
2290
                dfRemappedValue = m_dfNoDataValue + 1;
2✔
2291
        }
2292
        else if (eSrcBandDT == GDT_Int16 &&
6✔
2293
                 m_dfNoDataValue >= std::numeric_limits<int16_t>::min() &&
2✔
2294
                 m_dfNoDataValue <= std::numeric_limits<int16_t>::max() &&
8✔
2295
                 static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2✔
2296
        {
2297
            if (m_dfNoDataValue == std::numeric_limits<int16_t>::max())
2✔
2298
                dfRemappedValue = m_dfNoDataValue - 1;
1✔
2299
            else
2300
                dfRemappedValue = m_dfNoDataValue + 1;
1✔
2301
        }
2302
        else
2303
        {
2304
            constexpr double EPS = 1e-3;
2✔
2305
            if (m_dfNoDataValue == 0)
2✔
2306
                dfRemappedValue = EPS;
1✔
2307
            else
2308
                dfRemappedValue = m_dfNoDataValue * (1 + EPS);
1✔
2309
        }
2310
    }
2311
    const bool bByteOptim =
13✔
2312
        (eSrcBandDT == GDT_Byte && eBufType == GDT_Byte &&
6✔
2313
         eSrcMaskBandDT == GDT_Byte && m_dfMaskValueThreshold >= 0 &&
5✔
2314
         m_dfMaskValueThreshold <= 255 &&
5✔
2315
         static_cast<int>(m_dfMaskValueThreshold) == m_dfMaskValueThreshold &&
5✔
2316
         m_dfNoDataValue >= 0 && m_dfNoDataValue <= 255 &&
4✔
2317
         static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue &&
4✔
2318
         dfRemappedValue >= 0 && dfRemappedValue <= 255 &&
23✔
2319
         static_cast<int>(dfRemappedValue) == dfRemappedValue);
4✔
2320
    GByte *pabyWrkBuffer;
2321
    try
2322
    {
2323
        if (bByteOptim && nOutXOff == 0 && nOutYOff == 0 &&
13✔
2324
            nOutXSize == nBufXSize && nOutYSize == nBufYSize &&
4✔
2325
            eSrcBandDT == eBufType && nPixelSpace == nSrcBandDTSize &&
4✔
2326
            nLineSpace == nPixelSpace * nBufXSize)
4✔
2327
        {
2328
            pabyWrkBuffer = static_cast<GByte *>(pData);
4✔
2329
        }
2330
        else
2331
        {
2332
            oWorkingState.m_abyWrkBuffer.resize(static_cast<size_t>(nOutXSize) *
9✔
2333
                                                nOutYSize * nSrcBandDTSize);
9✔
2334
            pabyWrkBuffer =
2335
                reinterpret_cast<GByte *>(oWorkingState.m_abyWrkBuffer.data());
9✔
2336
        }
2337
        oWorkingState.m_abyWrkBufferMask.resize(static_cast<size_t>(nOutXSize) *
13✔
2338
                                                nOutYSize * nSrcMaskBandDTSize);
13✔
2339
    }
2340
    catch (const std::exception &)
×
2341
    {
2342
        CPLError(CE_Failure, CPLE_OutOfMemory,
×
2343
                 "Out of memory when allocating buffers");
2344
        return CE_Failure;
×
2345
    }
2346

2347
    /* -------------------------------------------------------------------- */
2348
    /*      Load data.                                                      */
2349
    /* -------------------------------------------------------------------- */
2350
    if (!m_osResampling.empty())
13✔
2351
    {
2352
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
×
2353
    }
2354
    else if (psExtraArgIn != nullptr)
13✔
2355
    {
2356
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
13✔
2357
    }
2358

2359
    psExtraArg->bFloatingPointWindowValidity = TRUE;
13✔
2360
    psExtraArg->dfXOff = dfReqXOff;
13✔
2361
    psExtraArg->dfYOff = dfReqYOff;
13✔
2362
    psExtraArg->dfXSize = dfReqXSize;
13✔
2363
    psExtraArg->dfYSize = dfReqYSize;
13✔
2364
    if (psExtraArgIn)
13✔
2365
    {
2366
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
13✔
2367
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
13✔
2368
    }
2369

2370
    if (l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
13✔
2371
                         pabyWrkBuffer, nOutXSize, nOutYSize, eSrcBandDT, 0, 0,
2372
                         psExtraArg) != CE_None)
13✔
2373
    {
2374
        return CE_Failure;
×
2375
    }
2376

2377
    if (l_band->GetMaskBand()->RasterIO(
26✔
2378
            GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2379
            oWorkingState.m_abyWrkBufferMask.data(), nOutXSize, nOutYSize,
13✔
2380
            eSrcMaskBandDT, 0, 0, psExtraArg) != CE_None)
13✔
2381
    {
2382
        return CE_Failure;
×
2383
    }
2384

2385
    /* -------------------------------------------------------------------- */
2386
    /*      Do the processing.                                              */
2387
    /* -------------------------------------------------------------------- */
2388

2389
    GByte *const pabyOut = static_cast<GByte *>(pData) +
13✔
2390
                           nPixelSpace * nOutXOff +
13✔
2391
                           static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
13✔
2392
    if (bByteOptim)
13✔
2393
    {
2394
        // Special case when everything fits on Byte
2395
        const GByte nMaskValueThreshold =
4✔
2396
            static_cast<GByte>(m_dfMaskValueThreshold);
4✔
2397
        const GByte nNoDataValue = static_cast<GByte>(m_dfNoDataValue);
4✔
2398
        const GByte nRemappedValue = static_cast<GByte>(dfRemappedValue);
4✔
2399
        size_t nSrcIdx = 0;
4✔
2400
        for (int iY = 0; iY < nOutYSize; iY++)
8✔
2401
        {
2402
            GSpacing nDstOffset = iY * nLineSpace;
4✔
2403
            for (int iX = 0; iX < nOutXSize; iX++)
12✔
2404
            {
2405
                const GByte nMaskVal =
2406
                    oWorkingState.m_abyWrkBufferMask[nSrcIdx];
8✔
2407
                if (nMaskVal <= nMaskValueThreshold)
8✔
2408
                {
2409
                    pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] = nNoDataValue;
4✔
2410
                }
2411
                else
2412
                {
2413
                    if (pabyWrkBuffer[nSrcIdx] == nNoDataValue)
4✔
2414
                    {
2415
                        pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2✔
2416
                            nRemappedValue;
2417
                    }
2418
                    else
2419
                    {
2420
                        pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2✔
2421
                            pabyWrkBuffer[nSrcIdx];
2✔
2422
                    }
2423
                }
2424
                nDstOffset += nPixelSpace;
8✔
2425
                nSrcIdx++;
8✔
2426
            }
2427
        }
2428
    }
2429
    else
2430
    {
2431
        size_t nSrcIdx = 0;
9✔
2432
        double dfMaskVal = 0;
9✔
2433
        const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
9✔
2434
        std::vector<GByte> abyDstNoData(nBufDTSize);
18✔
2435
        GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, abyDstNoData.data(),
9✔
2436
                      eBufType, 0, 1);
2437
        std::vector<GByte> abyRemappedValue(nBufDTSize);
18✔
2438
        GDALCopyWords(&dfRemappedValue, GDT_Float64, 0, abyRemappedValue.data(),
9✔
2439
                      eBufType, 0, 1);
2440
        for (int iY = 0; iY < nOutYSize; iY++)
18✔
2441
        {
2442
            GSpacing nDstOffset = iY * nLineSpace;
9✔
2443
            for (int iX = 0; iX < nOutXSize; iX++)
28✔
2444
            {
2445
                if (eSrcMaskBandDT == GDT_Byte)
19✔
2446
                {
2447
                    dfMaskVal = oWorkingState.m_abyWrkBufferMask[nSrcIdx];
19✔
2448
                }
2449
                else
2450
                {
2451
                    GDALCopyWords(oWorkingState.m_abyWrkBufferMask.data() +
×
2452
                                      nSrcIdx * nSrcMaskBandDTSize,
×
2453
                                  eSrcMaskBandDT, 0, &dfMaskVal, GDT_Float64, 0,
2454
                                  1);
2455
                }
2456
                void *const pDst =
19✔
2457
                    pabyOut + static_cast<GPtrDiff_t>(nDstOffset);
19✔
2458
                if (!(dfMaskVal > m_dfMaskValueThreshold))
19✔
2459
                {
2460
                    memcpy(pDst, abyDstNoData.data(), nBufDTSize);
9✔
2461
                }
2462
                else
2463
                {
2464
                    const void *const pSrc =
10✔
2465
                        pabyWrkBuffer + nSrcIdx * nSrcBandDTSize;
10✔
2466
                    if (eSrcBandDT == eBufType)
10✔
2467
                    {
2468
                        // coverity[overrun-buffer-arg]
2469
                        memcpy(pDst, pSrc, nBufDTSize);
8✔
2470
                    }
2471
                    else
2472
                    {
2473
                        GDALCopyWords(pSrc, eSrcBandDT, 0, pDst, eBufType, 0,
2✔
2474
                                      1);
2475
                    }
2476
                    if (memcmp(pDst, abyDstNoData.data(), nBufDTSize) == 0)
10✔
2477
                        memcpy(pDst, abyRemappedValue.data(), nBufDTSize);
9✔
2478
                }
2479
                nDstOffset += nPixelSpace;
19✔
2480
                nSrcIdx++;
19✔
2481
            }
2482
        }
2483
    }
2484

2485
    if (psExtraArg->pfnProgress)
13✔
2486
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
×
2487

2488
    return CE_None;
13✔
2489
}
2490

2491
/************************************************************************/
2492
/*                             GetMinimum()                             */
2493
/************************************************************************/
2494

2495
double VRTNoDataFromMaskSource::GetMinimum(int /* nXSize */, int /* nYSize */,
×
2496
                                           int *pbSuccess)
2497
{
2498
    *pbSuccess = FALSE;
×
2499
    return 0.0;
×
2500
}
2501

2502
/************************************************************************/
2503
/*                             GetMaximum()                             */
2504
/************************************************************************/
2505

2506
double VRTNoDataFromMaskSource::GetMaximum(int /* nXSize */, int /* nYSize */,
×
2507
                                           int *pbSuccess)
2508
{
2509
    *pbSuccess = FALSE;
×
2510
    return 0.0;
×
2511
}
2512

2513
/************************************************************************/
2514
/*                            GetHistogram()                            */
2515
/************************************************************************/
2516

2517
CPLErr VRTNoDataFromMaskSource::GetHistogram(
×
2518
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2519
    int /* nBuckets */, GUIntBig * /* panHistogram */,
2520
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
2521
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2522
{
2523
    return CE_Failure;
×
2524
}
2525

2526
/************************************************************************/
2527
/* ==================================================================== */
2528
/*                          VRTComplexSource                            */
2529
/* ==================================================================== */
2530
/************************************************************************/
2531

2532
/************************************************************************/
2533
/*                          VRTComplexSource()                          */
2534
/************************************************************************/
2535

2536
VRTComplexSource::VRTComplexSource(const VRTComplexSource *poSrcSource,
5✔
2537
                                   double dfXDstRatio, double dfYDstRatio)
5✔
2538
    : VRTSimpleSource(poSrcSource, dfXDstRatio, dfYDstRatio),
2539
      m_nProcessingFlags(poSrcSource->m_nProcessingFlags),
5✔
2540
      m_dfNoDataValue(poSrcSource->m_dfNoDataValue),
5✔
2541
      m_osNoDataValueOri(poSrcSource->m_osNoDataValueOri),
5✔
2542
      m_dfScaleOff(poSrcSource->m_dfScaleOff),
5✔
2543
      m_dfScaleRatio(poSrcSource->m_dfScaleRatio),
5✔
2544
      m_bSrcMinMaxDefined(poSrcSource->m_bSrcMinMaxDefined),
5✔
2545
      m_dfSrcMin(poSrcSource->m_dfSrcMin), m_dfSrcMax(poSrcSource->m_dfSrcMax),
5✔
2546
      m_dfDstMin(poSrcSource->m_dfDstMin), m_dfDstMax(poSrcSource->m_dfDstMax),
5✔
2547
      m_dfExponent(poSrcSource->m_dfExponent),
5✔
2548
      m_nColorTableComponent(poSrcSource->m_nColorTableComponent),
5✔
2549
      m_adfLUTInputs(poSrcSource->m_adfLUTInputs),
5✔
2550
      m_adfLUTOutputs(poSrcSource->m_adfLUTOutputs)
5✔
2551
{
2552
}
5✔
2553

2554
/************************************************************************/
2555
/*                           GetTypeStatic()                            */
2556
/************************************************************************/
2557

2558
const char *VRTComplexSource::GetTypeStatic()
13,487✔
2559
{
2560
    static const char *TYPE = "ComplexSource";
2561
    return TYPE;
13,487✔
2562
}
2563

2564
/************************************************************************/
2565
/*                            GetType()                                 */
2566
/************************************************************************/
2567

2568
const char *VRTComplexSource::GetType() const
3,815✔
2569
{
2570
    return GetTypeStatic();
3,815✔
2571
}
2572

2573
/************************************************************************/
2574
/*                           SetNoDataValue()                           */
2575
/************************************************************************/
2576

2577
void VRTComplexSource::SetNoDataValue(double dfNewNoDataValue)
53✔
2578

2579
{
2580
    if (dfNewNoDataValue == VRT_NODATA_UNSET)
53✔
2581
    {
2582
        m_nProcessingFlags &= ~PROCESSING_FLAG_NODATA;
×
2583
        m_dfNoDataValue = VRT_NODATA_UNSET;
×
2584
        return;
×
2585
    }
2586

2587
    m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
53✔
2588
    m_dfNoDataValue = dfNewNoDataValue;
53✔
2589
}
2590

2591
/************************************************************************/
2592
/*                      GetAdjustedNoDataValue()                        */
2593
/************************************************************************/
2594

2595
double VRTComplexSource::GetAdjustedNoDataValue() const
4,714✔
2596
{
2597
    if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
4,714✔
2598
    {
2599
        auto l_band = GetRasterBand();
24✔
2600
        if (l_band && l_band->GetRasterDataType() == GDT_Float32)
24✔
2601
        {
2602
            return GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
9✔
2603
        }
2604
    }
2605
    return m_dfNoDataValue;
4,705✔
2606
}
2607

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

2612
CPLXMLNode *VRTComplexSource::SerializeToXML(const char *pszVRTPath)
65✔
2613

2614
{
2615
    CPLXMLNode *psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
65✔
2616

2617
    if (psSrc == nullptr)
65✔
2618
        return nullptr;
×
2619

2620
    CPLFree(psSrc->pszValue);
65✔
2621
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
65✔
2622

2623
    if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0)
65✔
2624
    {
2625
        CPLSetXMLValue(psSrc, "UseMaskBand", "true");
30✔
2626
    }
2627

2628
    if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
65✔
2629
    {
2630
        if (!m_osNoDataValueOri.empty() && GetRasterBandNoOpen() == nullptr)
25✔
2631
        {
2632
            CPLSetXMLValue(psSrc, "NODATA", m_osNoDataValueOri.c_str());
2✔
2633
        }
2634
        else
2635
        {
2636
            GDALDataType eBandDT = GDT_Unknown;
23✔
2637
            double dfNoDataValue = m_dfNoDataValue;
23✔
2638
            const auto kMaxFloat = std::numeric_limits<float>::max();
23✔
2639
            if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
23✔
2640
                1e-10 * kMaxFloat)
2641
            {
2642
                auto l_band = GetRasterBand();
1✔
2643
                if (l_band)
1✔
2644
                {
2645
                    dfNoDataValue = GetAdjustedNoDataValue();
1✔
2646
                    eBandDT = l_band->GetRasterDataType();
1✔
2647
                }
2648
            }
2649
            CPLSetXMLValue(
23✔
2650
                psSrc, "NODATA",
2651
                VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
46✔
2652
        }
2653
    }
2654

2655
    if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
65✔
2656
    {
2657
        CPLSetXMLValue(psSrc, "ScaleOffset", CPLSPrintf("%g", m_dfScaleOff));
1✔
2658
        CPLSetXMLValue(psSrc, "ScaleRatio", CPLSPrintf("%g", m_dfScaleRatio));
1✔
2659
    }
2660
    else if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
64✔
2661
    {
2662
        CPLSetXMLValue(psSrc, "Exponent", CPLSPrintf("%g", m_dfExponent));
×
2663
        if (m_bSrcMinMaxDefined)
×
2664
        {
2665
            CPLSetXMLValue(psSrc, "SrcMin", CPLSPrintf("%g", m_dfSrcMin));
×
2666
            CPLSetXMLValue(psSrc, "SrcMax", CPLSPrintf("%g", m_dfSrcMax));
×
2667
        }
2668
        CPLSetXMLValue(psSrc, "DstMin", CPLSPrintf("%g", m_dfDstMin));
×
2669
        CPLSetXMLValue(psSrc, "DstMax", CPLSPrintf("%g", m_dfDstMax));
×
2670
    }
2671

2672
    if (!m_adfLUTInputs.empty())
65✔
2673
    {
2674
        // Make sure we print with sufficient precision to address really close
2675
        // entries (#6422).
2676
        CPLString osLUT;
×
2677
        if (m_adfLUTInputs.size() >= 2 &&
×
2678
            CPLString().Printf("%g", m_adfLUTInputs[0]) ==
×
2679
                CPLString().Printf("%g", m_adfLUTInputs[1]))
×
2680
        {
2681
            osLUT = CPLString().Printf("%.17g:%g", m_adfLUTInputs[0],
×
2682
                                       m_adfLUTOutputs[0]);
×
2683
        }
2684
        else
2685
        {
2686
            osLUT = CPLString().Printf("%g:%g", m_adfLUTInputs[0],
×
2687
                                       m_adfLUTOutputs[0]);
×
2688
        }
2689
        for (size_t i = 1; i < m_adfLUTInputs.size(); i++)
×
2690
        {
2691
            if (CPLString().Printf("%g", m_adfLUTInputs[i]) ==
×
2692
                    CPLString().Printf("%g", m_adfLUTInputs[i - 1]) ||
×
2693
                (i + 1 < m_adfLUTInputs.size() &&
×
2694
                 CPLString().Printf("%g", m_adfLUTInputs[i]) ==
×
2695
                     CPLString().Printf("%g", m_adfLUTInputs[i + 1])))
×
2696
            {
2697
                // TODO(schwehr): An explanation of the 18 would be helpful.
2698
                // Can someone distill the issue down to a quick comment?
2699
                // https://trac.osgeo.org/gdal/ticket/6422
2700
                osLUT += CPLString().Printf(",%.17g:%g", m_adfLUTInputs[i],
×
2701
                                            m_adfLUTOutputs[i]);
×
2702
            }
2703
            else
2704
            {
2705
                osLUT += CPLString().Printf(",%g:%g", m_adfLUTInputs[i],
×
2706
                                            m_adfLUTOutputs[i]);
×
2707
            }
2708
        }
2709
        CPLSetXMLValue(psSrc, "LUT", osLUT);
×
2710
    }
2711

2712
    if (m_nColorTableComponent)
65✔
2713
    {
2714
        CPLSetXMLValue(psSrc, "ColorTableComponent",
7✔
2715
                       CPLSPrintf("%d", m_nColorTableComponent));
2716
    }
2717

2718
    return psSrc;
65✔
2719
}
2720

2721
/************************************************************************/
2722
/*                              XMLInit()                               */
2723
/************************************************************************/
2724

2725
CPLErr VRTComplexSource::XMLInit(const CPLXMLNode *psSrc,
217✔
2726
                                 const char *pszVRTPath,
2727
                                 VRTMapSharedResources &oMapSharedSources)
2728

2729
{
2730
    /* -------------------------------------------------------------------- */
2731
    /*      Do base initialization.                                         */
2732
    /* -------------------------------------------------------------------- */
2733
    {
2734
        const CPLErr eErr =
2735
            VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
217✔
2736
        if (eErr != CE_None)
217✔
2737
            return eErr;
×
2738
    }
2739

2740
    /* -------------------------------------------------------------------- */
2741
    /*      Complex parameters.                                             */
2742
    /* -------------------------------------------------------------------- */
2743
    const char *pszScaleOffset = CPLGetXMLValue(psSrc, "ScaleOffset", nullptr);
217✔
2744
    const char *pszScaleRatio = CPLGetXMLValue(psSrc, "ScaleRatio", nullptr);
217✔
2745
    if (pszScaleOffset || pszScaleRatio)
217✔
2746
    {
2747
        m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
18✔
2748
        if (pszScaleOffset)
18✔
2749
            m_dfScaleOff = CPLAtof(pszScaleOffset);
18✔
2750
        if (pszScaleRatio)
18✔
2751
            m_dfScaleRatio = CPLAtof(pszScaleRatio);
15✔
2752
    }
2753
    else if (CPLGetXMLValue(psSrc, "Exponent", nullptr) != nullptr &&
199✔
2754
             CPLGetXMLValue(psSrc, "DstMin", nullptr) != nullptr &&
200✔
2755
             CPLGetXMLValue(psSrc, "DstMax", nullptr) != nullptr)
1✔
2756
    {
2757
        m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
1✔
2758
        m_dfExponent = CPLAtof(CPLGetXMLValue(psSrc, "Exponent", "1.0"));
1✔
2759

2760
        const char *pszSrcMin = CPLGetXMLValue(psSrc, "SrcMin", nullptr);
1✔
2761
        const char *pszSrcMax = CPLGetXMLValue(psSrc, "SrcMax", nullptr);
1✔
2762
        if (pszSrcMin && pszSrcMax)
1✔
2763
        {
2764
            m_dfSrcMin = CPLAtof(pszSrcMin);
×
2765
            m_dfSrcMax = CPLAtof(pszSrcMax);
×
2766
            m_bSrcMinMaxDefined = true;
×
2767
        }
2768

2769
        m_dfDstMin = CPLAtof(CPLGetXMLValue(psSrc, "DstMin", "0.0"));
1✔
2770
        m_dfDstMax = CPLAtof(CPLGetXMLValue(psSrc, "DstMax", "0.0"));
1✔
2771
    }
2772

2773
    if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
217✔
2774
    {
2775
        m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
50✔
2776
        m_osNoDataValueOri = pszNODATA;
50✔
2777
        m_dfNoDataValue = CPLAtofM(m_osNoDataValueOri.c_str());
50✔
2778
    }
2779

2780
    const char *pszUseMaskBand = CPLGetXMLValue(psSrc, "UseMaskBand", nullptr);
217✔
2781
    if (pszUseMaskBand && CPLTestBool(pszUseMaskBand))
217✔
2782
    {
2783
        m_nProcessingFlags |= PROCESSING_FLAG_USE_MASK_BAND;
38✔
2784
    }
2785

2786
    const char *pszLUT = CPLGetXMLValue(psSrc, "LUT", nullptr);
217✔
2787
    if (pszLUT)
217✔
2788
    {
2789
        const CPLStringList aosValues(
2790
            CSLTokenizeString2(pszLUT, ",:", CSLT_ALLOWEMPTYTOKENS));
59✔
2791

2792
        const int nLUTItemCount = aosValues.size() / 2;
59✔
2793
        try
2794
        {
2795
            m_adfLUTInputs.resize(nLUTItemCount);
59✔
2796
            m_adfLUTOutputs.resize(nLUTItemCount);
59✔
2797
        }
2798
        catch (const std::bad_alloc &e)
×
2799
        {
2800
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
2801
            m_adfLUTInputs.clear();
×
2802
            m_adfLUTOutputs.clear();
×
2803
            return CE_Failure;
×
2804
        }
2805

2806
        for (int nIndex = 0; nIndex < nLUTItemCount; nIndex++)
544✔
2807
        {
2808
            m_adfLUTInputs[nIndex] = CPLAtof(aosValues[nIndex * 2]);
485✔
2809
            m_adfLUTOutputs[nIndex] = CPLAtof(aosValues[nIndex * 2 + 1]);
485✔
2810

2811
            // Enforce the requirement that the LUT input array is
2812
            // monotonically non-decreasing.
2813
            if (std::isnan(m_adfLUTInputs[nIndex]) && nIndex != 0)
485✔
2814
            {
2815
                CPLError(CE_Failure, CPLE_AppDefined,
×
2816
                         "A Not-A-Number (NaN) source value should be the "
2817
                         "first one of the LUT.");
2818
                m_adfLUTInputs.clear();
×
2819
                m_adfLUTOutputs.clear();
×
2820
                return CE_Failure;
×
2821
            }
2822
            else if (nIndex > 0 &&
911✔
2823
                     m_adfLUTInputs[nIndex] < m_adfLUTInputs[nIndex - 1])
426✔
2824
            {
2825
                CPLError(CE_Failure, CPLE_AppDefined,
×
2826
                         "Source values of the LUT are not listed in a "
2827
                         "monotonically non-decreasing order");
2828
                m_adfLUTInputs.clear();
×
2829
                m_adfLUTOutputs.clear();
×
2830
                return CE_Failure;
×
2831
            }
2832
        }
2833

2834
        m_nProcessingFlags |= PROCESSING_FLAG_LUT;
59✔
2835
    }
2836

2837
    const char *pszColorTableComponent =
2838
        CPLGetXMLValue(psSrc, "ColorTableComponent", nullptr);
217✔
2839
    if (pszColorTableComponent)
217✔
2840
    {
2841
        m_nColorTableComponent = atoi(pszColorTableComponent);
15✔
2842
        m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
15✔
2843
    }
2844

2845
    return CE_None;
217✔
2846
}
2847

2848
/************************************************************************/
2849
/*                              LookupValue()                           */
2850
/************************************************************************/
2851

2852
double VRTComplexSource::LookupValue(double dfInput)
583,336✔
2853
{
2854
    auto beginIter = m_adfLUTInputs.begin();
583,336✔
2855
    auto endIter = m_adfLUTInputs.end();
583,336✔
2856
    size_t offset = 0;
583,336✔
2857
    if (std::isnan(m_adfLUTInputs[0]))
583,336✔
2858
    {
2859
        if (std::isnan(dfInput) || m_adfLUTInputs.size() == 1)
6✔
2860
            return m_adfLUTOutputs[0];
1✔
2861
        ++beginIter;
5✔
2862
        offset = 1;
5✔
2863
    }
2864

2865
    // Find the index of the first element in the LUT input array that
2866
    // is not smaller than the input value.
2867
    const size_t i =
2868
        offset +
2869
        std::distance(beginIter, std::lower_bound(beginIter, endIter, dfInput));
583,335✔
2870

2871
    if (i == offset)
583,335✔
2872
        return m_adfLUTOutputs[offset];
129,039✔
2873

2874
    // If the index is beyond the end of the LUT input array, the input
2875
    // value is larger than all the values in the array.
2876
    if (i == m_adfLUTInputs.size())
454,296✔
2877
        return m_adfLUTOutputs.back();
8✔
2878

2879
    if (m_adfLUTInputs[i] == dfInput)
454,288✔
2880
        return m_adfLUTOutputs[i];
179,297✔
2881

2882
    // Otherwise, interpolate.
2883
    return m_adfLUTOutputs[i - 1] +
274,991✔
2884
           (dfInput - m_adfLUTInputs[i - 1]) *
274,991✔
2885
               ((m_adfLUTOutputs[i] - m_adfLUTOutputs[i - 1]) /
274,991✔
2886
                (m_adfLUTInputs[i] - m_adfLUTInputs[i - 1]));
274,991✔
2887
}
2888

2889
/************************************************************************/
2890
/*                         SetLinearScaling()                           */
2891
/************************************************************************/
2892

2893
void VRTComplexSource::SetLinearScaling(double dfOffset, double dfScale)
88✔
2894
{
2895
    m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_EXPONENTIAL;
88✔
2896
    m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
88✔
2897
    m_dfScaleOff = dfOffset;
88✔
2898
    m_dfScaleRatio = dfScale;
88✔
2899
}
88✔
2900

2901
/************************************************************************/
2902
/*                         SetPowerScaling()                           */
2903
/************************************************************************/
2904

2905
void VRTComplexSource::SetPowerScaling(double dfExponentIn, double dfSrcMinIn,
8✔
2906
                                       double dfSrcMaxIn, double dfDstMinIn,
2907
                                       double dfDstMaxIn)
2908
{
2909
    m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_LINEAR;
8✔
2910
    m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
8✔
2911
    m_dfExponent = dfExponentIn;
8✔
2912
    m_dfSrcMin = dfSrcMinIn;
8✔
2913
    m_dfSrcMax = dfSrcMaxIn;
8✔
2914
    m_dfDstMin = dfDstMinIn;
8✔
2915
    m_dfDstMax = dfDstMaxIn;
8✔
2916
    m_bSrcMinMaxDefined = true;
8✔
2917
}
8✔
2918

2919
/************************************************************************/
2920
/*                    SetColorTableComponent()                          */
2921
/************************************************************************/
2922

2923
void VRTComplexSource::SetColorTableComponent(int nComponent)
174✔
2924
{
2925
    m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
174✔
2926
    m_nColorTableComponent = nComponent;
174✔
2927
}
174✔
2928

2929
/************************************************************************/
2930
/*                              RasterIO()                              */
2931
/************************************************************************/
2932

2933
CPLErr VRTComplexSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
15,691✔
2934
                                  int nYOff, int nXSize, int nYSize,
2935
                                  void *pData, int nBufXSize, int nBufYSize,
2936
                                  GDALDataType eBufType, GSpacing nPixelSpace,
2937
                                  GSpacing nLineSpace,
2938
                                  GDALRasterIOExtraArg *psExtraArgIn,
2939
                                  WorkingState &oWorkingState)
2940

2941
{
2942
    GDALRasterIOExtraArg sExtraArg;
2943
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
15,691✔
2944
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
15,691✔
2945

2946
    double dfXOff = nXOff;
15,691✔
2947
    double dfYOff = nYOff;
15,691✔
2948
    double dfXSize = nXSize;
15,691✔
2949
    double dfYSize = nYSize;
15,691✔
2950
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
15,691✔
2951
    {
2952
        dfXOff = psExtraArgIn->dfXOff;
87✔
2953
        dfYOff = psExtraArgIn->dfYOff;
87✔
2954
        dfXSize = psExtraArgIn->dfXSize;
87✔
2955
        dfYSize = psExtraArgIn->dfYSize;
87✔
2956
    }
2957

2958
    // The window we will actually request from the source raster band.
2959
    double dfReqXOff = 0.0;
15,691✔
2960
    double dfReqYOff = 0.0;
15,691✔
2961
    double dfReqXSize = 0.0;
15,691✔
2962
    double dfReqYSize = 0.0;
15,691✔
2963
    int nReqXOff = 0;
15,691✔
2964
    int nReqYOff = 0;
15,691✔
2965
    int nReqXSize = 0;
15,691✔
2966
    int nReqYSize = 0;
15,691✔
2967

2968
    // The window we will actual set _within_ the pData buffer.
2969
    int nOutXOff = 0;
15,691✔
2970
    int nOutYOff = 0;
15,691✔
2971
    int nOutXSize = 0;
15,691✔
2972
    int nOutYSize = 0;
15,691✔
2973

2974
    bool bError = false;
15,691✔
2975
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
15,691✔
2976
                         &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize,
2977
                         &nReqXOff, &nReqYOff, &nReqXSize, &nReqYSize,
2978
                         &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize, bError))
2979
    {
2980
        return bError ? CE_Failure : CE_None;
10,946✔
2981
    }
2982
#if DEBUG_VERBOSE
2983
    CPLDebug("VRT",
2984
             "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
2985
             "nBufYSize=%d,\n"
2986
             "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
2987
             "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
2988
             "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
2989
             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
2990
             dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
2991
             nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
2992
#endif
2993

2994
    auto poSourceBand = GetRasterBand();
4,745✔
2995
    if (!poSourceBand)
4,745✔
2996
        return CE_Failure;
×
2997

2998
    if (!m_osResampling.empty())
4,745✔
2999
    {
3000
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
28✔
3001
    }
3002
    else if (psExtraArgIn != nullptr)
4,717✔
3003
    {
3004
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
4,717✔
3005
    }
3006
    psExtraArg->bFloatingPointWindowValidity = TRUE;
4,745✔
3007
    psExtraArg->dfXOff = dfReqXOff;
4,745✔
3008
    psExtraArg->dfYOff = dfReqYOff;
4,745✔
3009
    psExtraArg->dfXSize = dfReqXSize;
4,745✔
3010
    psExtraArg->dfYSize = dfReqYSize;
4,745✔
3011
    if (psExtraArgIn)
4,745✔
3012
    {
3013
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
4,745✔
3014
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
4,745✔
3015
    }
3016

3017
    GByte *const pabyOut = static_cast<GByte *>(pData) +
4,745✔
3018
                           nPixelSpace * nOutXOff +
4,745✔
3019
                           static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
4,745✔
3020
    const auto eSourceType = poSourceBand->GetRasterDataType();
4,745✔
3021
    if (m_nProcessingFlags == PROCESSING_FLAG_NODATA)
4,745✔
3022
    {
3023
        // Optimization if doing only nodata processing
3024
        if (eSourceType == GDT_Byte)
65✔
3025
        {
3026
            if (!GDALIsValueInRange<GByte>(m_dfNoDataValue))
36✔
3027
            {
3028
                return VRTSimpleSource::RasterIO(
1✔
3029
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3030
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3031
                    psExtraArgIn, oWorkingState);
1✔
3032
            }
3033

3034
            return RasterIOProcessNoData<GByte, GDT_Byte>(
35✔
3035
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3036
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3037
                nLineSpace, psExtraArg, oWorkingState);
35✔
3038
        }
3039
        else if (eSourceType == GDT_Int16)
29✔
3040
        {
3041
            if (!GDALIsValueInRange<int16_t>(m_dfNoDataValue))
2✔
3042
            {
3043
                return VRTSimpleSource::RasterIO(
1✔
3044
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3045
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3046
                    psExtraArgIn, oWorkingState);
1✔
3047
            }
3048

3049
            return RasterIOProcessNoData<int16_t, GDT_Int16>(
1✔
3050
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3051
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3052
                nLineSpace, psExtraArg, oWorkingState);
1✔
3053
        }
3054
        else if (eSourceType == GDT_UInt16)
27✔
3055
        {
3056
            if (!GDALIsValueInRange<uint16_t>(m_dfNoDataValue))
8✔
3057
            {
3058
                return VRTSimpleSource::RasterIO(
1✔
3059
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3060
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3061
                    psExtraArgIn, oWorkingState);
1✔
3062
            }
3063

3064
            return RasterIOProcessNoData<uint16_t, GDT_UInt16>(
7✔
3065
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3066
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3067
                nLineSpace, psExtraArg, oWorkingState);
7✔
3068
        }
3069
    }
3070

3071
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
4,699✔
3072
    CPLErr eErr;
3073
    // For Int32, float32 isn't sufficiently precise as working data type
3074
    if (eVRTBandDataType == GDT_CInt32 || eVRTBandDataType == GDT_CFloat64 ||
4,699✔
3075
        eVRTBandDataType == GDT_Int32 || eVRTBandDataType == GDT_UInt32 ||
4,697✔
3076
        eVRTBandDataType == GDT_Int64 || eVRTBandDataType == GDT_UInt64 ||
4,695✔
3077
        eVRTBandDataType == GDT_Float64 || eSourceType == GDT_Int32 ||
4,690✔
3078
        eSourceType == GDT_UInt32 || eSourceType == GDT_Int64 ||
4,689✔
3079
        eSourceType == GDT_UInt64)
3080
    {
3081
        eErr = RasterIOInternal<double>(
11✔
3082
            poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3083
            nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3084
            nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat64 : GDT_Float64,
3085
            oWorkingState);
3086
    }
3087
    else
3088
    {
3089
        eErr = RasterIOInternal<float>(
4,688✔
3090
            poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3091
            nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3092
            nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32,
3093
            oWorkingState);
3094
    }
3095

3096
    if (psExtraArg->pfnProgress)
4,699✔
3097
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
44✔
3098

3099
    return eErr;
4,699✔
3100
}
3101

3102
/************************************************************************/
3103
/*                              hasZeroByte()                           */
3104
/************************************************************************/
3105

3106
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
3107
static inline bool hasZeroByte(uint32_t v)
3,838,620✔
3108
{
3109
    // Cf https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
3110
    return (((v)-0x01010101U) & ~(v)&0x80808080U) != 0;
3,838,620✔
3111
}
3112

3113
/************************************************************************/
3114
/*                                CopyWord()                            */
3115
/************************************************************************/
3116

3117
template <class SrcType>
3118
static void CopyWord(const SrcType *pSrcVal, GDALDataType eSrcType,
6,418,880✔
3119
                     void *pDstVal, GDALDataType eDstType)
3120
{
3121
    switch (eDstType)
6,418,880✔
3122
    {
3123
        case GDT_Byte:
2,145,060✔
3124
            GDALCopyWord(*pSrcVal, *static_cast<uint8_t *>(pDstVal));
2,145,060✔
3125
            break;
2,145,060✔
3126
        case GDT_Int8:
80✔
3127
            GDALCopyWord(*pSrcVal, *static_cast<int8_t *>(pDstVal));
80✔
3128
            break;
80✔
3129
        case GDT_UInt16:
1,348,720✔
3130
            GDALCopyWord(*pSrcVal, *static_cast<uint16_t *>(pDstVal));
1,348,720✔
3131
            break;
1,348,720✔
3132
        case GDT_Int16:
2,920,180✔
3133
            GDALCopyWord(*pSrcVal, *static_cast<int16_t *>(pDstVal));
2,920,180✔
3134
            break;
2,920,180✔
3135
        case GDT_UInt32:
20✔
3136
            GDALCopyWord(*pSrcVal, *static_cast<uint32_t *>(pDstVal));
20✔
3137
            break;
20✔
3138
        case GDT_Int32:
638✔
3139
            GDALCopyWord(*pSrcVal, *static_cast<int32_t *>(pDstVal));
638✔
3140
            break;
638✔
3141
        case GDT_UInt64:
20✔
3142
            GDALCopyWord(*pSrcVal, *static_cast<uint64_t *>(pDstVal));
20✔
3143
            break;
20✔
3144
        case GDT_Int64:
40✔
3145
            GDALCopyWord(*pSrcVal, *static_cast<int64_t *>(pDstVal));
40✔
3146
            break;
40✔
3147
        case GDT_Float32:
1,650✔
3148
            GDALCopyWord(*pSrcVal, *static_cast<float *>(pDstVal));
1,650✔
3149
            break;
1,650✔
3150
        case GDT_Float64:
1,461✔
3151
            GDALCopyWord(*pSrcVal, *static_cast<double *>(pDstVal));
1,461✔
3152
            break;
1,461✔
3153
        default:
1,016✔
3154
            GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1);
1,016✔
3155
            break;
1,016✔
3156
    }
3157
}
6,418,880✔
3158

3159
/************************************************************************/
3160
/*                       RasterIOProcessNoData()                        */
3161
/************************************************************************/
3162

3163
// This method is an optimization of the generic RasterIOInternal()
3164
// that deals with a VRTComplexSource with only a NODATA value in it, and
3165
// no other processing flags.
3166

3167
// nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3168
// referential.
3169
template <class SourceDT, GDALDataType eSourceType>
3170
CPLErr VRTComplexSource::RasterIOProcessNoData(
43✔
3171
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3172
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3173
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3174
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3175
    WorkingState &oWorkingState)
3176
{
3177
    CPLAssert(m_nProcessingFlags == PROCESSING_FLAG_NODATA);
43✔
3178
    CPLAssert(GDALIsValueInRange<SourceDT>(m_dfNoDataValue));
43✔
3179

3180
    /* -------------------------------------------------------------------- */
3181
    /*      Read into a temporary buffer.                                   */
3182
    /* -------------------------------------------------------------------- */
3183
    try
3184
    {
3185
        // Cannot overflow since pData should at least have that number of
3186
        // elements
3187
        const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
43✔
3188
        if (nPixelCount >
43✔
3189
            static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
43✔
3190
                sizeof(SourceDT))
3191
        {
3192
            CPLError(CE_Failure, CPLE_OutOfMemory,
×
3193
                     "Too large temporary buffer");
3194
            return CE_Failure;
×
3195
        }
3196
        oWorkingState.m_abyWrkBuffer.resize(sizeof(SourceDT) * nPixelCount);
43✔
3197
    }
3198
    catch (const std::bad_alloc &e)
×
3199
    {
3200
        CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
3201
        return CE_Failure;
×
3202
    }
3203
    const auto paSrcData =
3204
        reinterpret_cast<const SourceDT *>(oWorkingState.m_abyWrkBuffer.data());
43✔
3205

3206
    const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
43✔
3207
    if (!m_osResampling.empty())
43✔
3208
    {
3209
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
×
3210
    }
3211

3212
    const CPLErr eErr = poSourceBand->RasterIO(
43✔
3213
        GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3214
        oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize, eSourceType,
43✔
3215
        sizeof(SourceDT), sizeof(SourceDT) * static_cast<GSpacing>(nOutXSize),
8✔
3216
        psExtraArg);
3217
    if (!m_osResampling.empty())
43✔
3218
        psExtraArg->eResampleAlg = eResampleAlgBack;
×
3219

3220
    if (eErr != CE_None)
43✔
3221
    {
3222
        return eErr;
×
3223
    }
3224

3225
    const auto nNoDataValue = static_cast<SourceDT>(m_dfNoDataValue);
43✔
3226
    size_t idxBuffer = 0;
43✔
3227
    if (eSourceType == eBufType &&
74✔
3228
        !GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
31✔
3229
    {
3230
        // Most optimized case: the output type is the same as the source type,
3231
        // and conversion from the source type to the VRT band data type is
3232
        // not lossy
3233
        for (int iY = 0; iY < nOutYSize; iY++)
14✔
3234
        {
3235
            GByte *pDstLocation = static_cast<GByte *>(pData) +
19,607✔
3236
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
19,607✔
3237

3238
            int iX = 0;
19,607✔
3239
            if (sizeof(SourceDT) == 1 && nPixelSpace == 1)
19,595✔
3240
            {
3241
                // Optimization to detect more quickly if source pixels are
3242
                // at nodata.
3243
                const GByte byNoDataValue = static_cast<GByte>(nNoDataValue);
19,596✔
3244
                const uint32_t wordNoData =
19,596✔
3245
                    (static_cast<uint32_t>(byNoDataValue) << 24) |
19,596✔
3246
                    (byNoDataValue << 16) | (byNoDataValue << 8) |
19,596✔
3247
                    byNoDataValue;
19,596✔
3248

3249
                // Warning: hasZeroByte() assumes WORD_SIZE = 4
3250
                constexpr int WORD_SIZE = 4;
19,596✔
3251
                for (; iX < nOutXSize - (WORD_SIZE - 1); iX += WORD_SIZE)
3,862,740✔
3252
                {
3253
                    uint32_t v;
3254
                    static_assert(sizeof(v) == WORD_SIZE,
3255
                                  "sizeof(v) == WORD_SIZE");
3256
                    memcpy(&v, paSrcData + idxBuffer, sizeof(v));
3,993,120✔
3257
                    // Cf https://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
3258
                    if (!hasZeroByte(v ^ wordNoData))
3,993,120✔
3259
                    {
3260
                        // No bytes are at nodata
3261
                        memcpy(pDstLocation, &v, WORD_SIZE);
3,772,770✔
3262
                        idxBuffer += WORD_SIZE;
3,772,770✔
3263
                        pDstLocation += WORD_SIZE;
3,772,770✔
3264
                    }
3265
                    else if (v == wordNoData)
70,377✔
3266
                    {
3267
                        // All bytes are at nodata
3268
                        idxBuffer += WORD_SIZE;
131,075✔
3269
                        pDstLocation += WORD_SIZE;
131,075✔
3270
                    }
3271
                    else
3272
                    {
3273
                        // There are both bytes at nodata and valid bytes
3274
                        for (int k = 0; k < WORD_SIZE; ++k)
×
3275
                        {
3276
                            if (paSrcData[idxBuffer] != nNoDataValue)
48✔
3277
                            {
3278
                                memcpy(pDstLocation, &paSrcData[idxBuffer],
36✔
3279
                                       sizeof(SourceDT));
3280
                            }
3281
                            idxBuffer++;
48✔
3282
                            pDstLocation += nPixelSpace;
48✔
3283
                        }
3284
                    }
3285
                }
3286
            }
3287

3288
            for (; iX < nOutXSize;
72✔
3289
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
3,709✔
3290
            {
3291
                if (paSrcData[idxBuffer] != nNoDataValue)
3,709✔
3292
                {
3293
                    memcpy(pDstLocation, &paSrcData[idxBuffer],
3,679✔
3294
                           sizeof(SourceDT));
3295
                }
3296
            }
3297
        }
3298
    }
3299
    else if (!GDALDataTypeIsConversionLossy(eSourceType, eVRTBandDataType))
13✔
3300
    {
3301
        // Conversion from the source type to the VRT band data type is
3302
        // not lossy, so we can directly convert from the source type to
3303
        // the the output type
3304
        for (int iY = 0; iY < nOutYSize; iY++)
106✔
3305
        {
3306
            GByte *pDstLocation = static_cast<GByte *>(pData) +
94✔
3307
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
94✔
3308

3309
            for (int iX = 0; iX < nOutXSize;
1,556✔
3310
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
1,462✔
3311
            {
3312
                if (paSrcData[idxBuffer] != nNoDataValue)
1,462✔
3313
                {
3314
                    CopyWord(&paSrcData[idxBuffer], eSourceType, pDstLocation,
658✔
3315
                             eBufType);
3316
                }
3317
            }
3318
        }
3319
    }
3320
    else
3321
    {
3322
        GByte abyTemp[2 * sizeof(double)];
3323
        for (int iY = 0; iY < nOutYSize; iY++)
7✔
3324
        {
3325
            GByte *pDstLocation = static_cast<GByte *>(pData) +
6✔
3326
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
6✔
3327

3328
            for (int iX = 0; iX < nOutXSize;
36✔
3329
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
30✔
3330
            {
3331
                if (paSrcData[idxBuffer] != nNoDataValue)
30✔
3332
                {
3333
                    // Convert first to the VRTRasterBand data type
3334
                    // to get its clamping, before outputting to buffer data type
3335
                    CopyWord(&paSrcData[idxBuffer], eSourceType, abyTemp,
20✔
3336
                             eVRTBandDataType);
3337
                    GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
20✔
3338
                                  eBufType, 0, 1);
3339
                }
3340
            }
3341
        }
3342
    }
3343

3344
    return CE_None;
8✔
3345
}
3346

3347
/************************************************************************/
3348
/*                          RasterIOInternal()                          */
3349
/************************************************************************/
3350

3351
// nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3352
// referential.
3353
template <class WorkingDT>
3354
CPLErr VRTComplexSource::RasterIOInternal(
4,713✔
3355
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3356
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3357
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3358
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3359
    GDALDataType eWrkDataType, WorkingState &oWorkingState)
3360
{
3361
    const GDALColorTable *poColorTable = nullptr;
4,713✔
3362
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
4,713✔
3363
    const int nWordSize = GDALGetDataTypeSizeBytes(eWrkDataType);
4,713✔
3364
    assert(nWordSize != 0);
4,713✔
3365

3366
    // If no explicit <NODATA> is set, but UseMaskBand is set, and the band
3367
    // has a nodata value, then use it as if it was set as <NODATA>
3368
    int bNoDataSet = (m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0;
4,713✔
3369
    double dfNoDataValue = GetAdjustedNoDataValue();
4,713✔
3370

3371
    if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
4,816✔
3372
        poSourceBand->GetMaskFlags() == GMF_NODATA)
103✔
3373
    {
3374
        dfNoDataValue = poSourceBand->GetNoDataValue(&bNoDataSet);
×
3375
    }
3376

3377
    const bool bNoDataSetIsNan = bNoDataSet && std::isnan(dfNoDataValue);
4,713✔
3378
    const bool bNoDataSetAndNotNan =
4,713✔
3379
        bNoDataSet && !std::isnan(dfNoDataValue) &&
4,734✔
3380
        GDALIsValueInRange<WorkingDT>(dfNoDataValue);
21✔
3381
    const auto fWorkingDataTypeNoData = static_cast<WorkingDT>(dfNoDataValue);
4,713✔
3382

3383
    const GByte *pabyMask = nullptr;
4,713✔
3384
    const WorkingDT *pafData = nullptr;
4,713✔
3385
    if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0 &&
4,713✔
3386
        m_dfScaleRatio == 0 && bNoDataSet == FALSE &&
4,423✔
3387
        (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) == 0)
4,041✔
3388
    {
3389
        /* ------------------------------------------------------------------ */
3390
        /*      Optimization when writing a constant value */
3391
        /*      (used by the -addalpha option of gdalbuildvrt) */
3392
        /* ------------------------------------------------------------------ */
3393
        // Already set to NULL when defined.
3394
        // pafData = NULL;
3395
    }
3396
    else
3397
    {
3398
        /* ---------------------------------------------------------------- */
3399
        /*      Read into a temporary buffer.                               */
3400
        /* ---------------------------------------------------------------- */
3401
        const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
672✔
3402
        try
3403
        {
3404
            // Cannot overflow since pData should at least have that number of
3405
            // elements
3406
            if (nPixelCount >
672✔
3407
                static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
672✔
3408
                    static_cast<size_t>(nWordSize))
672✔
3409
            {
3410
                CPLError(CE_Failure, CPLE_OutOfMemory,
×
3411
                         "Too large temporary buffer");
3412
                return CE_Failure;
×
3413
            }
3414
            oWorkingState.m_abyWrkBuffer.resize(nWordSize * nPixelCount);
672✔
3415
        }
3416
        catch (const std::bad_alloc &e)
×
3417
        {
3418
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
×
3419
            return CE_Failure;
×
3420
        }
3421
        pafData = reinterpret_cast<const WorkingDT *>(
3422
            oWorkingState.m_abyWrkBuffer.data());
672✔
3423

3424
        const GDALRIOResampleAlg eResampleAlgBack = psExtraArg->eResampleAlg;
672✔
3425
        if (!m_osResampling.empty())
672✔
3426
        {
3427
            psExtraArg->eResampleAlg =
28✔
3428
                GDALRasterIOGetResampleAlg(m_osResampling);
28✔
3429
        }
3430

3431
        const CPLErr eErr = poSourceBand->RasterIO(
672✔
3432
            GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3433
            oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize,
672✔
3434
            eWrkDataType, nWordSize,
3435
            nWordSize * static_cast<GSpacing>(nOutXSize), psExtraArg);
672✔
3436
        if (!m_osResampling.empty())
672✔
3437
            psExtraArg->eResampleAlg = eResampleAlgBack;
28✔
3438

3439
        if (eErr != CE_None)
672✔
3440
        {
3441
            return eErr;
×
3442
        }
3443

3444
        // Allocate and read mask band if needed
3445
        if (!bNoDataSet &&
1,993✔
3446
            (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
775✔
3447
            (poSourceBand->GetMaskFlags() != GMF_ALL_VALID ||
103✔
3448
             poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
51✔
3449
             GetMaskBandMainBand() != nullptr))
31✔
3450
        {
3451
            try
3452
            {
3453
                oWorkingState.m_abyWrkBufferMask.resize(nPixelCount);
103✔
3454
            }
3455
            catch (const std::exception &)
×
3456
            {
3457
                CPLError(CE_Failure, CPLE_OutOfMemory,
×
3458
                         "Out of memory when allocating mask buffer");
3459
                return CE_Failure;
×
3460
            }
3461
            pabyMask = reinterpret_cast<const GByte *>(
3462
                oWorkingState.m_abyWrkBufferMask.data());
103✔
3463
            auto poMaskBand =
51✔
3464
                (poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
103✔
3465
                 GetMaskBandMainBand() != nullptr)
83✔
3466
                    ? poSourceBand
3467
                    : poSourceBand->GetMaskBand();
52✔
3468
            if (poMaskBand->RasterIO(
103✔
3469
                    GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3470
                    oWorkingState.m_abyWrkBufferMask.data(), nOutXSize,
103✔
3471
                    nOutYSize, GDT_Byte, 1, static_cast<GSpacing>(nOutXSize),
3472
                    psExtraArg) != CE_None)
103✔
3473
            {
3474
                return CE_Failure;
×
3475
            }
3476
        }
3477

3478
        if (m_nColorTableComponent != 0)
672✔
3479
        {
3480
            poColorTable = poSourceBand->GetColorTable();
64✔
3481
            if (poColorTable == nullptr)
64✔
3482
            {
3483
                CPLError(CE_Failure, CPLE_AppDefined,
×
3484
                         "Source band has no color table.");
3485
                return CE_Failure;
×
3486
            }
3487
        }
3488
    }
3489

3490
    /* -------------------------------------------------------------------- */
3491
    /*      Selectively copy into output buffer with nodata masking,        */
3492
    /*      and/or scaling.                                                 */
3493
    /* -------------------------------------------------------------------- */
3494

3495
    const bool bTwoStepDataTypeConversion =
4,713✔
3496
        CPL_TO_BOOL(
4,713✔
3497
            GDALDataTypeIsConversionLossy(eWrkDataType, eVRTBandDataType)) &&
9,383✔
3498
        !CPL_TO_BOOL(GDALDataTypeIsConversionLossy(eVRTBandDataType, eBufType));
4,670✔
3499

3500
    size_t idxBuffer = 0;
4,713✔
3501
    for (int iY = 0; iY < nOutYSize; iY++)
75,132✔
3502
    {
3503
        GByte *pDstLocation = static_cast<GByte *>(pData) +
70,419✔
3504
                              static_cast<GPtrDiff_t>(nLineSpace) * iY;
70,419✔
3505

3506
        for (int iX = 0; iX < nOutXSize;
11,977,128✔
3507
             iX++, pDstLocation += nPixelSpace, idxBuffer++)
11,906,772✔
3508
        {
3509
            WorkingDT afResult[2];
3510
            if (pafData && !bIsComplex)
11,906,772✔
3511
            {
3512
                WorkingDT fResult = pafData[idxBuffer];
6,297,070✔
3513
                if (bNoDataSetIsNan && std::isnan(fResult))
6,297,070✔
3514
                    continue;
1,188,620✔
3515
                if (bNoDataSetAndNotNan &&
6,298,280✔
3516
                    ARE_REAL_EQUAL(fResult, fWorkingDataTypeNoData))
1,230✔
3517
                    continue;
254✔
3518
                if (pabyMask && pabyMask[idxBuffer] == 0)
6,296,790✔
3519
                    continue;
1,188,350✔
3520

3521
                if (poColorTable)
5,108,450✔
3522
                {
3523
                    const GDALColorEntry *poEntry =
3524
                        poColorTable->GetColorEntry(static_cast<int>(fResult));
1,925,900✔
3525
                    if (poEntry)
1,925,900✔
3526
                    {
3527
                        if (m_nColorTableComponent == 1)
1,925,900✔
3528
                            fResult = poEntry->c1;
683,585✔
3529
                        else if (m_nColorTableComponent == 2)
1,242,320✔
3530
                            fResult = poEntry->c2;
529,008✔
3531
                        else if (m_nColorTableComponent == 3)
713,309✔
3532
                            fResult = poEntry->c3;
529,008✔
3533
                        else if (m_nColorTableComponent == 4)
184,301✔
3534
                            fResult = poEntry->c4;
184,301✔
3535
                    }
3536
                    else
3537
                    {
3538
                        CPLErrorOnce(CE_Failure, CPLE_AppDefined,
×
3539
                                     "No entry %d.", static_cast<int>(fResult));
3540
                        continue;
×
3541
                    }
3542
                }
3543

3544
                if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
5,108,450✔
3545
                {
3546
                    fResult = static_cast<WorkingDT>(fResult * m_dfScaleRatio +
1,649,970✔
3547
                                                     m_dfScaleOff);
1,649,970✔
3548
                }
3549
                else if ((m_nProcessingFlags &
3,458,480✔
3550
                          PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
3551
                {
3552
                    if (!m_bSrcMinMaxDefined)
3,543✔
3553
                    {
3554
                        int bSuccessMin = FALSE;
1✔
3555
                        int bSuccessMax = FALSE;
1✔
3556
                        double adfMinMax[2] = {
2✔
3557
                            poSourceBand->GetMinimum(&bSuccessMin),
1✔
3558
                            poSourceBand->GetMaximum(&bSuccessMax)};
1✔
3559
                        if ((bSuccessMin && bSuccessMax) ||
2✔
3560
                            poSourceBand->ComputeRasterMinMax(
1✔
3561
                                TRUE, adfMinMax) == CE_None)
3562
                        {
3563
                            m_dfSrcMin = adfMinMax[0];
1✔
3564
                            m_dfSrcMax = adfMinMax[1];
1✔
3565
                            m_bSrcMinMaxDefined = true;
1✔
3566
                        }
3567
                        else
3568
                        {
3569
                            CPLError(CE_Failure, CPLE_AppDefined,
×
3570
                                     "Cannot determine source min/max value");
3571
                            return CE_Failure;
×
3572
                        }
3573
                    }
3574

3575
                    double dfPowVal =
3,543✔
3576
                        (fResult - m_dfSrcMin) / (m_dfSrcMax - m_dfSrcMin);
3,543✔
3577
                    if (dfPowVal < 0.0)
3,543✔
3578
                        dfPowVal = 0.0;
×
3579
                    else if (dfPowVal > 1.0)
3,543✔
3580
                        dfPowVal = 1.0;
699✔
3581
                    fResult =
3,543✔
3582
                        static_cast<WorkingDT>((m_dfDstMax - m_dfDstMin) *
3,543✔
3583
                                                   pow(dfPowVal, m_dfExponent) +
3,543✔
3584
                                               m_dfDstMin);
3,543✔
3585
                }
3586

3587
                if (!m_adfLUTInputs.empty())
5,108,450✔
3588
                    fResult = static_cast<WorkingDT>(LookupValue(fResult));
583,336✔
3589

3590
                if (m_nMaxValue != 0 && fResult > m_nMaxValue)
5,108,450✔
3591
                    fResult = static_cast<WorkingDT>(m_nMaxValue);
800✔
3592

3593
                afResult[0] = fResult;
5,108,450✔
3594
                afResult[1] = 0;
5,108,450✔
3595
            }
3596
            else if (pafData && bIsComplex)
5,609,652✔
3597
            {
3598
                afResult[0] = pafData[2 * idxBuffer];
1,015✔
3599
                afResult[1] = pafData[2 * idxBuffer + 1];
1,015✔
3600

3601
                // Do not use color table.
3602
                if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
1,015✔
3603
                {
3604
                    afResult[0] = static_cast<WorkingDT>(
1✔
3605
                        afResult[0] * m_dfScaleRatio + m_dfScaleOff);
1✔
3606
                    afResult[1] = static_cast<WorkingDT>(
1✔
3607
                        afResult[1] * m_dfScaleRatio + m_dfScaleOff);
1✔
3608
                }
3609

3610
                /* Do not use LUT */
3611
            }
3612
            else
3613
            {
3614
                afResult[0] = static_cast<WorkingDT>(m_dfScaleOff);
5,608,642✔
3615
                afResult[1] = 0;
5,608,642✔
3616

3617
                if (!m_adfLUTInputs.empty())
5,608,642✔
3618
                    afResult[0] =
×
3619
                        static_cast<WorkingDT>(LookupValue(afResult[0]));
×
3620

3621
                if (m_nMaxValue != 0 && afResult[0] > m_nMaxValue)
5,608,642✔
3622
                    afResult[0] = static_cast<WorkingDT>(m_nMaxValue);
×
3623
            }
3624

3625
            if (eBufType == GDT_Byte && eVRTBandDataType == GDT_Byte)
10,718,082✔
3626
            {
3627
                *pDstLocation = static_cast<GByte>(std::min(
4,299,880✔
3628
                    255.0f,
8,599,760✔
3629
                    std::max(0.0f, static_cast<float>(afResult[0]) + 0.5f)));
4,299,880✔
3630
            }
3631
            else if (!bTwoStepDataTypeConversion)
6,418,222✔
3632
            {
3633
                CopyWord<WorkingDT>(afResult, eWrkDataType, pDstLocation,
3,957✔
3634
                                    eBufType);
3635
            }
3636
            else if (eVRTBandDataType == GDT_Float32 && eBufType == GDT_Float64)
6,414,270✔
3637
            {
3638
                // Particular case of the below 2-step conversion.
3639
                // Helps a bit for some geolocation based warping with Sentinel3
3640
                // data where the longitude/latitude arrays are Int32 bands,
3641
                // rescaled in VRT as Float32 and requested as Float64
3642
                float fVal;
3643
                GDALCopyWord(afResult[0], fVal);
20✔
3644
                *reinterpret_cast<double *>(pDstLocation) = fVal;
20✔
3645
            }
3646
            else
3647
            {
3648
                GByte abyTemp[2 * sizeof(double)];
3649
                // Convert first to the VRTRasterBand data type
3650
                // to get its clamping, before outputting to buffer data type
3651
                CopyWord<WorkingDT>(afResult, eWrkDataType, abyTemp,
6,414,250✔
3652
                                    eVRTBandDataType);
3653
                GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
6,414,250✔
3654
                              eBufType, 0, 1);
3655
            }
3656
        }
3657
    }
3658

3659
    return CE_None;
4,713✔
3660
}
3661

3662
// Explicitly instantiate template method, as it is used in another file.
3663
template CPLErr VRTComplexSource::RasterIOInternal<float>(
3664
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3665
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3666
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3667
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3668
    GDALDataType eWrkDataType, WorkingState &oWorkingState);
3669

3670
/************************************************************************/
3671
/*                        AreValuesUnchanged()                          */
3672
/************************************************************************/
3673

3674
bool VRTComplexSource::AreValuesUnchanged() const
9✔
3675
{
3676
    return m_dfScaleOff == 0.0 && m_dfScaleRatio == 1.0 &&
10✔
3677
           m_adfLUTInputs.empty() && m_nColorTableComponent == 0 &&
24✔
3678
           (m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) == 0;
14✔
3679
}
3680

3681
/************************************************************************/
3682
/*                             GetMinimum()                             */
3683
/************************************************************************/
3684

3685
double VRTComplexSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
2✔
3686
{
3687
    if (AreValuesUnchanged())
2✔
3688
    {
3689
        return VRTSimpleSource::GetMinimum(nXSize, nYSize, pbSuccess);
1✔
3690
    }
3691

3692
    *pbSuccess = FALSE;
1✔
3693
    return 0;
1✔
3694
}
3695

3696
/************************************************************************/
3697
/*                             GetMaximum()                             */
3698
/************************************************************************/
3699

3700
double VRTComplexSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
2✔
3701
{
3702
    if (AreValuesUnchanged())
2✔
3703
    {
3704
        return VRTSimpleSource::GetMaximum(nXSize, nYSize, pbSuccess);
1✔
3705
    }
3706

3707
    *pbSuccess = FALSE;
1✔
3708
    return 0;
1✔
3709
}
3710

3711
/************************************************************************/
3712
/*                            GetHistogram()                            */
3713
/************************************************************************/
3714

3715
CPLErr VRTComplexSource::GetHistogram(int nXSize, int nYSize, double dfMin,
×
3716
                                      double dfMax, int nBuckets,
3717
                                      GUIntBig *panHistogram,
3718
                                      int bIncludeOutOfRange, int bApproxOK,
3719
                                      GDALProgressFunc pfnProgress,
3720
                                      void *pProgressData)
3721
{
3722
    if (AreValuesUnchanged())
×
3723
    {
3724
        return VRTSimpleSource::GetHistogram(
×
3725
            nXSize, nYSize, dfMin, dfMax, nBuckets, panHistogram,
3726
            bIncludeOutOfRange, bApproxOK, pfnProgress, pProgressData);
×
3727
    }
3728

3729
    return CE_Failure;
×
3730
}
3731

3732
/************************************************************************/
3733
/* ==================================================================== */
3734
/*                          VRTFuncSource                               */
3735
/* ==================================================================== */
3736
/************************************************************************/
3737

3738
/************************************************************************/
3739
/*                           VRTFuncSource()                            */
3740
/************************************************************************/
3741

3742
VRTFuncSource::VRTFuncSource()
12✔
3743
    : pfnReadFunc(nullptr), pCBData(nullptr), eType(GDT_Byte),
3744
      fNoDataValue(static_cast<float>(VRT_NODATA_UNSET))
12✔
3745
{
3746
}
12✔
3747

3748
/************************************************************************/
3749
/*                           ~VRTFuncSource()                           */
3750
/************************************************************************/
3751

3752
VRTFuncSource::~VRTFuncSource()
24✔
3753
{
3754
}
24✔
3755

3756
/************************************************************************/
3757
/*                            GetType()                                 */
3758
/************************************************************************/
3759

3760
const char *VRTFuncSource::GetType() const
×
3761
{
3762
    static const char *TYPE = "FuncSource";
3763
    return TYPE;
×
3764
}
3765

3766
/************************************************************************/
3767
/*                           SerializeToXML()                           */
3768
/************************************************************************/
3769

3770
CPLXMLNode *VRTFuncSource::SerializeToXML(CPL_UNUSED const char *pszVRTPath)
×
3771
{
3772
    return nullptr;
×
3773
}
3774

3775
/************************************************************************/
3776
/*                              RasterIO()                              */
3777
/************************************************************************/
3778

3779
CPLErr VRTFuncSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
10✔
3780
                               int nYOff, int nXSize, int nYSize, void *pData,
3781
                               int nBufXSize, int nBufYSize,
3782
                               GDALDataType eBufType, GSpacing nPixelSpace,
3783
                               GSpacing nLineSpace,
3784
                               GDALRasterIOExtraArg * /* psExtraArg */,
3785
                               WorkingState & /* oWorkingState */)
3786
{
3787
    if (nPixelSpace * 8 == GDALGetDataTypeSize(eBufType) &&
10✔
3788
        nLineSpace == nPixelSpace * nXSize && nBufXSize == nXSize &&
10✔
3789
        nBufYSize == nYSize && eBufType == eType)
20✔
3790
    {
3791
        return pfnReadFunc(pCBData, nXOff, nYOff, nXSize, nYSize, pData);
10✔
3792
    }
3793
    else
3794
    {
3795
        CPLError(CE_Failure, CPLE_AppDefined,
×
3796
                 "VRTFuncSource::RasterIO() - Irregular request.");
3797
        CPLDebug("VRT", "Irregular request: %d,%d  %d,%d, %d,%d %d,%d %d,%d",
×
3798
                 static_cast<int>(nPixelSpace) * 8,
3799
                 GDALGetDataTypeSize(eBufType), static_cast<int>(nLineSpace),
3800
                 static_cast<int>(nPixelSpace) * nXSize, nBufXSize, nXSize,
3801
                 nBufYSize, nYSize, static_cast<int>(eBufType),
3802
                 static_cast<int>(eType));
×
3803

3804
        return CE_Failure;
×
3805
    }
3806
}
3807

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

3812
double VRTFuncSource::GetMinimum(int /* nXSize */, int /* nYSize */,
×
3813
                                 int *pbSuccess)
3814
{
3815
    *pbSuccess = FALSE;
×
3816
    return 0;
×
3817
}
3818

3819
/************************************************************************/
3820
/*                             GetMaximum()                             */
3821
/************************************************************************/
3822

3823
double VRTFuncSource::GetMaximum(int /* nXSize */, int /* nYSize */,
×
3824
                                 int *pbSuccess)
3825
{
3826
    *pbSuccess = FALSE;
×
3827
    return 0;
×
3828
}
3829

3830
/************************************************************************/
3831
/*                            GetHistogram()                            */
3832
/************************************************************************/
3833

3834
CPLErr VRTFuncSource::GetHistogram(
×
3835
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
3836
    int /* nBuckets */, GUIntBig * /* panHistogram */,
3837
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
3838
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
3839
{
3840
    return CE_Failure;
×
3841
}
3842

3843
/************************************************************************/
3844
/*                        VRTParseCoreSources()                         */
3845
/************************************************************************/
3846

3847
VRTSource *VRTParseCoreSources(const CPLXMLNode *psChild,
3,061✔
3848
                               const char *pszVRTPath,
3849
                               VRTMapSharedResources &oMapSharedSources)
3850

3851
{
3852
    VRTSource *poSource = nullptr;
3,061✔
3853

3854
    if (EQUAL(psChild->pszValue, VRTAveragedSource::GetTypeStatic()) ||
6,115✔
3855
        (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()) &&
3,054✔
3856
         STARTS_WITH_CI(CPLGetXMLValue(psChild, "Resampling", "Nearest"),
2,843✔
3857
                        "Aver")))
3858
    {
3859
        poSource = new VRTAveragedSource();
16✔
3860
    }
3861
    else if (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()))
3,045✔
3862
    {
3863
        poSource = new VRTSimpleSource();
2,834✔
3864
    }
3865
    else if (EQUAL(psChild->pszValue, VRTComplexSource::GetTypeStatic()))
211✔
3866
    {
3867
        poSource = new VRTComplexSource();
203✔
3868
    }
3869
    else if (EQUAL(psChild->pszValue, VRTNoDataFromMaskSource::GetTypeStatic()))
8✔
3870
    {
3871
        poSource = new VRTNoDataFromMaskSource();
8✔
3872
    }
3873
    else
3874
    {
3875
        CPLError(CE_Failure, CPLE_AppDefined,
×
3876
                 "VRTParseCoreSources() - Unknown source : %s",
3877
                 psChild->pszValue);
×
3878
        return nullptr;
×
3879
    }
3880

3881
    if (poSource->XMLInit(psChild, pszVRTPath, oMapSharedSources) == CE_None)
3,061✔
3882
        return poSource;
3,058✔
3883

3884
    delete poSource;
3✔
3885
    return nullptr;
3✔
3886
}
3887

3888
/*! @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