Coverage Report

Created: 2026-07-14 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/vrt/vrtsources.cpp
Line
Count
Source
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
#include "gdalsubdatasetinfo.h"
41
42
/*! @cond Doxygen_Suppress */
43
44
// #define DEBUG_VERBOSE 1
45
46
/************************************************************************/
47
/* ==================================================================== */
48
/*                             VRTSource                                */
49
/* ==================================================================== */
50
/************************************************************************/
51
52
VRTSource::~VRTSource()
53
0
{
54
0
}
55
56
/************************************************************************/
57
/*                            GetFileList()                             */
58
/************************************************************************/
59
60
void VRTSource::GetFileList(char *** /* ppapszFileList */, int * /* pnSize */,
61
                            int * /* pnMaxSize */, CPLHashSet * /* hSetFiles */)
62
0
{
63
0
}
64
65
/************************************************************************/
66
/* ==================================================================== */
67
/*                          VRTSimpleSource                             */
68
/* ==================================================================== */
69
/************************************************************************/
70
71
/************************************************************************/
72
/*                          VRTSimpleSource()                           */
73
/************************************************************************/
74
75
0
VRTSimpleSource::VRTSimpleSource() = default;
76
77
/************************************************************************/
78
/*                          VRTSimpleSource()                           */
79
/************************************************************************/
80
81
VRTSimpleSource::VRTSimpleSource(const VRTSimpleSource *poSrcSource,
82
                                 double dfXDstRatio, double dfYDstRatio)
83
0
    : VRTSource(*poSrcSource),
84
0
      m_poMapSharedSources(poSrcSource->m_poMapSharedSources),
85
0
      m_poRasterBand(poSrcSource->m_poRasterBand),
86
0
      m_poMaskBandMainBand(poSrcSource->m_poMaskBandMainBand),
87
0
      m_aosOpenOptionsOri(poSrcSource->m_aosOpenOptionsOri),
88
0
      m_aosOpenOptions(poSrcSource->m_aosOpenOptions),
89
0
      m_bSrcDSNameFromVRT(poSrcSource->m_bSrcDSNameFromVRT),
90
0
      m_nBand(poSrcSource->m_nBand),
91
0
      m_bGetMaskBand(poSrcSource->m_bGetMaskBand),
92
0
      m_dfSrcXOff(poSrcSource->m_dfSrcXOff),
93
0
      m_dfSrcYOff(poSrcSource->m_dfSrcYOff),
94
0
      m_dfSrcXSize(poSrcSource->m_dfSrcXSize),
95
0
      m_dfSrcYSize(poSrcSource->m_dfSrcYSize),
96
0
      m_nMaxValue(poSrcSource->m_nMaxValue), m_bRelativeToVRTOri(-1),
97
0
      m_nExplicitSharedStatus(poSrcSource->m_nExplicitSharedStatus),
98
0
      m_osSrcDSName(poSrcSource->m_osSrcDSName),
99
0
      m_bDropRefOnSrcBand(poSrcSource->m_bDropRefOnSrcBand)
100
0
{
101
0
    if (!poSrcSource->IsSrcWinSet() && !poSrcSource->IsDstWinSet() &&
102
0
        (dfXDstRatio != 1.0 || dfYDstRatio != 1.0))
103
0
    {
104
0
        auto l_band = GetRasterBand();
105
0
        if (l_band)
106
0
        {
107
0
            m_dfSrcXOff = 0;
108
0
            m_dfSrcYOff = 0;
109
0
            m_dfSrcXSize = l_band->GetXSize();
110
0
            m_dfSrcYSize = l_band->GetYSize();
111
0
            m_dfDstXOff = 0;
112
0
            m_dfDstYOff = 0;
113
0
            m_dfDstXSize = l_band->GetXSize() * dfXDstRatio;
114
0
            m_dfDstYSize = l_band->GetYSize() * dfYDstRatio;
115
0
        }
116
0
    }
117
0
    else if (poSrcSource->IsDstWinSet())
118
0
    {
119
0
        m_dfDstXOff = poSrcSource->m_dfDstXOff * dfXDstRatio;
120
0
        m_dfDstYOff = poSrcSource->m_dfDstYOff * dfYDstRatio;
121
0
        m_dfDstXSize = poSrcSource->m_dfDstXSize * dfXDstRatio;
122
0
        m_dfDstYSize = poSrcSource->m_dfDstYSize * dfYDstRatio;
123
0
    }
124
125
0
    if (m_bDropRefOnSrcBand)
126
0
    {
127
0
        GDALDataset *poDS = GetSourceDataset();
128
0
        if (poDS)
129
0
            poDS->Reference();
130
0
    }
131
0
}
132
133
/************************************************************************/
134
/*                          ~VRTSimpleSource()                          */
135
/************************************************************************/
136
137
VRTSimpleSource::~VRTSimpleSource()
138
139
0
{
140
0
    if (m_bDropRefOnSrcBand)
141
0
    {
142
0
        GDALDataset *poDS = GetSourceDataset();
143
0
        if (poDS)
144
0
            poDS->ReleaseRef();
145
0
    }
146
0
}
147
148
/************************************************************************/
149
/*                          GetSourceDataset()                          */
150
/************************************************************************/
151
152
GDALDataset *VRTSimpleSource::GetSourceDataset() const
153
0
{
154
0
    GDALDataset *poDS = nullptr;
155
0
    if (m_poMaskBandMainBand)
156
0
        poDS = m_poMaskBandMainBand->GetDataset();
157
0
    else if (m_poRasterBand)
158
0
        poDS = m_poRasterBand->GetDataset();
159
0
    return poDS;
160
0
}
161
162
/************************************************************************/
163
/*                           GetTypeStatic()                            */
164
/************************************************************************/
165
166
const char *VRTSimpleSource::GetTypeStatic()
167
0
{
168
0
    static const char *TYPE = "SimpleSource";
169
0
    return TYPE;
170
0
}
171
172
/************************************************************************/
173
/*                              GetType()                               */
174
/************************************************************************/
175
176
const char *VRTSimpleSource::GetType() const
177
0
{
178
0
    return GetTypeStatic();
179
0
}
180
181
/************************************************************************/
182
/*                             FlushCache()                             */
183
/************************************************************************/
184
185
CPLErr VRTSimpleSource::FlushCache(bool bAtClosing)
186
187
0
{
188
0
    if (m_poMaskBandMainBand != nullptr)
189
0
    {
190
0
        return m_poMaskBandMainBand->FlushCache(bAtClosing);
191
0
    }
192
0
    else if (m_poRasterBand != nullptr)
193
0
    {
194
0
        return m_poRasterBand->FlushCache(bAtClosing);
195
0
    }
196
0
    return CE_None;
197
0
}
198
199
/************************************************************************/
200
/*                  UnsetPreservedRelativeFilenames()                   */
201
/************************************************************************/
202
203
void VRTSimpleSource::UnsetPreservedRelativeFilenames()
204
0
{
205
0
    if (m_bRelativeToVRTOri &&
206
0
        !STARTS_WITH(m_osSourceFileNameOri.c_str(), "http://") &&
207
0
        !STARTS_WITH(m_osSourceFileNameOri.c_str(), "https://"))
208
0
    {
209
0
        m_bRelativeToVRTOri = -1;
210
0
        m_osSourceFileNameOri = "";
211
0
    }
212
0
}
213
214
/************************************************************************/
215
/*                             SetSrcBand()                             */
216
/************************************************************************/
217
218
void VRTSimpleSource::SetSrcBand(const char *pszFilename, int nBand)
219
220
0
{
221
0
    m_nBand = nBand;
222
0
    m_osSrcDSName = pszFilename;
223
0
}
224
225
/************************************************************************/
226
/*                             SetSrcBand()                             */
227
/************************************************************************/
228
229
void VRTSimpleSource::SetSrcBand(GDALRasterBand *poNewSrcBand)
230
231
0
{
232
0
    m_poRasterBand = poNewSrcBand;
233
0
    m_nBand = m_poRasterBand->GetBand();
234
0
    auto poDS = poNewSrcBand->GetDataset();
235
0
    if (poDS != nullptr)
236
0
    {
237
0
        m_osSrcDSName = poDS->GetDescription();
238
0
        m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
239
0
        m_aosOpenOptionsOri = m_aosOpenOptions;
240
0
    }
241
0
}
242
243
/************************************************************************/
244
/*                        SetSourceDatasetName()                        */
245
/************************************************************************/
246
247
void VRTSimpleSource::SetSourceDatasetName(const char *pszFilename,
248
                                           bool bRelativeToVRT)
249
0
{
250
0
    CPLAssert(m_nBand >= 0);
251
0
    m_osSrcDSName = pszFilename;
252
0
    m_osSourceFileNameOri = pszFilename;
253
0
    m_bRelativeToVRTOri = bRelativeToVRT;
254
0
}
255
256
/************************************************************************/
257
/*                           SetSrcMaskBand()                           */
258
/************************************************************************/
259
260
// poSrcBand is not the mask band, but the band from which the mask band is
261
// taken.
262
void VRTSimpleSource::SetSrcMaskBand(GDALRasterBand *poNewSrcBand)
263
264
0
{
265
0
    m_poRasterBand = poNewSrcBand->GetMaskBand();
266
0
    m_poMaskBandMainBand = poNewSrcBand;
267
0
    m_nBand = poNewSrcBand->GetBand();
268
0
    auto poDS = poNewSrcBand->GetDataset();
269
0
    if (poDS != nullptr)
270
0
    {
271
0
        m_osSrcDSName = poDS->GetDescription();
272
0
        m_aosOpenOptions = CSLDuplicate(poDS->GetOpenOptions());
273
0
        m_aosOpenOptionsOri = m_aosOpenOptions;
274
0
    }
275
0
    m_bGetMaskBand = true;
276
0
}
277
278
/************************************************************************/
279
/*                         RoundIfCloseToInt()                          */
280
/************************************************************************/
281
282
static double RoundIfCloseToInt(double dfValue)
283
0
{
284
0
    double dfClosestInt = floor(dfValue + 0.5);
285
0
    return (fabs(dfValue - dfClosestInt) < 1e-3) ? dfClosestInt : dfValue;
286
0
}
287
288
/************************************************************************/
289
/*                            SetSrcWindow()                            */
290
/************************************************************************/
291
292
void VRTSimpleSource::SetSrcWindow(double dfNewXOff, double dfNewYOff,
293
                                   double dfNewXSize, double dfNewYSize)
294
295
0
{
296
0
    m_dfSrcXOff = RoundIfCloseToInt(dfNewXOff);
297
0
    m_dfSrcYOff = RoundIfCloseToInt(dfNewYOff);
298
0
    m_dfSrcXSize = RoundIfCloseToInt(dfNewXSize);
299
0
    m_dfSrcYSize = RoundIfCloseToInt(dfNewYSize);
300
0
}
301
302
/************************************************************************/
303
/*                            SetDstWindow()                            */
304
/************************************************************************/
305
306
void VRTSimpleSource::SetDstWindow(double dfNewXOff, double dfNewYOff,
307
                                   double dfNewXSize, double dfNewYSize)
308
309
0
{
310
0
    m_dfDstXOff = RoundIfCloseToInt(dfNewXOff);
311
0
    m_dfDstYOff = RoundIfCloseToInt(dfNewYOff);
312
0
    m_dfDstXSize = RoundIfCloseToInt(dfNewXSize);
313
0
    m_dfDstYSize = RoundIfCloseToInt(dfNewYSize);
314
0
}
315
316
/************************************************************************/
317
/*                            GetDstWindow()                            */
318
/************************************************************************/
319
320
void VRTSimpleSource::GetDstWindow(double &dfDstXOff, double &dfDstYOff,
321
                                   double &dfDstXSize, double &dfDstYSize) const
322
0
{
323
0
    dfDstXOff = m_dfDstXOff;
324
0
    dfDstYOff = m_dfDstYOff;
325
0
    dfDstXSize = m_dfDstXSize;
326
0
    dfDstYSize = m_dfDstYSize;
327
0
}
328
329
/************************************************************************/
330
/*                        DstWindowIntersects()                         */
331
/************************************************************************/
332
333
bool VRTSimpleSource::DstWindowIntersects(double dfXOff, double dfYOff,
334
                                          double dfXSize, double dfYSize) const
335
0
{
336
0
    return IsDstWinSet() && m_dfDstXOff + m_dfDstXSize > dfXOff &&
337
0
           m_dfDstYOff + m_dfDstYSize > dfYOff &&
338
0
           m_dfDstXOff < dfXOff + dfXSize && m_dfDstYOff < dfYOff + dfYSize;
339
0
}
340
341
/************************************************************************/
342
/*                            IsSlowSource()                            */
343
/************************************************************************/
344
345
static bool IsSlowSource(const char *pszSrcName)
346
0
{
347
0
    return strstr(pszSrcName, "/vsicurl/http") != nullptr ||
348
0
           strstr(pszSrcName, "/vsicurl/ftp") != nullptr ||
349
0
           (strstr(pszSrcName, "/vsicurl?") != nullptr &&
350
0
            strstr(pszSrcName, "&url=http") != nullptr);
351
0
}
352
353
/************************************************************************/
354
/*                       AddSourceFilenameNode()                        */
355
/************************************************************************/
356
357
/* static */
358
std::pair<std::string, bool> VRTSimpleSource::ComputeSourceNameAndRelativeFlag(
359
    const char *pszVRTPath, const std::string &osSourceNameIn)
360
0
{
361
0
    std::string osSourceFilename = osSourceNameIn;
362
0
    int bRelativeToVRT = false;
363
364
    // If this isn't actually a file, don't even try to know if it is a
365
    // relative path. It can't be !, and unfortunately CPLIsFilenameRelative()
366
    // can only work with strings that are filenames To be clear
367
    // NITF_TOC_ENTRY:CADRG_JOG-A_250K_1_0:some_path isn't a relative file
368
    // path.
369
0
    VSIStatBufL sStat;
370
0
    if (VSIStatExL(osSourceFilename.c_str(), &sStat, VSI_STAT_EXISTS_FLAG) != 0)
371
0
    {
372
        // Try subdatasetinfo API first
373
        // Note: this will become the only branch when subdatasetinfo will become
374
        //       available for NITF_IM, RASTERLITE and TILEDB
375
0
        const auto oSubDSInfo{GDALGetSubdatasetInfo(osSourceFilename.c_str())};
376
0
        if (oSubDSInfo && !oSubDSInfo->GetPathComponent().empty())
377
0
        {
378
0
            auto path{oSubDSInfo->GetPathComponent()};
379
0
            std::string relPath{CPLExtractRelativePath(pszVRTPath, path.c_str(),
380
0
                                                       &bRelativeToVRT)};
381
0
            osSourceFilename = oSubDSInfo->ModifyPathComponent(relPath);
382
0
            GDALDestroySubdatasetInfo(oSubDSInfo);
383
0
        }
384
0
        else
385
0
        {
386
0
            for (const char *pszSyntax :
387
0
                 GDALDataset::apszSpecialSubDatasetSyntax)
388
0
            {
389
0
                CPLString osPrefix(pszSyntax);
390
0
                osPrefix.resize(strchr(pszSyntax, ':') - pszSyntax + 1);
391
0
                if (pszSyntax[osPrefix.size()] == '"')
392
0
                    osPrefix += '"';
393
0
                if (EQUALN(osSourceFilename.c_str(), osPrefix, osPrefix.size()))
394
0
                {
395
0
                    if (STARTS_WITH_CI(pszSyntax + osPrefix.size(), "{ANY}"))
396
0
                    {
397
0
                        const char *pszLastPart =
398
0
                            strrchr(osSourceFilename.c_str(), ':') + 1;
399
                        // CSV:z:/foo.xyz
400
0
                        if ((pszLastPart[0] == '/' || pszLastPart[0] == '\\') &&
401
0
                            pszLastPart - osSourceFilename.c_str() >= 3 &&
402
0
                            pszLastPart[-3] == ':')
403
0
                            pszLastPart -= 2;
404
0
                        CPLString osPrefixFilename(osSourceFilename);
405
0
                        osPrefixFilename.resize(pszLastPart -
406
0
                                                osSourceFilename.c_str());
407
0
                        osSourceFilename = CPLExtractRelativePath(
408
0
                            pszVRTPath, pszLastPart, &bRelativeToVRT);
409
0
                        osSourceFilename = osPrefixFilename + osSourceFilename;
410
0
                    }
411
0
                    else if (STARTS_WITH_CI(pszSyntax + osPrefix.size(),
412
0
                                            "{FILENAME}"))
413
0
                    {
414
0
                        CPLString osFilename(osSourceFilename.c_str() +
415
0
                                             osPrefix.size());
416
0
                        size_t nPos = 0;
417
0
                        if (osFilename.size() >= 3 && osFilename[1] == ':' &&
418
0
                            (osFilename[2] == '\\' || osFilename[2] == '/'))
419
0
                            nPos = 2;
420
0
                        nPos = osFilename.find(
421
0
                            pszSyntax[osPrefix.size() + strlen("{FILENAME}")],
422
0
                            nPos);
423
0
                        if (nPos != std::string::npos)
424
0
                        {
425
0
                            const CPLString osSuffix = osFilename.substr(nPos);
426
0
                            osFilename.resize(nPos);
427
0
                            osSourceFilename = CPLExtractRelativePath(
428
0
                                pszVRTPath, osFilename, &bRelativeToVRT);
429
0
                            osSourceFilename =
430
0
                                osPrefix + osSourceFilename + osSuffix;
431
0
                        }
432
0
                    }
433
0
                    break;
434
0
                }
435
0
            }
436
0
        }
437
0
    }
438
0
    else
439
0
    {
440
0
        std::string osVRTFilename = pszVRTPath;
441
0
        std::string osSourceDataset = osSourceNameIn;
442
0
        ;
443
0
        char *pszCurDir = CPLGetCurrentDir();
444
0
        if (CPLIsFilenameRelative(osSourceDataset.c_str()) &&
445
0
            !CPLIsFilenameRelative(osVRTFilename.c_str()) &&
446
0
            pszCurDir != nullptr)
447
0
        {
448
0
            osSourceDataset = CPLFormFilenameSafe(
449
0
                pszCurDir, osSourceDataset.c_str(), nullptr);
450
0
        }
451
0
        else if (!CPLIsFilenameRelative(osSourceDataset.c_str()) &&
452
0
                 CPLIsFilenameRelative(osVRTFilename.c_str()) &&
453
0
                 pszCurDir != nullptr)
454
0
        {
455
0
            osVRTFilename =
456
0
                CPLFormFilenameSafe(pszCurDir, osVRTFilename.c_str(), nullptr);
457
0
        }
458
0
        CPLFree(pszCurDir);
459
0
        osSourceFilename = CPLExtractRelativePath(
460
0
            osVRTFilename.c_str(), osSourceDataset.c_str(), &bRelativeToVRT);
461
0
    }
462
463
0
    return {osSourceFilename, static_cast<bool>(bRelativeToVRT)};
464
0
}
465
466
/************************************************************************/
467
/*                       AddSourceFilenameNode()                        */
468
/************************************************************************/
469
470
void VRTSimpleSource::AddSourceFilenameNode(const char *pszVRTPath,
471
                                            CPLXMLNode *psSrc)
472
0
{
473
474
0
    bool bRelativeToVRT = false;
475
0
    std::string osSourceFilename;
476
477
0
    if (m_bRelativeToVRTOri >= 0)
478
0
    {
479
0
        osSourceFilename = m_osSourceFileNameOri;
480
0
        bRelativeToVRT = CPL_TO_BOOL(m_bRelativeToVRTOri);
481
0
    }
482
0
    else if (IsSlowSource(m_osSrcDSName))
483
0
    {
484
        // Testing the existence of remote resources can be excruciating
485
        // slow, so let's just suppose they exist.
486
0
        osSourceFilename = m_osSrcDSName;
487
0
        bRelativeToVRT = false;
488
0
    }
489
0
    else
490
0
    {
491
0
        std::tie(osSourceFilename, bRelativeToVRT) =
492
0
            ComputeSourceNameAndRelativeFlag(pszVRTPath, m_osSrcDSName);
493
0
    }
494
495
0
    CPLSetXMLValue(psSrc, "SourceFilename", osSourceFilename.c_str());
496
497
0
    CPLCreateXMLNode(CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
498
0
                                      CXT_Attribute, "relativeToVRT"),
499
0
                     CXT_Text, bRelativeToVRT ? "1" : "0");
500
501
    // Determine if we must write the shared attribute. The config option
502
    // will override the m_nExplicitSharedStatus value
503
0
    const char *pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
504
0
    if ((pszShared == nullptr && m_nExplicitSharedStatus == 0) ||
505
0
        (pszShared != nullptr && !CPLTestBool(pszShared)))
506
0
    {
507
0
        CPLCreateXMLNode(
508
0
            CPLCreateXMLNode(CPLGetXMLNode(psSrc, "SourceFilename"),
509
0
                             CXT_Attribute, "shared"),
510
0
            CXT_Text, "0");
511
0
    }
512
0
}
513
514
/************************************************************************/
515
/*                           SerializeToXML()                           */
516
/************************************************************************/
517
518
CPLXMLNode *VRTSimpleSource::SerializeToXML(const char *pszVRTPath)
519
520
0
{
521
0
    CPLXMLNode *const psSrc =
522
0
        CPLCreateXMLNode(nullptr, CXT_Element, GetTypeStatic());
523
524
0
    if (!m_osResampling.empty())
525
0
    {
526
0
        CPLCreateXMLNode(CPLCreateXMLNode(psSrc, CXT_Attribute, "resampling"),
527
0
                         CXT_Text, m_osResampling.c_str());
528
0
    }
529
530
0
    if (!m_osName.empty())
531
0
    {
532
0
        CPLAddXMLAttributeAndValue(psSrc, "name", m_osName.c_str());
533
0
    }
534
535
0
    if (m_bSrcDSNameFromVRT)
536
0
    {
537
0
        CPLAddXMLChild(psSrc, CPLParseXMLString(m_osSrcDSName.c_str()));
538
0
    }
539
0
    else
540
0
    {
541
0
        bool bDone = false;
542
0
        if (m_osSrcDSName.empty() && m_poRasterBand)
543
0
        {
544
0
            auto poSrcDS = m_poRasterBand->GetDataset();
545
0
            if (poSrcDS)
546
0
            {
547
0
                VRTDataset *poSrcVRTDS = nullptr;
548
                // For GDALComputedDataset
549
0
                void *pHandle = poSrcDS->GetInternalHandle("VRT_DATASET");
550
0
                if (pHandle && poSrcDS->GetInternalHandle(nullptr) == nullptr)
551
0
                {
552
0
                    poSrcVRTDS = static_cast<VRTDataset *>(pHandle);
553
0
                }
554
0
                else
555
0
                {
556
0
                    poSrcVRTDS = dynamic_cast<VRTDataset *>(poSrcDS);
557
0
                }
558
0
                if (poSrcVRTDS)
559
0
                {
560
0
                    poSrcVRTDS->UnsetPreservedRelativeFilenames();
561
0
                    CPLAddXMLChild(psSrc,
562
0
                                   poSrcVRTDS->SerializeToXML(pszVRTPath));
563
0
                    bDone = true;
564
0
                }
565
0
            }
566
0
        }
567
0
        if (!bDone)
568
0
        {
569
0
            AddSourceFilenameNode(pszVRTPath, psSrc);
570
0
        }
571
0
    }
572
573
0
    GDALSerializeOpenOptionsToXML(psSrc, m_aosOpenOptionsOri.List());
574
575
0
    if (m_bGetMaskBand)
576
0
        CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("mask,%d", m_nBand));
577
0
    else
578
0
        CPLSetXMLValue(psSrc, "SourceBand", CPLSPrintf("%d", m_nBand));
579
580
    // TODO: in a later version, no longer emit SourceProperties, which
581
    // is no longer used by GDAL 3.4
582
0
    if (m_poRasterBand)
583
0
    {
584
        /* Write a few additional useful properties of the dataset */
585
        /* so that we can use a proxy dataset when re-opening. See XMLInit() */
586
        /* below */
587
0
        CPLSetXMLValue(psSrc, "SourceProperties.#RasterXSize",
588
0
                       CPLSPrintf("%d", m_poRasterBand->GetXSize()));
589
0
        CPLSetXMLValue(psSrc, "SourceProperties.#RasterYSize",
590
0
                       CPLSPrintf("%d", m_poRasterBand->GetYSize()));
591
0
        CPLSetXMLValue(
592
0
            psSrc, "SourceProperties.#DataType",
593
0
            GDALGetDataTypeName(m_poRasterBand->GetRasterDataType()));
594
595
0
        int nBlockXSize = 0;
596
0
        int nBlockYSize = 0;
597
0
        m_poRasterBand->GetBlockSize(&nBlockXSize, &nBlockYSize);
598
599
0
        CPLSetXMLValue(psSrc, "SourceProperties.#BlockXSize",
600
0
                       CPLSPrintf("%d", nBlockXSize));
601
0
        CPLSetXMLValue(psSrc, "SourceProperties.#BlockYSize",
602
0
                       CPLSPrintf("%d", nBlockYSize));
603
0
    }
604
605
0
    if (IsSrcWinSet())
606
0
    {
607
0
        CPLSetXMLValue(psSrc, "SrcRect.#xOff",
608
0
                       CPLSPrintf("%.15g", m_dfSrcXOff));
609
0
        CPLSetXMLValue(psSrc, "SrcRect.#yOff",
610
0
                       CPLSPrintf("%.15g", m_dfSrcYOff));
611
0
        CPLSetXMLValue(psSrc, "SrcRect.#xSize",
612
0
                       CPLSPrintf("%.15g", m_dfSrcXSize));
613
0
        CPLSetXMLValue(psSrc, "SrcRect.#ySize",
614
0
                       CPLSPrintf("%.15g", m_dfSrcYSize));
615
0
    }
616
617
0
    if (IsDstWinSet())
618
0
    {
619
0
        CPLSetXMLValue(psSrc, "DstRect.#xOff",
620
0
                       CPLSPrintf("%.15g", m_dfDstXOff));
621
0
        CPLSetXMLValue(psSrc, "DstRect.#yOff",
622
0
                       CPLSPrintf("%.15g", m_dfDstYOff));
623
0
        CPLSetXMLValue(psSrc, "DstRect.#xSize",
624
0
                       CPLSPrintf("%.15g", m_dfDstXSize));
625
0
        CPLSetXMLValue(psSrc, "DstRect.#ySize",
626
0
                       CPLSPrintf("%.15g", m_dfDstYSize));
627
0
    }
628
629
0
    return psSrc;
630
0
}
631
632
/************************************************************************/
633
/*                              XMLInit()                               */
634
/************************************************************************/
635
636
CPLErr VRTSimpleSource::XMLInit(const CPLXMLNode *psSrc, const char *pszVRTPath,
637
                                VRTMapSharedResources &oMapSharedSources)
638
639
0
{
640
0
    m_poMapSharedSources = &oMapSharedSources;
641
642
0
    m_osResampling = CPLGetXMLValue(psSrc, "resampling", "");
643
0
    m_osName = CPLGetXMLValue(psSrc, "name", "");
644
645
    /* -------------------------------------------------------------------- */
646
    /*      Prepare filename.                                               */
647
    /* -------------------------------------------------------------------- */
648
0
    const CPLXMLNode *psSourceFileNameNode =
649
0
        CPLGetXMLNode(psSrc, "SourceFilename");
650
0
    const CPLXMLNode *psSourceVRTDataset = CPLGetXMLNode(psSrc, "VRTDataset");
651
0
    const char *pszFilename =
652
0
        psSourceFileNameNode ? CPLGetXMLValue(psSourceFileNameNode, nullptr, "")
653
0
                             : "";
654
655
0
    if (pszFilename[0] == '\0' && !psSourceVRTDataset)
656
0
    {
657
0
        CPLError(CE_Warning, CPLE_AppDefined,
658
0
                 "Missing <SourceFilename> or <VRTDataset> element in <%s>.",
659
0
                 psSrc->pszValue);
660
0
        return CE_Failure;
661
0
    }
662
663
    // Backup original filename and relativeToVRT so as to be able to
664
    // serialize them identically again (#5985)
665
0
    m_osSourceFileNameOri = pszFilename;
666
0
    if (pszFilename[0])
667
0
    {
668
0
        m_bRelativeToVRTOri =
669
0
            atoi(CPLGetXMLValue(psSourceFileNameNode, "relativetoVRT", "0"));
670
0
        const char *pszShared =
671
0
            CPLGetXMLValue(psSourceFileNameNode, "shared", nullptr);
672
0
        if (pszShared == nullptr)
673
0
        {
674
0
            pszShared = CPLGetConfigOption("VRT_SHARED_SOURCE", nullptr);
675
0
        }
676
0
        if (pszShared != nullptr)
677
0
        {
678
0
            m_nExplicitSharedStatus = CPLTestBool(pszShared);
679
0
        }
680
681
0
        m_osSrcDSName = GDALDataset::BuildFilename(
682
0
            pszFilename, pszVRTPath, CPL_TO_BOOL(m_bRelativeToVRTOri));
683
0
    }
684
0
    else if (psSourceVRTDataset)
685
0
    {
686
0
        CPLXMLNode sNode;
687
0
        sNode.eType = psSourceVRTDataset->eType;
688
0
        sNode.pszValue = psSourceVRTDataset->pszValue;
689
0
        sNode.psNext = nullptr;
690
0
        sNode.psChild = psSourceVRTDataset->psChild;
691
0
        char *pszXML = CPLSerializeXMLTree(&sNode);
692
0
        if (pszXML)
693
0
        {
694
0
            m_bSrcDSNameFromVRT = true;
695
0
            m_osSrcDSName = pszXML;
696
0
            CPLFree(pszXML);
697
0
        }
698
0
    }
699
700
0
    const char *pszSourceBand = CPLGetXMLValue(psSrc, "SourceBand", "1");
701
0
    m_bGetMaskBand = false;
702
0
    if (STARTS_WITH_CI(pszSourceBand, "mask"))
703
0
    {
704
0
        m_bGetMaskBand = true;
705
0
        if (pszSourceBand[4] == ',')
706
0
            m_nBand = atoi(pszSourceBand + 5);
707
0
        else
708
0
            m_nBand = 1;
709
0
    }
710
0
    else
711
0
    {
712
0
        m_nBand = atoi(pszSourceBand);
713
0
    }
714
0
    if (!GDALCheckBandCount(m_nBand, 0))
715
0
    {
716
0
        CPLError(CE_Warning, CPLE_AppDefined,
717
0
                 "Invalid <SourceBand> element in VRTRasterBand.");
718
0
        return CE_Failure;
719
0
    }
720
721
0
    m_aosOpenOptions = GDALDeserializeOpenOptionsFromXML(psSrc);
722
0
    m_aosOpenOptionsOri = m_aosOpenOptions;
723
0
    if (strstr(m_osSrcDSName.c_str(), "<VRTDataset") != nullptr)
724
0
        m_aosOpenOptions.SetNameValue("ROOT_PATH", pszVRTPath);
725
726
0
    return ParseSrcRectAndDstRect(psSrc);
727
0
}
728
729
/************************************************************************/
730
/*                       ParseSrcRectAndDstRect()                       */
731
/************************************************************************/
732
733
CPLErr VRTSimpleSource::ParseSrcRectAndDstRect(const CPLXMLNode *psSrc)
734
0
{
735
0
    const auto GetAttrValue = [](const CPLXMLNode *psNode,
736
0
                                 const char *pszAttrName, double dfDefaultVal)
737
0
    {
738
0
        if (const char *pszVal = CPLGetXMLValue(psNode, pszAttrName, nullptr))
739
0
            return CPLAtof(pszVal);
740
0
        else
741
0
            return dfDefaultVal;
742
0
    };
743
744
    /* -------------------------------------------------------------------- */
745
    /*      Set characteristics.                                            */
746
    /* -------------------------------------------------------------------- */
747
0
    const CPLXMLNode *const psSrcRect = CPLGetXMLNode(psSrc, "SrcRect");
748
0
    if (psSrcRect)
749
0
    {
750
0
        double xOff = GetAttrValue(psSrcRect, "xOff", UNINIT_WINDOW);
751
0
        double yOff = GetAttrValue(psSrcRect, "yOff", UNINIT_WINDOW);
752
0
        double xSize = GetAttrValue(psSrcRect, "xSize", UNINIT_WINDOW);
753
0
        double ySize = GetAttrValue(psSrcRect, "ySize", UNINIT_WINDOW);
754
        // Test written that way to catch NaN values
755
0
        if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
756
0
            !(yOff >= INT_MIN && yOff <= INT_MAX) ||
757
0
            !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
758
0
            !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
759
0
        {
760
0
            CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in SrcRect");
761
0
            return CE_Failure;
762
0
        }
763
0
        SetSrcWindow(xOff, yOff, xSize, ySize);
764
0
    }
765
0
    else
766
0
    {
767
0
        m_dfSrcXOff = UNINIT_WINDOW;
768
0
        m_dfSrcYOff = UNINIT_WINDOW;
769
0
        m_dfSrcXSize = UNINIT_WINDOW;
770
0
        m_dfSrcYSize = UNINIT_WINDOW;
771
0
    }
772
773
0
    const CPLXMLNode *const psDstRect = CPLGetXMLNode(psSrc, "DstRect");
774
0
    if (psDstRect)
775
0
    {
776
0
        double xOff = GetAttrValue(psDstRect, "xOff", UNINIT_WINDOW);
777
0
        ;
778
0
        double yOff = GetAttrValue(psDstRect, "yOff", UNINIT_WINDOW);
779
0
        double xSize = GetAttrValue(psDstRect, "xSize", UNINIT_WINDOW);
780
0
        ;
781
0
        double ySize = GetAttrValue(psDstRect, "ySize", UNINIT_WINDOW);
782
        // Test written that way to catch NaN values
783
0
        if (!(xOff >= INT_MIN && xOff <= INT_MAX) ||
784
0
            !(yOff >= INT_MIN && yOff <= INT_MAX) ||
785
0
            !(xSize > 0 || xSize == UNINIT_WINDOW) || xSize > INT_MAX ||
786
0
            !(ySize > 0 || ySize == UNINIT_WINDOW) || ySize > INT_MAX)
787
0
        {
788
0
            CPLError(CE_Failure, CPLE_AppDefined, "Wrong values in DstRect");
789
0
            return CE_Failure;
790
0
        }
791
0
        SetDstWindow(xOff, yOff, xSize, ySize);
792
0
    }
793
0
    else
794
0
    {
795
0
        m_dfDstXOff = UNINIT_WINDOW;
796
0
        m_dfDstYOff = UNINIT_WINDOW;
797
0
        m_dfDstXSize = UNINIT_WINDOW;
798
0
        m_dfDstYSize = UNINIT_WINDOW;
799
0
    }
800
801
0
    return CE_None;
802
0
}
803
804
/************************************************************************/
805
/*                            GetFileList()                             */
806
/************************************************************************/
807
808
void VRTSimpleSource::GetFileList(char ***ppapszFileList, int *pnSize,
809
                                  int *pnMaxSize, CPLHashSet *hSetFiles)
810
0
{
811
0
    if (!m_osSrcDSName.empty() && !m_bSrcDSNameFromVRT)
812
0
    {
813
0
        const char *pszFilename = m_osSrcDSName.c_str();
814
815
        /* --------------------------------------------------------------------
816
         */
817
        /*      Is it already in the list ? */
818
        /* --------------------------------------------------------------------
819
         */
820
0
        if (CPLHashSetLookup(hSetFiles, pszFilename) != nullptr)
821
0
            return;
822
823
        /* --------------------------------------------------------------------
824
         */
825
        /*      Grow array if necessary */
826
        /* --------------------------------------------------------------------
827
         */
828
0
        if (*pnSize + 1 >= *pnMaxSize)
829
0
        {
830
0
            *pnMaxSize = std::max(*pnSize + 2, 2 + 2 * (*pnMaxSize));
831
0
            *ppapszFileList = static_cast<char **>(
832
0
                CPLRealloc(*ppapszFileList, sizeof(char *) * (*pnMaxSize)));
833
0
        }
834
835
        /* --------------------------------------------------------------------
836
         */
837
        /*      Add the string to the list */
838
        /* --------------------------------------------------------------------
839
         */
840
0
        (*ppapszFileList)[*pnSize] = CPLStrdup(pszFilename);
841
0
        (*ppapszFileList)[(*pnSize + 1)] = nullptr;
842
0
        CPLHashSetInsert(hSetFiles, (*ppapszFileList)[*pnSize]);
843
844
0
        (*pnSize)++;
845
0
    }
846
0
}
847
848
/************************************************************************/
849
/*                             OpenSource()                             */
850
/************************************************************************/
851
852
void VRTSimpleSource::OpenSource() const
853
0
{
854
0
    CPLAssert(m_poRasterBand == nullptr);
855
856
    /* ----------------------------------------------------------------- */
857
    /*      Create a proxy dataset                                       */
858
    /* ----------------------------------------------------------------- */
859
0
    GDALProxyPoolDataset *proxyDS = nullptr;
860
0
    std::string osKeyMapSharedSources;
861
0
    if (m_poMapSharedSources)
862
0
    {
863
0
        osKeyMapSharedSources = m_osSrcDSName;
864
0
        for (int i = 0; i < m_aosOpenOptions.size(); ++i)
865
0
        {
866
0
            osKeyMapSharedSources += "||";
867
0
            osKeyMapSharedSources += m_aosOpenOptions[i];
868
0
        }
869
870
0
        proxyDS = cpl::down_cast<GDALProxyPoolDataset *>(
871
0
            m_poMapSharedSources->Get(osKeyMapSharedSources));
872
0
    }
873
874
0
    if (proxyDS == nullptr)
875
0
    {
876
0
        int bShared = true;
877
0
        if (m_nExplicitSharedStatus != -1)
878
0
            bShared = m_nExplicitSharedStatus;
879
880
0
        const CPLString osUniqueHandle(CPLSPrintf("%p", m_poMapSharedSources));
881
0
        proxyDS = GDALProxyPoolDataset::Create(
882
0
            m_osSrcDSName, m_aosOpenOptions.List(), GA_ReadOnly, bShared,
883
0
            osUniqueHandle.c_str());
884
0
        if (proxyDS == nullptr)
885
0
            return;
886
0
    }
887
0
    else
888
0
    {
889
0
        proxyDS->Reference();
890
0
    }
891
892
0
    if (m_bGetMaskBand)
893
0
    {
894
0
        GDALProxyPoolRasterBand *poMaskBand =
895
0
            cpl::down_cast<GDALProxyPoolRasterBand *>(
896
0
                proxyDS->GetRasterBand(m_nBand));
897
0
        poMaskBand->AddSrcMaskBandDescriptionFromUnderlying();
898
0
    }
899
900
    /* -------------------------------------------------------------------- */
901
    /*      Get the raster band.                                            */
902
    /* -------------------------------------------------------------------- */
903
904
0
    m_poRasterBand = proxyDS->GetRasterBand(m_nBand);
905
0
    if (m_poRasterBand == nullptr || !ValidateOpenedBand(m_poRasterBand))
906
0
    {
907
0
        proxyDS->ReleaseRef();
908
0
        return;
909
0
    }
910
911
0
    if (m_bGetMaskBand)
912
0
    {
913
0
        m_poRasterBand = m_poRasterBand->GetMaskBand();
914
0
        if (m_poRasterBand == nullptr)
915
0
        {
916
0
            proxyDS->ReleaseRef();
917
0
            return;
918
0
        }
919
0
        m_poMaskBandMainBand = m_poRasterBand;
920
0
    }
921
922
0
    if (m_poMapSharedSources)
923
0
    {
924
0
        m_poMapSharedSources->Insert(osKeyMapSharedSources, proxyDS);
925
0
    }
926
0
}
927
928
/************************************************************************/
929
/*                           GetRasterBand()                            */
930
/************************************************************************/
931
932
GDALRasterBand *VRTSimpleSource::GetRasterBand() const
933
0
{
934
0
    if (m_poRasterBand == nullptr)
935
0
        OpenSource();
936
0
    return m_poRasterBand;
937
0
}
938
939
/************************************************************************/
940
/*                        GetMaskBandMainBand()                         */
941
/************************************************************************/
942
943
GDALRasterBand *VRTSimpleSource::GetMaskBandMainBand()
944
0
{
945
0
    if (m_poRasterBand == nullptr)
946
0
        OpenSource();
947
0
    return m_poMaskBandMainBand;
948
0
}
949
950
/************************************************************************/
951
/*                       IsSameExceptBandNumber()                       */
952
/************************************************************************/
953
954
bool VRTSimpleSource::IsSameExceptBandNumber(
955
    const VRTSimpleSource *poOtherSource) const
956
0
{
957
0
    return m_dfSrcXOff == poOtherSource->m_dfSrcXOff &&
958
0
           m_dfSrcYOff == poOtherSource->m_dfSrcYOff &&
959
0
           m_dfSrcXSize == poOtherSource->m_dfSrcXSize &&
960
0
           m_dfSrcYSize == poOtherSource->m_dfSrcYSize &&
961
0
           m_dfDstXOff == poOtherSource->m_dfDstXOff &&
962
0
           m_dfDstYOff == poOtherSource->m_dfDstYOff &&
963
0
           m_dfDstXSize == poOtherSource->m_dfDstXSize &&
964
0
           m_dfDstYSize == poOtherSource->m_dfDstYSize &&
965
0
           m_osSrcDSName == poOtherSource->m_osSrcDSName;
966
0
}
967
968
/************************************************************************/
969
/*                              SrcToDst()                              */
970
/*                                                                      */
971
/*      Note: this is a no-op if the both src and dst windows are unset */
972
/************************************************************************/
973
974
void VRTSimpleSource::SrcToDst(double dfX, double dfY, double &dfXOut,
975
                               double &dfYOut) const
976
977
0
{
978
0
    dfXOut = ((dfX - m_dfSrcXOff) / m_dfSrcXSize) * m_dfDstXSize + m_dfDstXOff;
979
0
    dfYOut = ((dfY - m_dfSrcYOff) / m_dfSrcYSize) * m_dfDstYSize + m_dfDstYOff;
980
0
}
981
982
/************************************************************************/
983
/*                              DstToSrc()                              */
984
/*                                                                      */
985
/*      Note: this is a no-op if the both src and dst windows are unset */
986
/************************************************************************/
987
988
void VRTSimpleSource::DstToSrc(double dfX, double dfY, double &dfXOut,
989
                               double &dfYOut) const
990
991
0
{
992
0
    dfXOut = ((dfX - m_dfDstXOff) / m_dfDstXSize) * m_dfSrcXSize + m_dfSrcXOff;
993
0
    dfYOut = ((dfY - m_dfDstYOff) / m_dfDstYSize) * m_dfSrcYSize + m_dfSrcYOff;
994
0
}
995
996
/************************************************************************/
997
/*                          GetSrcDstWindow()                           */
998
/************************************************************************/
999
1000
int VRTSimpleSource::GetSrcDstWindow(
1001
    double dfXOff, double dfYOff, double dfXSize, double dfYSize, int nBufXSize,
1002
    int nBufYSize, double *pdfReqXOff, double *pdfReqYOff, double *pdfReqXSize,
1003
    double *pdfReqYSize, int *pnReqXOff, int *pnReqYOff, int *pnReqXSize,
1004
    int *pnReqYSize, int *pnOutXOff, int *pnOutYOff, int *pnOutXSize,
1005
    int *pnOutYSize, bool &bErrorOut)
1006
1007
0
{
1008
0
    return GetSrcDstWindow(
1009
0
        dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
1010
0
        GRIORA_Bilinear,  // to stick with legacy behavior
1011
0
        pdfReqXOff, pdfReqYOff, pdfReqXSize, pdfReqYSize, pnReqXOff, pnReqYOff,
1012
0
        pnReqXSize, pnReqYSize, pnOutXOff, pnOutYOff, pnOutXSize, pnOutYSize,
1013
0
        bErrorOut);
1014
0
}
1015
1016
int VRTSimpleSource::GetSrcDstWindow(
1017
    double dfXOff, double dfYOff, double dfXSize, double dfYSize, int nBufXSize,
1018
    int nBufYSize, GDALRIOResampleAlg eResampleAlg, double *pdfReqXOff,
1019
    double *pdfReqYOff, double *pdfReqXSize, double *pdfReqYSize,
1020
    int *pnReqXOff, int *pnReqYOff, int *pnReqXSize, int *pnReqYSize,
1021
    int *pnOutXOff, int *pnOutYOff, int *pnOutXSize, int *pnOutYSize,
1022
    bool &bErrorOut)
1023
1024
0
{
1025
0
    bErrorOut = false;
1026
1027
0
    if (m_dfSrcXSize == 0.0 || m_dfSrcYSize == 0.0 || m_dfDstXSize == 0.0 ||
1028
0
        m_dfDstYSize == 0.0)
1029
0
    {
1030
0
        return FALSE;
1031
0
    }
1032
1033
0
    const bool bDstWinSet = IsDstWinSet();
1034
1035
0
#ifdef DEBUG
1036
0
    const bool bSrcWinSet = IsSrcWinSet();
1037
1038
0
    if (bSrcWinSet != bDstWinSet)
1039
0
    {
1040
0
        return FALSE;
1041
0
    }
1042
0
#endif
1043
1044
    /* -------------------------------------------------------------------- */
1045
    /*      If the input window completely misses the portion of the        */
1046
    /*      virtual dataset provided by this source we have nothing to do.  */
1047
    /* -------------------------------------------------------------------- */
1048
0
    if (bDstWinSet)
1049
0
    {
1050
0
        if (dfXOff >= m_dfDstXOff + m_dfDstXSize ||
1051
0
            dfYOff >= m_dfDstYOff + m_dfDstYSize ||
1052
0
            dfXOff + dfXSize <= m_dfDstXOff || dfYOff + dfYSize <= m_dfDstYOff)
1053
0
            return FALSE;
1054
0
    }
1055
1056
    /* -------------------------------------------------------------------- */
1057
    /*      This request window corresponds to the whole output buffer.     */
1058
    /* -------------------------------------------------------------------- */
1059
0
    *pnOutXOff = 0;
1060
0
    *pnOutYOff = 0;
1061
0
    *pnOutXSize = nBufXSize;
1062
0
    *pnOutYSize = nBufYSize;
1063
1064
    /* -------------------------------------------------------------------- */
1065
    /*      If the input window extents outside the portion of the on       */
1066
    /*      the virtual file that this source can set, then clip down       */
1067
    /*      the requested window.                                           */
1068
    /* -------------------------------------------------------------------- */
1069
0
    bool bModifiedX = false;
1070
0
    bool bModifiedY = false;
1071
0
    double dfRXOff = dfXOff;
1072
0
    double dfRYOff = dfYOff;
1073
0
    double dfRXSize = dfXSize;
1074
0
    double dfRYSize = dfYSize;
1075
1076
0
    if (bDstWinSet)
1077
0
    {
1078
0
        if (dfRXOff < m_dfDstXOff)
1079
0
        {
1080
0
            dfRXSize = dfRXSize + dfRXOff - m_dfDstXOff;
1081
0
            dfRXOff = m_dfDstXOff;
1082
0
            bModifiedX = true;
1083
0
        }
1084
1085
0
        if (dfRYOff < m_dfDstYOff)
1086
0
        {
1087
0
            dfRYSize = dfRYSize + dfRYOff - m_dfDstYOff;
1088
0
            dfRYOff = m_dfDstYOff;
1089
0
            bModifiedY = true;
1090
0
        }
1091
1092
0
        if (dfRXOff + dfRXSize > m_dfDstXOff + m_dfDstXSize)
1093
0
        {
1094
0
            dfRXSize = m_dfDstXOff + m_dfDstXSize - dfRXOff;
1095
0
            bModifiedX = true;
1096
0
        }
1097
1098
0
        if (dfRYOff + dfRYSize > m_dfDstYOff + m_dfDstYSize)
1099
0
        {
1100
0
            dfRYSize = m_dfDstYOff + m_dfDstYSize - dfRYOff;
1101
0
            bModifiedY = true;
1102
0
        }
1103
0
    }
1104
1105
    /* -------------------------------------------------------------------- */
1106
    /*      Translate requested region in virtual file into the source      */
1107
    /*      band coordinates.                                               */
1108
    /* -------------------------------------------------------------------- */
1109
0
    const double dfScaleX = m_dfSrcXSize / m_dfDstXSize;
1110
0
    const double dfScaleY = m_dfSrcYSize / m_dfDstYSize;
1111
1112
0
    *pdfReqXOff = (dfRXOff - m_dfDstXOff) * dfScaleX + m_dfSrcXOff;
1113
0
    *pdfReqYOff = (dfRYOff - m_dfDstYOff) * dfScaleY + m_dfSrcYOff;
1114
0
    *pdfReqXSize = dfRXSize * dfScaleX;
1115
0
    *pdfReqYSize = dfRYSize * dfScaleY;
1116
1117
0
    if (!std::isfinite(*pdfReqXOff) || !std::isfinite(*pdfReqYOff) ||
1118
0
        !std::isfinite(*pdfReqXSize) || !std::isfinite(*pdfReqYSize) ||
1119
0
        *pdfReqXOff > INT_MAX || *pdfReqYOff > INT_MAX || *pdfReqXSize < 0 ||
1120
0
        *pdfReqYSize < 0)
1121
0
    {
1122
0
        return FALSE;
1123
0
    }
1124
1125
    /* -------------------------------------------------------------------- */
1126
    /*      Clamp within the bounds of the available source data.           */
1127
    /* -------------------------------------------------------------------- */
1128
0
    if (*pdfReqXOff < 0)
1129
0
    {
1130
0
        *pdfReqXSize += *pdfReqXOff;
1131
0
        *pdfReqXOff = 0;
1132
0
        bModifiedX = true;
1133
0
    }
1134
0
    if (*pdfReqYOff < 0)
1135
0
    {
1136
0
        *pdfReqYSize += *pdfReqYOff;
1137
0
        *pdfReqYOff = 0;
1138
0
        bModifiedY = true;
1139
0
    }
1140
1141
0
    constexpr double EPSILON = 1e-10;
1142
0
    if (eResampleAlg == GRIORA_NearestNeighbour &&
1143
0
        (std::fabs(m_dfSrcXOff - std::round(m_dfSrcXOff)) > EPSILON ||
1144
0
         std::fabs(m_dfSrcYOff - std::round(m_dfSrcYOff)) > EPSILON ||
1145
0
         std::fabs(m_dfDstXOff - std::round(m_dfDstXOff)) > EPSILON ||
1146
0
         std::fabs(m_dfDstYOff - std::round(m_dfDstYOff)) > EPSILON))
1147
0
    {
1148
        // Align the behavior with https://github.com/OSGeo/gdal/blob/0e5bb914b80d049198d9a85e04b22c9b0590cc36/gcore/rasterio.cpp#L799
1149
        // in the way we round coordinates
1150
        // Add small epsilon to avoid some numeric precision issues.
1151
        // Covered by test_vrt_read_multithreaded_non_integer_coordinates_nearest test
1152
0
        *pnReqXOff = static_cast<int>(*pdfReqXOff + 0.5 + EPSILON);
1153
0
        *pnReqYOff = static_cast<int>(*pdfReqYOff + 0.5 + EPSILON);
1154
0
    }
1155
0
    else
1156
0
    {
1157
0
        *pnReqXOff = static_cast<int>(*pdfReqXOff);
1158
0
        *pnReqYOff = static_cast<int>(*pdfReqYOff);
1159
0
    }
1160
1161
0
    constexpr double EPS = 1e-3;
1162
0
    constexpr double ONE_MINUS_EPS = 1.0 - EPS;
1163
0
    if (*pdfReqXOff - *pnReqXOff > ONE_MINUS_EPS)
1164
0
    {
1165
0
        (*pnReqXOff)++;
1166
0
        *pdfReqXOff = *pnReqXOff;
1167
0
    }
1168
0
    if (*pdfReqYOff - *pnReqYOff > ONE_MINUS_EPS)
1169
0
    {
1170
0
        (*pnReqYOff)++;
1171
0
        *pdfReqYOff = *pnReqYOff;
1172
0
    }
1173
1174
0
    if (*pdfReqXSize > INT_MAX)
1175
0
        *pnReqXSize = INT_MAX;
1176
0
    else
1177
0
        *pnReqXSize = static_cast<int>(floor(*pdfReqXSize + 0.5));
1178
1179
0
    if (*pdfReqYSize > INT_MAX)
1180
0
        *pnReqYSize = INT_MAX;
1181
0
    else
1182
0
        *pnReqYSize = static_cast<int>(floor(*pdfReqYSize + 0.5));
1183
1184
    /* -------------------------------------------------------------------- */
1185
    /*      Clamp within the bounds of the available source data.           */
1186
    /* -------------------------------------------------------------------- */
1187
1188
0
    if (*pnReqXSize == 0)
1189
0
        *pnReqXSize = 1;
1190
0
    if (*pnReqYSize == 0)
1191
0
        *pnReqYSize = 1;
1192
1193
0
    auto l_band = GetRasterBand();
1194
0
    if (!l_band)
1195
0
    {
1196
0
        bErrorOut = true;
1197
0
        return FALSE;
1198
0
    }
1199
0
    if (*pnReqXSize > INT_MAX - *pnReqXOff ||
1200
0
        *pnReqXOff + *pnReqXSize > l_band->GetXSize())
1201
0
    {
1202
0
        *pnReqXSize = l_band->GetXSize() - *pnReqXOff;
1203
0
        bModifiedX = true;
1204
0
    }
1205
0
    if (*pdfReqXOff + *pdfReqXSize > l_band->GetXSize())
1206
0
    {
1207
0
        *pdfReqXSize = l_band->GetXSize() - *pdfReqXOff;
1208
0
        bModifiedX = true;
1209
0
    }
1210
1211
0
    if (*pnReqYSize > INT_MAX - *pnReqYOff ||
1212
0
        *pnReqYOff + *pnReqYSize > l_band->GetYSize())
1213
0
    {
1214
0
        *pnReqYSize = l_band->GetYSize() - *pnReqYOff;
1215
0
        bModifiedY = true;
1216
0
    }
1217
0
    if (*pdfReqYOff + *pdfReqYSize > l_band->GetYSize())
1218
0
    {
1219
0
        *pdfReqYSize = l_band->GetYSize() - *pdfReqYOff;
1220
0
        bModifiedY = true;
1221
0
    }
1222
1223
    /* -------------------------------------------------------------------- */
1224
    /*      Don't do anything if the requesting region is completely off    */
1225
    /*      the source image.                                               */
1226
    /* -------------------------------------------------------------------- */
1227
0
    if (*pnReqXOff >= l_band->GetXSize() || *pnReqYOff >= l_band->GetYSize() ||
1228
0
        *pnReqXSize <= 0 || *pnReqYSize <= 0)
1229
0
    {
1230
0
        return FALSE;
1231
0
    }
1232
1233
    /* -------------------------------------------------------------------- */
1234
    /*      If we haven't had to modify the source rectangle, then the      */
1235
    /*      destination rectangle must be the whole region.                 */
1236
    /* -------------------------------------------------------------------- */
1237
0
    if (bModifiedX || bModifiedY)
1238
0
    {
1239
        /* --------------------------------------------------------------------
1240
         */
1241
        /*      Now transform this possibly reduced request back into the */
1242
        /*      destination buffer coordinates in case the output region is */
1243
        /*      less than the whole buffer. */
1244
        /* --------------------------------------------------------------------
1245
         */
1246
0
        double dfDstULX = 0.0;
1247
0
        double dfDstULY = 0.0;
1248
0
        double dfDstLRX = 0.0;
1249
0
        double dfDstLRY = 0.0;
1250
1251
0
        SrcToDst(*pdfReqXOff, *pdfReqYOff, dfDstULX, dfDstULY);
1252
0
        SrcToDst(*pdfReqXOff + *pdfReqXSize, *pdfReqYOff + *pdfReqYSize,
1253
0
                 dfDstLRX, dfDstLRY);
1254
#if DEBUG_VERBOSE
1255
        CPLDebug("VRT", "dfDstULX=%g dfDstULY=%g dfDstLRX=%g dfDstLRY=%g",
1256
                 dfDstULX, dfDstULY, dfDstLRX, dfDstLRY);
1257
#endif
1258
1259
0
        if (bModifiedX)
1260
0
        {
1261
0
            const double dfScaleWinToBufX = nBufXSize / dfXSize;
1262
1263
0
            const double dfOutXOff = (dfDstULX - dfXOff) * dfScaleWinToBufX;
1264
0
            if (dfOutXOff <= 0)
1265
0
                *pnOutXOff = 0;
1266
0
            else if (dfOutXOff > INT_MAX)
1267
0
                *pnOutXOff = INT_MAX;
1268
0
            else
1269
0
                *pnOutXOff = static_cast<int>(dfOutXOff + EPS);
1270
1271
            // Apply correction on floating-point source window
1272
0
            {
1273
0
                double dfDstDeltaX =
1274
0
                    (dfOutXOff - *pnOutXOff) / dfScaleWinToBufX;
1275
0
                double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
1276
0
                *pdfReqXOff -= dfSrcDeltaX;
1277
0
                *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
1278
0
                                        static_cast<double>(INT_MAX));
1279
0
            }
1280
1281
0
            double dfOutRightXOff = (dfDstLRX - dfXOff) * dfScaleWinToBufX;
1282
0
            if (dfOutRightXOff < dfOutXOff)
1283
0
                return FALSE;
1284
0
            if (dfOutRightXOff > INT_MAX)
1285
0
                dfOutRightXOff = INT_MAX;
1286
0
            const int nOutRightXOff =
1287
0
                static_cast<int>(ceil(dfOutRightXOff - EPS));
1288
0
            *pnOutXSize = nOutRightXOff - *pnOutXOff;
1289
1290
0
            if (*pnOutXSize > INT_MAX - *pnOutXOff ||
1291
0
                *pnOutXOff + *pnOutXSize > nBufXSize)
1292
0
                *pnOutXSize = nBufXSize - *pnOutXOff;
1293
1294
            // Apply correction on floating-point source window
1295
0
            {
1296
0
                double dfDstDeltaX =
1297
0
                    (nOutRightXOff - dfOutRightXOff) / dfScaleWinToBufX;
1298
0
                double dfSrcDeltaX = dfDstDeltaX / m_dfDstXSize * m_dfSrcXSize;
1299
0
                *pdfReqXSize = std::min(*pdfReqXSize + dfSrcDeltaX,
1300
0
                                        static_cast<double>(INT_MAX));
1301
0
            }
1302
0
        }
1303
1304
0
        if (bModifiedY)
1305
0
        {
1306
0
            const double dfScaleWinToBufY = nBufYSize / dfYSize;
1307
1308
0
            const double dfOutYOff = (dfDstULY - dfYOff) * dfScaleWinToBufY;
1309
0
            if (dfOutYOff <= 0)
1310
0
                *pnOutYOff = 0;
1311
0
            else if (dfOutYOff > INT_MAX)
1312
0
                *pnOutYOff = INT_MAX;
1313
0
            else
1314
0
                *pnOutYOff = static_cast<int>(dfOutYOff + EPS);
1315
1316
            // Apply correction on floating-point source window
1317
0
            {
1318
0
                double dfDstDeltaY =
1319
0
                    (dfOutYOff - *pnOutYOff) / dfScaleWinToBufY;
1320
0
                double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
1321
0
                *pdfReqYOff -= dfSrcDeltaY;
1322
0
                *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
1323
0
                                        static_cast<double>(INT_MAX));
1324
0
            }
1325
1326
0
            double dfOutTopYOff = (dfDstLRY - dfYOff) * dfScaleWinToBufY;
1327
0
            if (dfOutTopYOff < dfOutYOff)
1328
0
                return FALSE;
1329
0
            if (dfOutTopYOff > INT_MAX)
1330
0
                dfOutTopYOff = INT_MAX;
1331
0
            const int nOutTopYOff = static_cast<int>(ceil(dfOutTopYOff - EPS));
1332
0
            *pnOutYSize = nOutTopYOff - *pnOutYOff;
1333
1334
0
            if (*pnOutYSize > INT_MAX - *pnOutYOff ||
1335
0
                *pnOutYOff + *pnOutYSize > nBufYSize)
1336
0
                *pnOutYSize = nBufYSize - *pnOutYOff;
1337
1338
            // Apply correction on floating-point source window
1339
0
            {
1340
0
                double dfDstDeltaY =
1341
0
                    (nOutTopYOff - dfOutTopYOff) / dfScaleWinToBufY;
1342
0
                double dfSrcDeltaY = dfDstDeltaY / m_dfDstYSize * m_dfSrcYSize;
1343
0
                *pdfReqYSize = std::min(*pdfReqYSize + dfSrcDeltaY,
1344
0
                                        static_cast<double>(INT_MAX));
1345
0
            }
1346
0
        }
1347
1348
0
        if (*pnOutXSize < 1 || *pnOutYSize < 1)
1349
0
            return FALSE;
1350
0
    }
1351
1352
0
    *pdfReqXOff = RoundIfCloseToInt(*pdfReqXOff);
1353
0
    *pdfReqYOff = RoundIfCloseToInt(*pdfReqYOff);
1354
0
    *pdfReqXSize = RoundIfCloseToInt(*pdfReqXSize);
1355
0
    *pdfReqYSize = RoundIfCloseToInt(*pdfReqYSize);
1356
1357
0
    return TRUE;
1358
0
}
1359
1360
/************************************************************************/
1361
/*                        NeedMaxValAdjustment()                        */
1362
/************************************************************************/
1363
1364
int VRTSimpleSource::NeedMaxValAdjustment() const
1365
0
{
1366
0
    if (!m_nMaxValue)
1367
0
        return FALSE;
1368
1369
0
    auto l_band = GetRasterBand();
1370
0
    if (!l_band)
1371
0
        return FALSE;
1372
0
    const char *pszNBITS =
1373
0
        l_band->GetMetadataItem(GDALMD_NBITS, GDAL_MDD_IMAGE_STRUCTURE);
1374
0
    const int nBits = (pszNBITS) ? atoi(pszNBITS) : 0;
1375
0
    if (nBits >= 1 && nBits <= 31)
1376
0
    {
1377
0
        const int nBandMaxValue = static_cast<int>((1U << nBits) - 1);
1378
0
        return nBandMaxValue > m_nMaxValue;
1379
0
    }
1380
0
    return TRUE;
1381
0
}
1382
1383
/************************************************************************/
1384
/*                             CopyWordIn()                             */
1385
/************************************************************************/
1386
1387
template <class DstType>
1388
static void CopyWordIn(const void *pSrcVal, GDALDataType eSrcType,
1389
                       DstType *pDstVal, GDALDataType eDstType)
1390
0
{
1391
0
    switch (eSrcType)
1392
0
    {
1393
0
        case GDT_UInt8:
1394
0
            GDALCopyWord(*static_cast<const uint8_t *>(pSrcVal), *pDstVal);
1395
0
            break;
1396
0
        case GDT_Int8:
1397
0
            GDALCopyWord(*static_cast<const int8_t *>(pSrcVal), *pDstVal);
1398
0
            break;
1399
0
        case GDT_UInt16:
1400
0
            GDALCopyWord(*static_cast<const uint16_t *>(pSrcVal), *pDstVal);
1401
0
            break;
1402
0
        case GDT_Int16:
1403
0
            GDALCopyWord(*static_cast<const int16_t *>(pSrcVal), *pDstVal);
1404
0
            break;
1405
0
        case GDT_UInt32:
1406
0
            GDALCopyWord(*static_cast<const uint32_t *>(pSrcVal), *pDstVal);
1407
0
            break;
1408
0
        case GDT_Int32:
1409
0
            GDALCopyWord(*static_cast<const int32_t *>(pSrcVal), *pDstVal);
1410
0
            break;
1411
0
        case GDT_UInt64:
1412
0
            GDALCopyWord(*static_cast<const uint64_t *>(pSrcVal), *pDstVal);
1413
0
            break;
1414
0
        case GDT_Int64:
1415
0
            GDALCopyWord(*static_cast<const int64_t *>(pSrcVal), *pDstVal);
1416
0
            break;
1417
0
        case GDT_Float16:
1418
0
            GDALCopyWord(*static_cast<const GFloat16 *>(pSrcVal), *pDstVal);
1419
0
            break;
1420
0
        case GDT_Float32:
1421
0
            GDALCopyWord(*static_cast<const float *>(pSrcVal), *pDstVal);
1422
0
            break;
1423
0
        case GDT_Float64:
1424
0
            GDALCopyWord(*static_cast<const double *>(pSrcVal), *pDstVal);
1425
0
            break;
1426
0
        case GDT_CInt16:
1427
0
        case GDT_CInt32:
1428
0
        case GDT_CFloat16:
1429
0
        case GDT_CFloat32:
1430
0
        case GDT_CFloat64:
1431
0
            GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1);
1432
0
            break;
1433
0
        case GDT_Unknown:
1434
0
        case GDT_TypeCount:
1435
0
            CPLAssert(false);
1436
0
    }
1437
0
}
1438
1439
/************************************************************************/
1440
/*                            CopyWordOut()                             */
1441
/************************************************************************/
1442
1443
template <class SrcType>
1444
static void CopyWordOut(const SrcType *pSrcVal, GDALDataType eSrcType,
1445
                        void *pDstVal, GDALDataType eDstType)
1446
0
{
1447
0
    switch (eDstType)
1448
0
    {
1449
0
        case GDT_UInt8:
1450
0
            GDALCopyWord(*pSrcVal, *static_cast<uint8_t *>(pDstVal));
1451
0
            break;
1452
0
        case GDT_Int8:
1453
0
            GDALCopyWord(*pSrcVal, *static_cast<int8_t *>(pDstVal));
1454
0
            break;
1455
0
        case GDT_UInt16:
1456
0
            GDALCopyWord(*pSrcVal, *static_cast<uint16_t *>(pDstVal));
1457
0
            break;
1458
0
        case GDT_Int16:
1459
0
            GDALCopyWord(*pSrcVal, *static_cast<int16_t *>(pDstVal));
1460
0
            break;
1461
0
        case GDT_UInt32:
1462
0
            GDALCopyWord(*pSrcVal, *static_cast<uint32_t *>(pDstVal));
1463
0
            break;
1464
0
        case GDT_Int32:
1465
0
            GDALCopyWord(*pSrcVal, *static_cast<int32_t *>(pDstVal));
1466
0
            break;
1467
0
        case GDT_UInt64:
1468
0
            GDALCopyWord(*pSrcVal, *static_cast<uint64_t *>(pDstVal));
1469
0
            break;
1470
0
        case GDT_Int64:
1471
0
            GDALCopyWord(*pSrcVal, *static_cast<int64_t *>(pDstVal));
1472
0
            break;
1473
0
        case GDT_Float16:
1474
0
            GDALCopyWord(*pSrcVal, *static_cast<GFloat16 *>(pDstVal));
1475
0
            break;
1476
0
        case GDT_Float32:
1477
0
            GDALCopyWord(*pSrcVal, *static_cast<float *>(pDstVal));
1478
0
            break;
1479
0
        case GDT_Float64:
1480
0
            GDALCopyWord(*pSrcVal, *static_cast<double *>(pDstVal));
1481
0
            break;
1482
0
        case GDT_CInt16:
1483
0
        case GDT_CInt32:
1484
0
        case GDT_CFloat16:
1485
0
        case GDT_CFloat32:
1486
0
        case GDT_CFloat64:
1487
0
            GDALCopyWords(pSrcVal, eSrcType, 0, pDstVal, eDstType, 0, 1);
1488
0
            break;
1489
0
        case GDT_Unknown:
1490
0
        case GDT_TypeCount:
1491
0
            CPLAssert(false);
1492
0
    }
1493
0
}
Unexecuted instantiation: vrtsources.cpp:void CopyWordOut<int>(int const*, GDALDataType, void*, GDALDataType)
Unexecuted instantiation: vrtsources.cpp:void CopyWordOut<double>(double const*, GDALDataType, void*, GDALDataType)
Unexecuted instantiation: vrtsources.cpp:void CopyWordOut<unsigned char>(unsigned char const*, GDALDataType, void*, GDALDataType)
Unexecuted instantiation: vrtsources.cpp:void CopyWordOut<short>(short const*, GDALDataType, void*, GDALDataType)
Unexecuted instantiation: vrtsources.cpp:void CopyWordOut<unsigned short>(unsigned short const*, GDALDataType, void*, GDALDataType)
Unexecuted instantiation: vrtsources.cpp:void CopyWordOut<float>(float const*, GDALDataType, void*, GDALDataType)
1494
1495
/************************************************************************/
1496
/*                        GDALClampValueToType()                        */
1497
/************************************************************************/
1498
1499
template <class T>
1500
inline void GDALClampValueToType(T *pValue, GDALDataType eClampingType)
1501
0
{
1502
0
    switch (eClampingType)
1503
0
    {
1504
0
        case GDT_UInt8:
1505
0
            *pValue = GDALClampValueToType<T, uint8_t>(*pValue);
1506
0
            break;
1507
0
        case GDT_Int8:
1508
0
            *pValue = GDALClampValueToType<T, int8_t>(*pValue);
1509
0
            break;
1510
0
        case GDT_UInt16:
1511
0
            *pValue = GDALClampValueToType<T, uint16_t>(*pValue);
1512
0
            break;
1513
0
        case GDT_Int16:
1514
0
        case GDT_CInt16:
1515
0
            *pValue = GDALClampValueToType<T, int16_t>(*pValue);
1516
0
            break;
1517
0
        case GDT_UInt32:
1518
0
            *pValue = GDALClampValueToType<T, uint32_t>(*pValue);
1519
0
            break;
1520
0
        case GDT_Int32:
1521
0
        case GDT_CInt32:
1522
0
            *pValue = GDALClampValueToType<T, int32_t>(*pValue);
1523
0
            break;
1524
0
        case GDT_UInt64:
1525
0
            *pValue = GDALClampValueToType<T, uint64_t>(*pValue);
1526
0
            break;
1527
0
        case GDT_Int64:
1528
0
            *pValue = GDALClampValueToType<T, int64_t>(*pValue);
1529
0
            break;
1530
0
        case GDT_Float16:
1531
0
        case GDT_CFloat16:
1532
0
            *pValue = GDALClampValueToType<T, GFloat16>(*pValue);
1533
0
            break;
1534
0
        case GDT_Float32:
1535
0
        case GDT_CFloat32:
1536
0
            *pValue = GDALClampValueToType<T, float>(*pValue);
1537
0
            break;
1538
0
        case GDT_Float64:
1539
0
        case GDT_CFloat64:
1540
0
            *pValue = GDALClampValueToType<T, double>(*pValue);
1541
0
            break;
1542
0
        case GDT_Unknown:
1543
0
        case GDT_TypeCount:
1544
0
            CPLAssert(false);
1545
0
            break;
1546
0
    }
1547
0
}
Unexecuted instantiation: void GDALClampValueToType<unsigned char>(unsigned char*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<signed char>(signed char*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<unsigned short>(unsigned short*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<short>(short*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<unsigned int>(unsigned int*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<int>(int*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<unsigned long>(unsigned long*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<long>(long*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<cpl::Float16>(cpl::Float16*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<float>(float*, GDALDataType)
Unexecuted instantiation: void GDALClampValueToType<double>(double*, GDALDataType)
1548
1549
/************************************************************************/
1550
/*                        GDALClampValueToType()                        */
1551
/************************************************************************/
1552
1553
inline void GDALClampValueToType(void *pValue, GDALDataType eValueType,
1554
                                 GDALDataType eClampingType)
1555
0
{
1556
0
    switch (eValueType)
1557
0
    {
1558
0
        case GDT_UInt8:
1559
0
            GDALClampValueToType(static_cast<uint8_t *>(pValue), eClampingType);
1560
0
            break;
1561
0
        case GDT_Int8:
1562
0
            GDALClampValueToType(static_cast<int8_t *>(pValue), eClampingType);
1563
0
            break;
1564
0
        case GDT_UInt16:
1565
0
            GDALClampValueToType(static_cast<uint16_t *>(pValue),
1566
0
                                 eClampingType);
1567
0
            break;
1568
0
        case GDT_Int16:
1569
0
            GDALClampValueToType(static_cast<int16_t *>(pValue), eClampingType);
1570
0
            break;
1571
0
        case GDT_UInt32:
1572
0
            GDALClampValueToType(static_cast<uint32_t *>(pValue),
1573
0
                                 eClampingType);
1574
0
            break;
1575
0
        case GDT_Int32:
1576
0
            GDALClampValueToType(static_cast<int32_t *>(pValue), eClampingType);
1577
0
            break;
1578
0
        case GDT_UInt64:
1579
0
            GDALClampValueToType(static_cast<uint64_t *>(pValue),
1580
0
                                 eClampingType);
1581
0
            break;
1582
0
        case GDT_Int64:
1583
0
            GDALClampValueToType(static_cast<int64_t *>(pValue), eClampingType);
1584
0
            break;
1585
0
        case GDT_Float16:
1586
0
            GDALClampValueToType(static_cast<GFloat16 *>(pValue),
1587
0
                                 eClampingType);
1588
0
            break;
1589
0
        case GDT_Float32:
1590
0
            GDALClampValueToType(static_cast<float *>(pValue), eClampingType);
1591
0
            break;
1592
0
        case GDT_Float64:
1593
0
            GDALClampValueToType(static_cast<double *>(pValue), eClampingType);
1594
0
            break;
1595
0
        case GDT_CInt16:
1596
0
            GDALClampValueToType(static_cast<int16_t *>(pValue) + 0,
1597
0
                                 eClampingType);
1598
0
            GDALClampValueToType(static_cast<int16_t *>(pValue) + 1,
1599
0
                                 eClampingType);
1600
0
            break;
1601
0
        case GDT_CInt32:
1602
0
            GDALClampValueToType(static_cast<int32_t *>(pValue) + 0,
1603
0
                                 eClampingType);
1604
0
            GDALClampValueToType(static_cast<int32_t *>(pValue) + 1,
1605
0
                                 eClampingType);
1606
0
            break;
1607
0
        case GDT_CFloat16:
1608
0
            GDALClampValueToType(static_cast<GFloat16 *>(pValue) + 0,
1609
0
                                 eClampingType);
1610
0
            GDALClampValueToType(static_cast<GFloat16 *>(pValue) + 1,
1611
0
                                 eClampingType);
1612
0
            break;
1613
0
        case GDT_CFloat32:
1614
0
            GDALClampValueToType(static_cast<float *>(pValue) + 0,
1615
0
                                 eClampingType);
1616
0
            GDALClampValueToType(static_cast<float *>(pValue) + 1,
1617
0
                                 eClampingType);
1618
0
            break;
1619
0
        case GDT_CFloat64:
1620
0
            GDALClampValueToType(static_cast<double *>(pValue) + 0,
1621
0
                                 eClampingType);
1622
0
            GDALClampValueToType(static_cast<double *>(pValue) + 1,
1623
0
                                 eClampingType);
1624
0
            break;
1625
0
        case GDT_Unknown:
1626
0
        case GDT_TypeCount:
1627
0
            CPLAssert(false);
1628
0
            break;
1629
0
    }
1630
0
}
1631
1632
/************************************************************************/
1633
/*                              RasterIO()                              */
1634
/************************************************************************/
1635
1636
CPLErr VRTSimpleSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
1637
                                 int nYOff, int nXSize, int nYSize, void *pData,
1638
                                 int nBufXSize, int nBufYSize,
1639
                                 GDALDataType eBufType, GSpacing nPixelSpace,
1640
                                 GSpacing nLineSpace,
1641
                                 GDALRasterIOExtraArg *psExtraArgIn,
1642
                                 WorkingState & /*oWorkingState*/)
1643
1644
0
{
1645
0
    GDALRasterIOExtraArg sExtraArg;
1646
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1647
0
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
1648
1649
0
    double dfXOff = nXOff;
1650
0
    double dfYOff = nYOff;
1651
0
    double dfXSize = nXSize;
1652
0
    double dfYSize = nYSize;
1653
0
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
1654
0
    {
1655
0
        dfXOff = psExtraArgIn->dfXOff;
1656
0
        dfYOff = psExtraArgIn->dfYOff;
1657
0
        dfXSize = psExtraArgIn->dfXSize;
1658
0
        dfYSize = psExtraArgIn->dfYSize;
1659
0
    }
1660
1661
    // The window we will actually request from the source raster band.
1662
0
    double dfReqXOff = 0.0;
1663
0
    double dfReqYOff = 0.0;
1664
0
    double dfReqXSize = 0.0;
1665
0
    double dfReqYSize = 0.0;
1666
0
    int nReqXOff = 0;
1667
0
    int nReqYOff = 0;
1668
0
    int nReqXSize = 0;
1669
0
    int nReqYSize = 0;
1670
1671
    // The window we will actual set _within_ the pData buffer.
1672
0
    int nOutXOff = 0;
1673
0
    int nOutYOff = 0;
1674
0
    int nOutXSize = 0;
1675
0
    int nOutYSize = 0;
1676
1677
0
    if (!m_osResampling.empty())
1678
0
    {
1679
0
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
1680
0
    }
1681
0
    else if (psExtraArgIn != nullptr)
1682
0
    {
1683
0
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
1684
0
    }
1685
1686
0
    bool bError = false;
1687
0
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
1688
0
                         psExtraArg->eResampleAlg, &dfReqXOff, &dfReqYOff,
1689
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
1690
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1691
0
                         &nOutXSize, &nOutYSize, bError))
1692
0
    {
1693
0
        return bError ? CE_Failure : CE_None;
1694
0
    }
1695
#if DEBUG_VERBOSE
1696
    CPLDebug("VRT",
1697
             "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
1698
             "nBufYSize=%d,\n"
1699
             "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
1700
             "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
1701
             "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
1702
             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
1703
             dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
1704
             nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
1705
#endif
1706
1707
    /* -------------------------------------------------------------------- */
1708
    /*      Actually perform the IO request.                                */
1709
    /* -------------------------------------------------------------------- */
1710
0
    psExtraArg->bFloatingPointWindowValidity = TRUE;
1711
0
    psExtraArg->dfXOff = dfReqXOff;
1712
0
    psExtraArg->dfYOff = dfReqYOff;
1713
0
    psExtraArg->dfXSize = dfReqXSize;
1714
0
    psExtraArg->dfYSize = dfReqYSize;
1715
0
    if (psExtraArgIn)
1716
0
    {
1717
0
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
1718
0
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
1719
0
        if (psExtraArgIn->nVersion >= 2)
1720
0
        {
1721
0
            psExtraArg->bUseOnlyThisScale = psExtraArgIn->bUseOnlyThisScale;
1722
0
        }
1723
0
        psExtraArg->bOperateInBufType =
1724
0
            GDAL_GET_OPERATE_IN_BUF_TYPE(*psExtraArgIn);
1725
0
    }
1726
1727
0
    GByte *pabyOut = static_cast<unsigned char *>(pData) +
1728
0
                     nOutXOff * nPixelSpace +
1729
0
                     static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
1730
1731
0
    auto l_band = GetRasterBand();
1732
0
    if (!l_band)
1733
0
        return CE_Failure;
1734
1735
0
    CPLErr eErr = CE_Failure;
1736
0
    if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
1737
0
                                      eVRTBandDataType))
1738
0
    {
1739
0
        if (!psExtraArg->bOperateInBufType)
1740
0
        {
1741
0
            const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
1742
0
            void *pTemp =
1743
0
                VSI_MALLOC3_VERBOSE(nOutXSize, nOutYSize, nBandDTSize);
1744
0
            if (pTemp)
1745
0
            {
1746
0
                eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1747
0
                                        nReqYSize, pTemp, nOutXSize, nOutYSize,
1748
0
                                        eVRTBandDataType, 0, 0, psExtraArg);
1749
0
                if (eErr == CE_None)
1750
0
                {
1751
0
                    GByte *pabyTemp = static_cast<GByte *>(pTemp);
1752
0
                    for (int iY = 0; iY < nOutYSize; iY++)
1753
0
                    {
1754
0
                        GDALCopyWords(
1755
0
                            pabyTemp + static_cast<size_t>(iY) * nBandDTSize *
1756
0
                                           nOutXSize,
1757
0
                            eVRTBandDataType, nBandDTSize,
1758
0
                            pabyOut + static_cast<GPtrDiff_t>(iY * nLineSpace),
1759
0
                            eBufType, static_cast<int>(nPixelSpace), nOutXSize);
1760
0
                    }
1761
0
                }
1762
0
                VSIFree(pTemp);
1763
0
            }
1764
0
        }
1765
0
        else
1766
0
        {
1767
0
            eErr =
1768
0
                l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1769
0
                                 nReqYSize, pabyOut, nOutXSize, nOutYSize,
1770
0
                                 eBufType, nPixelSpace, nLineSpace, psExtraArg);
1771
0
            if (eErr == CE_None)
1772
0
            {
1773
0
                for (int j = 0; j < nOutYSize; j++)
1774
0
                {
1775
0
                    for (int i = 0; i < nOutXSize; i++)
1776
0
                    {
1777
0
                        void *pDst = pabyOut + j * nLineSpace + i * nPixelSpace;
1778
0
                        GDALClampValueToType(pDst, eBufType, eVRTBandDataType);
1779
0
                    }
1780
0
                }
1781
0
            }
1782
0
        }
1783
0
    }
1784
0
    else
1785
0
    {
1786
0
        eErr = l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
1787
0
                                nReqYSize, pabyOut, nOutXSize, nOutYSize,
1788
0
                                eBufType, nPixelSpace, nLineSpace, psExtraArg);
1789
0
    }
1790
1791
0
    if (NeedMaxValAdjustment())
1792
0
    {
1793
0
        for (int j = 0; j < nOutYSize; j++)
1794
0
        {
1795
0
            for (int i = 0; i < nOutXSize; i++)
1796
0
            {
1797
0
                GByte *pDst = pabyOut + j * nLineSpace + i * nPixelSpace;
1798
0
                int nVal = 0;
1799
0
                CopyWordIn(pDst, eBufType, &nVal, GDT_Int32);
1800
0
                if (nVal > m_nMaxValue)
1801
0
                    nVal = m_nMaxValue;
1802
0
                CopyWordOut(&nVal, GDT_Int32, pDst, eBufType);
1803
0
            }
1804
0
        }
1805
0
    }
1806
1807
0
    if (psExtraArg->pfnProgress)
1808
0
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
1809
1810
0
    return eErr;
1811
0
}
1812
1813
/************************************************************************/
1814
/*                             GetMinimum()                             */
1815
/************************************************************************/
1816
1817
double VRTSimpleSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
1818
0
{
1819
    // The window we will actually request from the source raster band.
1820
0
    double dfReqXOff = 0.0;
1821
0
    double dfReqYOff = 0.0;
1822
0
    double dfReqXSize = 0.0;
1823
0
    double dfReqYSize = 0.0;
1824
0
    int nReqXOff = 0;
1825
0
    int nReqYOff = 0;
1826
0
    int nReqXSize = 0;
1827
0
    int nReqYSize = 0;
1828
1829
    // The window we will actual set _within_ the pData buffer.
1830
0
    int nOutXOff = 0;
1831
0
    int nOutYOff = 0;
1832
0
    int nOutXSize = 0;
1833
0
    int nOutYSize = 0;
1834
1835
0
    bool bError = false;
1836
0
    auto l_band = GetRasterBand();
1837
0
    if (!l_band ||
1838
0
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize,
1839
0
                         GRIORA_NearestNeighbour, &dfReqXOff, &dfReqYOff,
1840
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
1841
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1842
0
                         &nOutXSize, &nOutYSize, bError) ||
1843
0
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
1844
0
        nReqYSize != l_band->GetYSize())
1845
0
    {
1846
0
        *pbSuccess = FALSE;
1847
0
        return 0;
1848
0
    }
1849
1850
0
    const double dfVal = l_band->GetMinimum(pbSuccess);
1851
0
    if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
1852
0
        return m_nMaxValue;
1853
0
    return dfVal;
1854
0
}
1855
1856
/************************************************************************/
1857
/*                             GetMaximum()                             */
1858
/************************************************************************/
1859
1860
double VRTSimpleSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
1861
0
{
1862
    // The window we will actually request from the source raster band.
1863
0
    double dfReqXOff = 0.0;
1864
0
    double dfReqYOff = 0.0;
1865
0
    double dfReqXSize = 0.0;
1866
0
    double dfReqYSize = 0.0;
1867
0
    int nReqXOff = 0;
1868
0
    int nReqYOff = 0;
1869
0
    int nReqXSize = 0;
1870
0
    int nReqYSize = 0;
1871
1872
    // The window we will actual set _within_ the pData buffer.
1873
0
    int nOutXOff = 0;
1874
0
    int nOutYOff = 0;
1875
0
    int nOutXSize = 0;
1876
0
    int nOutYSize = 0;
1877
1878
0
    bool bError = false;
1879
0
    auto l_band = GetRasterBand();
1880
0
    if (!l_band ||
1881
0
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize,
1882
0
                         GRIORA_NearestNeighbour, &dfReqXOff, &dfReqYOff,
1883
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
1884
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1885
0
                         &nOutXSize, &nOutYSize, bError) ||
1886
0
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
1887
0
        nReqYSize != l_band->GetYSize())
1888
0
    {
1889
0
        *pbSuccess = FALSE;
1890
0
        return 0;
1891
0
    }
1892
1893
0
    const double dfVal = l_band->GetMaximum(pbSuccess);
1894
0
    if (NeedMaxValAdjustment() && dfVal > m_nMaxValue)
1895
0
        return m_nMaxValue;
1896
0
    return dfVal;
1897
0
}
1898
1899
/************************************************************************/
1900
/*                            GetHistogram()                            */
1901
/************************************************************************/
1902
1903
CPLErr VRTSimpleSource::GetHistogram(int nXSize, int nYSize, double dfMin,
1904
                                     double dfMax, int nBuckets,
1905
                                     GUIntBig *panHistogram,
1906
                                     int bIncludeOutOfRange, int bApproxOK,
1907
                                     GDALProgressFunc pfnProgress,
1908
                                     void *pProgressData)
1909
0
{
1910
    // The window we will actually request from the source raster band.
1911
0
    double dfReqXOff = 0.0;
1912
0
    double dfReqYOff = 0.0;
1913
0
    double dfReqXSize = 0.0;
1914
0
    double dfReqYSize = 0.0;
1915
0
    int nReqXOff = 0;
1916
0
    int nReqYOff = 0;
1917
0
    int nReqXSize = 0;
1918
0
    int nReqYSize = 0;
1919
1920
    // The window we will actual set _within_ the pData buffer.
1921
0
    int nOutXOff = 0;
1922
0
    int nOutYOff = 0;
1923
0
    int nOutXSize = 0;
1924
0
    int nOutYSize = 0;
1925
1926
0
    bool bError = false;
1927
0
    auto l_band = GetRasterBand();
1928
0
    if (!l_band || NeedMaxValAdjustment() ||
1929
0
        !GetSrcDstWindow(0, 0, nXSize, nYSize, nXSize, nYSize,
1930
0
                         GRIORA_NearestNeighbour, &dfReqXOff, &dfReqYOff,
1931
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
1932
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1933
0
                         &nOutXSize, &nOutYSize, bError) ||
1934
0
        nReqXOff != 0 || nReqYOff != 0 || nReqXSize != l_band->GetXSize() ||
1935
0
        nReqYSize != l_band->GetYSize())
1936
0
    {
1937
0
        return CE_Failure;
1938
0
    }
1939
1940
0
    return l_band->GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
1941
0
                                bIncludeOutOfRange, bApproxOK, pfnProgress,
1942
0
                                pProgressData);
1943
0
}
1944
1945
/************************************************************************/
1946
/*                          DatasetRasterIO()                           */
1947
/************************************************************************/
1948
1949
CPLErr VRTSimpleSource::DatasetRasterIO(
1950
    GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
1951
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1952
    int nBandCount, const int *panBandMap, GSpacing nPixelSpace,
1953
    GSpacing nLineSpace, GSpacing nBandSpace,
1954
    GDALRasterIOExtraArg *psExtraArgIn)
1955
0
{
1956
0
    if (GetType() != VRTSimpleSource::GetTypeStatic())
1957
0
    {
1958
0
        CPLError(CE_Failure, CPLE_NotSupported,
1959
0
                 "DatasetRasterIO() not implemented for %s", GetType());
1960
0
        return CE_Failure;
1961
0
    }
1962
1963
0
    GDALRasterIOExtraArg sExtraArg;
1964
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
1965
0
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
1966
1967
0
    double dfXOff = nXOff;
1968
0
    double dfYOff = nYOff;
1969
0
    double dfXSize = nXSize;
1970
0
    double dfYSize = nYSize;
1971
0
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
1972
0
    {
1973
0
        dfXOff = psExtraArgIn->dfXOff;
1974
0
        dfYOff = psExtraArgIn->dfYOff;
1975
0
        dfXSize = psExtraArgIn->dfXSize;
1976
0
        dfYSize = psExtraArgIn->dfYSize;
1977
0
    }
1978
1979
    // The window we will actually request from the source raster band.
1980
0
    double dfReqXOff = 0.0;
1981
0
    double dfReqYOff = 0.0;
1982
0
    double dfReqXSize = 0.0;
1983
0
    double dfReqYSize = 0.0;
1984
0
    int nReqXOff = 0;
1985
0
    int nReqYOff = 0;
1986
0
    int nReqXSize = 0;
1987
0
    int nReqYSize = 0;
1988
1989
    // The window we will actual set _within_ the pData buffer.
1990
0
    int nOutXOff = 0;
1991
0
    int nOutYOff = 0;
1992
0
    int nOutXSize = 0;
1993
0
    int nOutYSize = 0;
1994
1995
0
    if (!m_osResampling.empty())
1996
0
    {
1997
0
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
1998
0
    }
1999
0
    else if (psExtraArgIn != nullptr)
2000
0
    {
2001
0
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
2002
0
    }
2003
2004
0
    bool bError = false;
2005
0
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
2006
0
                         psExtraArg->eResampleAlg, &dfReqXOff, &dfReqYOff,
2007
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
2008
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
2009
0
                         &nOutXSize, &nOutYSize, bError))
2010
0
    {
2011
0
        return bError ? CE_Failure : CE_None;
2012
0
    }
2013
2014
0
    auto l_band = GetRasterBand();
2015
0
    if (!l_band)
2016
0
        return CE_Failure;
2017
2018
0
    GDALDataset *poDS = l_band->GetDataset();
2019
0
    if (poDS == nullptr)
2020
0
        return CE_Failure;
2021
2022
0
    psExtraArg->bFloatingPointWindowValidity = TRUE;
2023
0
    psExtraArg->dfXOff = dfReqXOff;
2024
0
    psExtraArg->dfYOff = dfReqYOff;
2025
0
    psExtraArg->dfXSize = dfReqXSize;
2026
0
    psExtraArg->dfYSize = dfReqYSize;
2027
0
    if (psExtraArgIn)
2028
0
    {
2029
0
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
2030
0
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
2031
0
        if (psExtraArgIn->nVersion >= 2)
2032
0
        {
2033
0
            psExtraArg->bUseOnlyThisScale = psExtraArgIn->bUseOnlyThisScale;
2034
0
        }
2035
0
        psExtraArg->bOperateInBufType =
2036
0
            GDAL_GET_OPERATE_IN_BUF_TYPE(*psExtraArgIn);
2037
0
    }
2038
2039
0
    GByte *pabyOut = static_cast<unsigned char *>(pData) +
2040
0
                     nOutXOff * nPixelSpace +
2041
0
                     static_cast<GPtrDiff_t>(nOutYOff) * nLineSpace;
2042
2043
0
    CPLErr eErr = CE_Failure;
2044
2045
0
    if (GDALDataTypeIsConversionLossy(l_band->GetRasterDataType(),
2046
0
                                      eVRTBandDataType))
2047
0
    {
2048
0
        if (!psExtraArg->bOperateInBufType)
2049
0
        {
2050
0
            const int nBandDTSize = GDALGetDataTypeSizeBytes(eVRTBandDataType);
2051
0
            void *pTemp = VSI_MALLOC3_VERBOSE(
2052
0
                nOutXSize, nOutYSize,
2053
0
                cpl::fits_on<int>(nBandDTSize * nBandCount));
2054
0
            if (pTemp)
2055
0
            {
2056
0
                eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
2057
0
                                      nReqYSize, pTemp, nOutXSize, nOutYSize,
2058
0
                                      eVRTBandDataType, nBandCount, panBandMap,
2059
0
                                      0, 0, 0, psExtraArg);
2060
0
                if (eErr == CE_None)
2061
0
                {
2062
0
                    GByte *pabyTemp = static_cast<GByte *>(pTemp);
2063
0
                    const size_t nSrcBandSpace =
2064
0
                        static_cast<size_t>(nOutYSize) * nOutXSize *
2065
0
                        nBandDTSize;
2066
0
                    for (int iBand = 0; iBand < nBandCount; iBand++)
2067
0
                    {
2068
0
                        for (int iY = 0; iY < nOutYSize; iY++)
2069
0
                        {
2070
0
                            GDALCopyWords(pabyTemp + iBand * nSrcBandSpace +
2071
0
                                              static_cast<size_t>(iY) *
2072
0
                                                  nBandDTSize * nOutXSize,
2073
0
                                          eVRTBandDataType, nBandDTSize,
2074
0
                                          pabyOut + static_cast<GPtrDiff_t>(
2075
0
                                                        iY * nLineSpace +
2076
0
                                                        iBand * nBandSpace),
2077
0
                                          eBufType,
2078
0
                                          static_cast<int>(nPixelSpace),
2079
0
                                          nOutXSize);
2080
0
                        }
2081
0
                    }
2082
0
                }
2083
0
                VSIFree(pTemp);
2084
0
            }
2085
0
        }
2086
0
        else
2087
0
        {
2088
0
            eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize,
2089
0
                                  nReqYSize, pabyOut, nOutXSize, nOutYSize,
2090
0
                                  eBufType, nBandCount, panBandMap, nPixelSpace,
2091
0
                                  nLineSpace, nBandSpace, psExtraArg);
2092
0
            if (eErr == CE_None)
2093
0
            {
2094
0
                for (int k = 0; k < nBandCount; k++)
2095
0
                {
2096
0
                    for (int j = 0; j < nOutYSize; j++)
2097
0
                    {
2098
0
                        for (int i = 0; i < nOutXSize; i++)
2099
0
                        {
2100
0
                            void *pDst = pabyOut + k * nBandSpace +
2101
0
                                         j * nLineSpace + i * nPixelSpace;
2102
0
                            GDALClampValueToType(pDst, eBufType,
2103
0
                                                 eVRTBandDataType);
2104
0
                        }
2105
0
                    }
2106
0
                }
2107
0
            }
2108
0
        }
2109
0
    }
2110
0
    else
2111
0
    {
2112
0
        eErr = poDS->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2113
0
                              pabyOut, nOutXSize, nOutYSize, eBufType,
2114
0
                              nBandCount, panBandMap, nPixelSpace, nLineSpace,
2115
0
                              nBandSpace, psExtraArg);
2116
0
    }
2117
2118
0
    if (NeedMaxValAdjustment())
2119
0
    {
2120
0
        for (int k = 0; k < nBandCount; k++)
2121
0
        {
2122
0
            for (int j = 0; j < nOutYSize; j++)
2123
0
            {
2124
0
                for (int i = 0; i < nOutXSize; i++)
2125
0
                {
2126
0
                    void *pDst = pabyOut + k * nBandSpace + j * nLineSpace +
2127
0
                                 i * nPixelSpace;
2128
0
                    int nVal = 0;
2129
0
                    CopyWordIn(pDst, eBufType, &nVal, GDT_Int32);
2130
2131
0
                    if (nVal > m_nMaxValue)
2132
0
                        nVal = m_nMaxValue;
2133
2134
0
                    CopyWordOut(&nVal, GDT_Int32, pDst, eBufType);
2135
0
                }
2136
0
            }
2137
0
        }
2138
0
    }
2139
2140
0
    if (psExtraArg->pfnProgress)
2141
0
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
2142
2143
0
    return eErr;
2144
0
}
2145
2146
/************************************************************************/
2147
/*                           SetResampling()                            */
2148
/************************************************************************/
2149
2150
void VRTSimpleSource::SetResampling(const char *pszResampling)
2151
0
{
2152
0
    m_osResampling = (pszResampling) ? pszResampling : "";
2153
0
}
2154
2155
/************************************************************************/
2156
/* ==================================================================== */
2157
/*                         VRTAveragedSource                            */
2158
/* ==================================================================== */
2159
/************************************************************************/
2160
2161
/************************************************************************/
2162
/*                         VRTAveragedSource()                          */
2163
/************************************************************************/
2164
2165
VRTAveragedSource::VRTAveragedSource()
2166
0
{
2167
0
}
2168
2169
/************************************************************************/
2170
/*                           GetTypeStatic()                            */
2171
/************************************************************************/
2172
2173
const char *VRTAveragedSource::GetTypeStatic()
2174
0
{
2175
0
    static const char *TYPE = "AveragedSource";
2176
0
    return TYPE;
2177
0
}
2178
2179
/************************************************************************/
2180
/*                              GetType()                               */
2181
/************************************************************************/
2182
2183
const char *VRTAveragedSource::GetType() const
2184
0
{
2185
0
    return GetTypeStatic();
2186
0
}
2187
2188
/************************************************************************/
2189
/*                           SerializeToXML()                           */
2190
/************************************************************************/
2191
2192
CPLXMLNode *VRTAveragedSource::SerializeToXML(const char *pszVRTPath)
2193
2194
0
{
2195
0
    CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
2196
2197
0
    if (psSrc == nullptr)
2198
0
        return nullptr;
2199
2200
0
    CPLFree(psSrc->pszValue);
2201
0
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
2202
2203
0
    return psSrc;
2204
0
}
2205
2206
/************************************************************************/
2207
/*                           SetNoDataValue()                           */
2208
/************************************************************************/
2209
2210
void VRTAveragedSource::SetNoDataValue(double dfNewNoDataValue)
2211
2212
0
{
2213
0
    if (dfNewNoDataValue == VRT_NODATA_UNSET)
2214
0
    {
2215
0
        m_bNoDataSet = FALSE;
2216
0
        m_dfNoDataValue = VRT_NODATA_UNSET;
2217
0
        return;
2218
0
    }
2219
2220
0
    m_bNoDataSet = TRUE;
2221
0
    m_dfNoDataValue = dfNewNoDataValue;
2222
0
}
2223
2224
/************************************************************************/
2225
/*                              RasterIO()                              */
2226
/************************************************************************/
2227
2228
CPLErr VRTAveragedSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
2229
                                   int nYOff, int nXSize, int nYSize,
2230
                                   void *pData, int nBufXSize, int nBufYSize,
2231
                                   GDALDataType eBufType, GSpacing nPixelSpace,
2232
                                   GSpacing nLineSpace,
2233
                                   GDALRasterIOExtraArg *psExtraArgIn,
2234
                                   WorkingState & /*oWorkingState*/)
2235
2236
0
{
2237
0
    GDALRasterIOExtraArg sExtraArg;
2238
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
2239
0
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
2240
2241
0
    double dfXOff = nXOff;
2242
0
    double dfYOff = nYOff;
2243
0
    double dfXSize = nXSize;
2244
0
    double dfYSize = nYSize;
2245
0
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
2246
0
    {
2247
0
        dfXOff = psExtraArgIn->dfXOff;
2248
0
        dfYOff = psExtraArgIn->dfYOff;
2249
0
        dfXSize = psExtraArgIn->dfXSize;
2250
0
        dfYSize = psExtraArgIn->dfYSize;
2251
0
    }
2252
2253
    // The window we will actually request from the source raster band.
2254
0
    double dfReqXOff = 0.0;
2255
0
    double dfReqYOff = 0.0;
2256
0
    double dfReqXSize = 0.0;
2257
0
    double dfReqYSize = 0.0;
2258
0
    int nReqXOff = 0;
2259
0
    int nReqYOff = 0;
2260
0
    int nReqXSize = 0;
2261
0
    int nReqYSize = 0;
2262
2263
    // The window we will actual set _within_ the pData buffer.
2264
0
    int nOutXOff = 0;
2265
0
    int nOutYOff = 0;
2266
0
    int nOutXSize = 0;
2267
0
    int nOutYSize = 0;
2268
2269
0
    if (!m_osResampling.empty())
2270
0
    {
2271
0
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
2272
0
    }
2273
0
    else if (psExtraArgIn != nullptr)
2274
0
    {
2275
0
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
2276
0
    }
2277
2278
0
    bool bError = false;
2279
0
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
2280
0
                         psExtraArg->eResampleAlg, &dfReqXOff, &dfReqYOff,
2281
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
2282
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
2283
0
                         &nOutXSize, &nOutYSize, bError))
2284
0
    {
2285
0
        return bError ? CE_Failure : CE_None;
2286
0
    }
2287
2288
0
    auto l_band = GetRasterBand();
2289
0
    if (!l_band)
2290
0
        return CE_Failure;
2291
2292
    /* -------------------------------------------------------------------- */
2293
    /*      Allocate a temporary buffer to whole the full resolution        */
2294
    /*      data from the area of interest.                                 */
2295
    /* -------------------------------------------------------------------- */
2296
0
    float *const pafSrc = static_cast<float *>(
2297
0
        VSI_MALLOC3_VERBOSE(sizeof(float), nReqXSize, nReqYSize));
2298
0
    if (pafSrc == nullptr)
2299
0
    {
2300
0
        return CE_Failure;
2301
0
    }
2302
2303
    /* -------------------------------------------------------------------- */
2304
    /*      Load it.                                                        */
2305
    /* -------------------------------------------------------------------- */
2306
0
    psExtraArg->bFloatingPointWindowValidity = TRUE;
2307
0
    psExtraArg->dfXOff = dfReqXOff;
2308
0
    psExtraArg->dfYOff = dfReqYOff;
2309
0
    psExtraArg->dfXSize = dfReqXSize;
2310
0
    psExtraArg->dfYSize = dfReqYSize;
2311
0
    if (psExtraArgIn)
2312
0
    {
2313
0
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
2314
0
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
2315
0
        if (psExtraArgIn->nVersion >= 2)
2316
0
        {
2317
0
            psExtraArg->bUseOnlyThisScale = psExtraArgIn->bUseOnlyThisScale;
2318
0
        }
2319
0
    }
2320
2321
0
    const CPLErr eErr = l_band->RasterIO(
2322
0
        GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize, pafSrc, nReqXSize,
2323
0
        nReqYSize, GDT_Float32, 0, 0, psExtraArg);
2324
2325
0
    if (eErr != CE_None)
2326
0
    {
2327
0
        VSIFree(pafSrc);
2328
0
        return eErr;
2329
0
    }
2330
2331
    /* -------------------------------------------------------------------- */
2332
    /*      Do the averaging.                                               */
2333
    /* -------------------------------------------------------------------- */
2334
0
    for (int iBufLine = nOutYOff; iBufLine < nOutYOff + nOutYSize; iBufLine++)
2335
0
    {
2336
0
        const double dfYDst =
2337
0
            (iBufLine / static_cast<double>(nBufYSize)) * nYSize + nYOff;
2338
2339
0
        for (int iBufPixel = nOutXOff; iBufPixel < nOutXOff + nOutXSize;
2340
0
             iBufPixel++)
2341
0
        {
2342
0
            double dfXSrcStart, dfXSrcEnd, dfYSrcStart, dfYSrcEnd;
2343
0
            int iXSrcStart, iYSrcStart, iXSrcEnd, iYSrcEnd;
2344
2345
0
            const double dfXDst =
2346
0
                (iBufPixel / static_cast<double>(nBufXSize)) * nXSize + nXOff;
2347
2348
            // Compute the source image rectangle needed for this pixel.
2349
0
            DstToSrc(dfXDst, dfYDst, dfXSrcStart, dfYSrcStart);
2350
0
            DstToSrc(dfXDst + 1.0, dfYDst + 1.0, dfXSrcEnd, dfYSrcEnd);
2351
2352
            // Convert to integers, assuming that the center of the source
2353
            // pixel must be in our rect to get included.
2354
0
            if (dfXSrcEnd >= dfXSrcStart + 1)
2355
0
            {
2356
0
                iXSrcStart = static_cast<int>(floor(dfXSrcStart + 0.5));
2357
0
                iXSrcEnd = static_cast<int>(floor(dfXSrcEnd + 0.5));
2358
0
            }
2359
0
            else
2360
0
            {
2361
                /* If the resampling factor is less than 100%, the distance */
2362
                /* between the source pixel is < 1, so we stick to nearest */
2363
                /* neighbour */
2364
0
                iXSrcStart = static_cast<int>(floor(dfXSrcStart));
2365
0
                iXSrcEnd = iXSrcStart + 1;
2366
0
            }
2367
0
            if (dfYSrcEnd >= dfYSrcStart + 1)
2368
0
            {
2369
0
                iYSrcStart = static_cast<int>(floor(dfYSrcStart + 0.5));
2370
0
                iYSrcEnd = static_cast<int>(floor(dfYSrcEnd + 0.5));
2371
0
            }
2372
0
            else
2373
0
            {
2374
0
                iYSrcStart = static_cast<int>(floor(dfYSrcStart));
2375
0
                iYSrcEnd = iYSrcStart + 1;
2376
0
            }
2377
2378
            // Transform into the coordinate system of the source *buffer*
2379
0
            iXSrcStart -= nReqXOff;
2380
0
            iYSrcStart -= nReqYOff;
2381
0
            iXSrcEnd -= nReqXOff;
2382
0
            iYSrcEnd -= nReqYOff;
2383
2384
0
            double dfSum = 0.0;
2385
0
            int nPixelCount = 0;
2386
2387
0
            for (int iY = iYSrcStart; iY < iYSrcEnd; iY++)
2388
0
            {
2389
0
                if (iY < 0 || iY >= nReqYSize)
2390
0
                    continue;
2391
2392
0
                for (int iX = iXSrcStart; iX < iXSrcEnd; iX++)
2393
0
                {
2394
0
                    if (iX < 0 || iX >= nReqXSize)
2395
0
                        continue;
2396
2397
0
                    const float fSampledValue =
2398
0
                        pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
2399
0
                    if (std::isnan(fSampledValue))
2400
0
                        continue;
2401
2402
0
                    if (m_bNoDataSet &&
2403
0
                        GDALIsValueInRange<float>(m_dfNoDataValue) &&
2404
0
                        ARE_REAL_EQUAL(fSampledValue,
2405
0
                                       static_cast<float>(m_dfNoDataValue)))
2406
0
                        continue;
2407
2408
0
                    nPixelCount++;
2409
0
                    dfSum += pafSrc[iX + static_cast<size_t>(iY) * nReqXSize];
2410
0
                }
2411
0
            }
2412
2413
0
            if (nPixelCount == 0)
2414
0
                continue;
2415
2416
            // Compute output value.
2417
0
            const float dfOutputValue = static_cast<float>(dfSum / nPixelCount);
2418
2419
            // Put it in the output buffer.
2420
0
            GByte *pDstLocation =
2421
0
                static_cast<GByte *>(pData) + nPixelSpace * iBufPixel +
2422
0
                static_cast<GPtrDiff_t>(nLineSpace) * iBufLine;
2423
2424
0
            if (eBufType == GDT_UInt8)
2425
0
                *pDstLocation = static_cast<GByte>(
2426
0
                    std::min(255.0, std::max(0.0, dfOutputValue + 0.5)));
2427
0
            else
2428
0
                GDALCopyWords(&dfOutputValue, GDT_Float32, 4, pDstLocation,
2429
0
                              eBufType, 8, 1);
2430
0
        }
2431
0
    }
2432
2433
0
    VSIFree(pafSrc);
2434
2435
0
    if (psExtraArg->pfnProgress)
2436
0
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
2437
2438
0
    return CE_None;
2439
0
}
2440
2441
/************************************************************************/
2442
/*                             GetMinimum()                             */
2443
/************************************************************************/
2444
2445
double VRTAveragedSource::GetMinimum(int /* nXSize */, int /* nYSize */,
2446
                                     int *pbSuccess)
2447
0
{
2448
0
    *pbSuccess = FALSE;
2449
0
    return 0.0;
2450
0
}
2451
2452
/************************************************************************/
2453
/*                             GetMaximum()                             */
2454
/************************************************************************/
2455
2456
double VRTAveragedSource::GetMaximum(int /* nXSize */, int /* nYSize */,
2457
                                     int *pbSuccess)
2458
0
{
2459
0
    *pbSuccess = FALSE;
2460
0
    return 0.0;
2461
0
}
2462
2463
/************************************************************************/
2464
/*                            GetHistogram()                            */
2465
/************************************************************************/
2466
2467
CPLErr VRTAveragedSource::GetHistogram(
2468
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2469
    int /* nBuckets */, GUIntBig * /* panHistogram */,
2470
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
2471
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2472
0
{
2473
0
    return CE_Failure;
2474
0
}
2475
2476
/************************************************************************/
2477
/* ==================================================================== */
2478
/*                     VRTNoDataFromMaskSource                          */
2479
/* ==================================================================== */
2480
/************************************************************************/
2481
2482
/************************************************************************/
2483
/*                      VRTNoDataFromMaskSource()                       */
2484
/************************************************************************/
2485
2486
VRTNoDataFromMaskSource::VRTNoDataFromMaskSource()
2487
0
{
2488
0
}
2489
2490
/************************************************************************/
2491
/*                              XMLInit()                               */
2492
/************************************************************************/
2493
2494
CPLErr
2495
VRTNoDataFromMaskSource::XMLInit(const CPLXMLNode *psSrc,
2496
                                 const char *pszVRTPath,
2497
                                 VRTMapSharedResources &oMapSharedSources)
2498
2499
0
{
2500
    /* -------------------------------------------------------------------- */
2501
    /*      Do base initialization.                                         */
2502
    /* -------------------------------------------------------------------- */
2503
0
    {
2504
0
        const CPLErr eErr =
2505
0
            VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
2506
0
        if (eErr != CE_None)
2507
0
            return eErr;
2508
0
    }
2509
2510
0
    if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
2511
0
    {
2512
0
        m_bNoDataSet = true;
2513
0
        m_dfNoDataValue = CPLAtofM(pszNODATA);
2514
0
    }
2515
2516
0
    m_dfMaskValueThreshold =
2517
0
        CPLAtofM(CPLGetXMLValue(psSrc, "MaskValueThreshold", "0"));
2518
2519
0
    if (const char *pszRemappedValue =
2520
0
            CPLGetXMLValue(psSrc, "RemappedValue", nullptr))
2521
0
    {
2522
0
        m_bHasRemappedValue = true;
2523
0
        m_dfRemappedValue = CPLAtofM(pszRemappedValue);
2524
0
    }
2525
2526
0
    return CE_None;
2527
0
}
2528
2529
/************************************************************************/
2530
/*                           GetTypeStatic()                            */
2531
/************************************************************************/
2532
2533
const char *VRTNoDataFromMaskSource::GetTypeStatic()
2534
0
{
2535
0
    static const char *TYPE = "NoDataFromMaskSource";
2536
0
    return TYPE;
2537
0
}
2538
2539
/************************************************************************/
2540
/*                              GetType()                               */
2541
/************************************************************************/
2542
2543
const char *VRTNoDataFromMaskSource::GetType() const
2544
0
{
2545
0
    return GetTypeStatic();
2546
0
}
2547
2548
/************************************************************************/
2549
/*                           SerializeToXML()                           */
2550
/************************************************************************/
2551
2552
CPLXMLNode *VRTNoDataFromMaskSource::SerializeToXML(const char *pszVRTPath)
2553
2554
0
{
2555
0
    CPLXMLNode *const psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
2556
2557
0
    if (psSrc == nullptr)
2558
0
        return nullptr;
2559
2560
0
    CPLFree(psSrc->pszValue);
2561
0
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
2562
2563
0
    if (m_bNoDataSet)
2564
0
    {
2565
0
        CPLSetXMLValue(psSrc, "MaskValueThreshold",
2566
0
                       CPLSPrintf("%.17g", m_dfMaskValueThreshold));
2567
2568
0
        GDALDataType eBandDT = GDT_Unknown;
2569
0
        double dfNoDataValue = m_dfNoDataValue;
2570
0
        const auto kMaxFloat = std::numeric_limits<float>::max();
2571
0
        if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
2572
0
            1e-10 * kMaxFloat)
2573
0
        {
2574
0
            auto l_band = GetRasterBand();
2575
0
            if (l_band)
2576
0
            {
2577
0
                eBandDT = l_band->GetRasterDataType();
2578
0
                if (eBandDT == GDT_Float32)
2579
0
                {
2580
0
                    dfNoDataValue =
2581
0
                        GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
2582
0
                }
2583
0
            }
2584
0
        }
2585
0
        CPLSetXMLValue(psSrc, "NODATA",
2586
0
                       VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
2587
0
    }
2588
2589
0
    if (m_bHasRemappedValue)
2590
0
    {
2591
0
        CPLSetXMLValue(psSrc, "RemappedValue",
2592
0
                       CPLSPrintf("%.17g", m_dfRemappedValue));
2593
0
    }
2594
2595
0
    return psSrc;
2596
0
}
2597
2598
/************************************************************************/
2599
/*                           SetParameters()                            */
2600
/************************************************************************/
2601
2602
void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
2603
                                            double dfMaskValueThreshold)
2604
0
{
2605
0
    m_bNoDataSet = true;
2606
0
    m_dfNoDataValue = dfNoDataValue;
2607
0
    m_dfMaskValueThreshold = dfMaskValueThreshold;
2608
0
    if (!m_bHasRemappedValue)
2609
0
        m_dfRemappedValue = m_dfNoDataValue;
2610
0
}
2611
2612
/************************************************************************/
2613
/*                           SetParameters()                            */
2614
/************************************************************************/
2615
2616
void VRTNoDataFromMaskSource::SetParameters(double dfNoDataValue,
2617
                                            double dfMaskValueThreshold,
2618
                                            double dfRemappedValue)
2619
0
{
2620
0
    SetParameters(dfNoDataValue, dfMaskValueThreshold);
2621
0
    m_bHasRemappedValue = true;
2622
0
    m_dfRemappedValue = dfRemappedValue;
2623
0
}
2624
2625
/************************************************************************/
2626
/*                              RasterIO()                              */
2627
/************************************************************************/
2628
2629
CPLErr VRTNoDataFromMaskSource::RasterIO(
2630
    GDALDataType eVRTBandDataType, int nXOff, int nYOff, int nXSize, int nYSize,
2631
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
2632
    GSpacing nPixelSpace, GSpacing nLineSpace,
2633
    GDALRasterIOExtraArg *psExtraArgIn, WorkingState &oWorkingState)
2634
2635
0
{
2636
0
    if (!m_bNoDataSet)
2637
0
    {
2638
0
        return VRTSimpleSource::RasterIO(eVRTBandDataType, nXOff, nYOff, nXSize,
2639
0
                                         nYSize, pData, nBufXSize, nBufYSize,
2640
0
                                         eBufType, nPixelSpace, nLineSpace,
2641
0
                                         psExtraArgIn, oWorkingState);
2642
0
    }
2643
2644
0
    GDALRasterIOExtraArg sExtraArg;
2645
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
2646
0
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
2647
2648
0
    double dfXOff = nXOff;
2649
0
    double dfYOff = nYOff;
2650
0
    double dfXSize = nXSize;
2651
0
    double dfYSize = nYSize;
2652
0
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
2653
0
    {
2654
0
        dfXOff = psExtraArgIn->dfXOff;
2655
0
        dfYOff = psExtraArgIn->dfYOff;
2656
0
        dfXSize = psExtraArgIn->dfXSize;
2657
0
        dfYSize = psExtraArgIn->dfYSize;
2658
0
    }
2659
2660
    // The window we will actually request from the source raster band.
2661
0
    double dfReqXOff = 0.0;
2662
0
    double dfReqYOff = 0.0;
2663
0
    double dfReqXSize = 0.0;
2664
0
    double dfReqYSize = 0.0;
2665
0
    int nReqXOff = 0;
2666
0
    int nReqYOff = 0;
2667
0
    int nReqXSize = 0;
2668
0
    int nReqYSize = 0;
2669
2670
    // The window we will actual set _within_ the pData buffer.
2671
0
    int nOutXOff = 0;
2672
0
    int nOutYOff = 0;
2673
0
    int nOutXSize = 0;
2674
0
    int nOutYSize = 0;
2675
2676
0
    if (!m_osResampling.empty())
2677
0
    {
2678
0
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
2679
0
    }
2680
0
    else if (psExtraArgIn != nullptr)
2681
0
    {
2682
0
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
2683
0
    }
2684
2685
0
    bool bError = false;
2686
0
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
2687
0
                         psExtraArg->eResampleAlg, &dfReqXOff, &dfReqYOff,
2688
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
2689
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
2690
0
                         &nOutXSize, &nOutYSize, bError))
2691
0
    {
2692
0
        return bError ? CE_Failure : CE_None;
2693
0
    }
2694
2695
0
    auto l_band = GetRasterBand();
2696
0
    if (!l_band)
2697
0
        return CE_Failure;
2698
2699
    /* -------------------------------------------------------------------- */
2700
    /*      Allocate temporary buffer(s).                                   */
2701
    /* -------------------------------------------------------------------- */
2702
0
    const auto eSrcBandDT = l_band->GetRasterDataType();
2703
0
    const int nSrcBandDTSize = GDALGetDataTypeSizeBytes(eSrcBandDT);
2704
0
    const auto eSrcMaskBandDT = l_band->GetMaskBand()->GetRasterDataType();
2705
0
    const int nSrcMaskBandDTSize = GDALGetDataTypeSizeBytes(eSrcMaskBandDT);
2706
0
    double dfRemappedValue = m_dfRemappedValue;
2707
0
    if (!m_bHasRemappedValue)
2708
0
    {
2709
0
        if (eSrcBandDT == GDT_UInt8 &&
2710
0
            m_dfNoDataValue >= std::numeric_limits<GByte>::min() &&
2711
0
            m_dfNoDataValue <= std::numeric_limits<GByte>::max() &&
2712
0
            static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2713
0
        {
2714
0
            if (m_dfNoDataValue == std::numeric_limits<GByte>::max())
2715
0
                dfRemappedValue = m_dfNoDataValue - 1;
2716
0
            else
2717
0
                dfRemappedValue = m_dfNoDataValue + 1;
2718
0
        }
2719
0
        else if (eSrcBandDT == GDT_UInt16 &&
2720
0
                 m_dfNoDataValue >= std::numeric_limits<uint16_t>::min() &&
2721
0
                 m_dfNoDataValue <= std::numeric_limits<uint16_t>::max() &&
2722
0
                 static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2723
0
        {
2724
0
            if (m_dfNoDataValue == std::numeric_limits<uint16_t>::max())
2725
0
                dfRemappedValue = m_dfNoDataValue - 1;
2726
0
            else
2727
0
                dfRemappedValue = m_dfNoDataValue + 1;
2728
0
        }
2729
0
        else if (eSrcBandDT == GDT_Int16 &&
2730
0
                 m_dfNoDataValue >= std::numeric_limits<int16_t>::min() &&
2731
0
                 m_dfNoDataValue <= std::numeric_limits<int16_t>::max() &&
2732
0
                 static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue)
2733
0
        {
2734
0
            if (m_dfNoDataValue == std::numeric_limits<int16_t>::max())
2735
0
                dfRemappedValue = m_dfNoDataValue - 1;
2736
0
            else
2737
0
                dfRemappedValue = m_dfNoDataValue + 1;
2738
0
        }
2739
0
        else
2740
0
        {
2741
0
            constexpr double EPS = 1e-3;
2742
0
            if (m_dfNoDataValue == 0)
2743
0
                dfRemappedValue = EPS;
2744
0
            else
2745
0
                dfRemappedValue = m_dfNoDataValue * (1 + EPS);
2746
0
        }
2747
0
    }
2748
0
    const bool bByteOptim =
2749
0
        (eSrcBandDT == GDT_UInt8 && eBufType == GDT_UInt8 &&
2750
0
         eSrcMaskBandDT == GDT_UInt8 && m_dfMaskValueThreshold >= 0 &&
2751
0
         m_dfMaskValueThreshold <= 255 &&
2752
0
         static_cast<int>(m_dfMaskValueThreshold) == m_dfMaskValueThreshold &&
2753
0
         m_dfNoDataValue >= 0 && m_dfNoDataValue <= 255 &&
2754
0
         static_cast<int>(m_dfNoDataValue) == m_dfNoDataValue &&
2755
0
         dfRemappedValue >= 0 && dfRemappedValue <= 255 &&
2756
0
         static_cast<int>(dfRemappedValue) == dfRemappedValue);
2757
0
    GByte *pabyWrkBuffer;
2758
0
    try
2759
0
    {
2760
0
        if (bByteOptim && nOutXOff == 0 && nOutYOff == 0 &&
2761
0
            nOutXSize == nBufXSize && nOutYSize == nBufYSize &&
2762
0
            nPixelSpace == nSrcBandDTSize &&
2763
0
            nLineSpace == nPixelSpace * nBufXSize)
2764
0
        {
2765
0
            pabyWrkBuffer = static_cast<GByte *>(pData);
2766
0
        }
2767
0
        else
2768
0
        {
2769
0
            oWorkingState.m_abyWrkBuffer.resize(static_cast<size_t>(nOutXSize) *
2770
0
                                                nOutYSize * nSrcBandDTSize);
2771
0
            pabyWrkBuffer =
2772
0
                reinterpret_cast<GByte *>(oWorkingState.m_abyWrkBuffer.data());
2773
0
        }
2774
0
        oWorkingState.m_abyWrkBufferMask.resize(static_cast<size_t>(nOutXSize) *
2775
0
                                                nOutYSize * nSrcMaskBandDTSize);
2776
0
    }
2777
0
    catch (const std::exception &)
2778
0
    {
2779
0
        CPLError(CE_Failure, CPLE_OutOfMemory,
2780
0
                 "Out of memory when allocating buffers");
2781
0
        return CE_Failure;
2782
0
    }
2783
2784
    /* -------------------------------------------------------------------- */
2785
    /*      Load data.                                                      */
2786
    /* -------------------------------------------------------------------- */
2787
0
    psExtraArg->bFloatingPointWindowValidity = TRUE;
2788
0
    psExtraArg->dfXOff = dfReqXOff;
2789
0
    psExtraArg->dfYOff = dfReqYOff;
2790
0
    psExtraArg->dfXSize = dfReqXSize;
2791
0
    psExtraArg->dfYSize = dfReqYSize;
2792
0
    if (psExtraArgIn)
2793
0
    {
2794
0
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
2795
0
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
2796
0
    }
2797
2798
0
    if (l_band->RasterIO(GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2799
0
                         pabyWrkBuffer, nOutXSize, nOutYSize, eSrcBandDT, 0, 0,
2800
0
                         psExtraArg) != CE_None)
2801
0
    {
2802
0
        return CE_Failure;
2803
0
    }
2804
2805
0
    if (l_band->GetMaskBand()->RasterIO(
2806
0
            GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
2807
0
            oWorkingState.m_abyWrkBufferMask.data(), nOutXSize, nOutYSize,
2808
0
            eSrcMaskBandDT, 0, 0, psExtraArg) != CE_None)
2809
0
    {
2810
0
        return CE_Failure;
2811
0
    }
2812
2813
    /* -------------------------------------------------------------------- */
2814
    /*      Do the processing.                                              */
2815
    /* -------------------------------------------------------------------- */
2816
2817
0
    GByte *const pabyOut = static_cast<GByte *>(pData) +
2818
0
                           nPixelSpace * nOutXOff +
2819
0
                           static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
2820
0
    if (bByteOptim)
2821
0
    {
2822
        // Special case when everything fits on Byte
2823
0
        const GByte nMaskValueThreshold =
2824
0
            static_cast<GByte>(m_dfMaskValueThreshold);
2825
0
        const GByte nNoDataValue = static_cast<GByte>(m_dfNoDataValue);
2826
0
        const GByte nRemappedValue = static_cast<GByte>(dfRemappedValue);
2827
0
        size_t nSrcIdx = 0;
2828
0
        for (int iY = 0; iY < nOutYSize; iY++)
2829
0
        {
2830
0
            GSpacing nDstOffset = iY * nLineSpace;
2831
0
            for (int iX = 0; iX < nOutXSize; iX++)
2832
0
            {
2833
0
                const GByte nMaskVal =
2834
0
                    oWorkingState.m_abyWrkBufferMask[nSrcIdx];
2835
0
                if (nMaskVal <= nMaskValueThreshold)
2836
0
                {
2837
0
                    pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] = nNoDataValue;
2838
0
                }
2839
0
                else
2840
0
                {
2841
0
                    if (pabyWrkBuffer[nSrcIdx] == nNoDataValue)
2842
0
                    {
2843
0
                        pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2844
0
                            nRemappedValue;
2845
0
                    }
2846
0
                    else
2847
0
                    {
2848
0
                        pabyOut[static_cast<GPtrDiff_t>(nDstOffset)] =
2849
0
                            pabyWrkBuffer[nSrcIdx];
2850
0
                    }
2851
0
                }
2852
0
                nDstOffset += nPixelSpace;
2853
0
                nSrcIdx++;
2854
0
            }
2855
0
        }
2856
0
    }
2857
0
    else
2858
0
    {
2859
0
        size_t nSrcIdx = 0;
2860
0
        double dfMaskVal = 0;
2861
0
        const int nBufDTSize = GDALGetDataTypeSizeBytes(eBufType);
2862
0
        std::vector<GByte> abyDstNoData(nBufDTSize);
2863
0
        GDALCopyWords(&m_dfNoDataValue, GDT_Float64, 0, abyDstNoData.data(),
2864
0
                      eBufType, 0, 1);
2865
0
        std::vector<GByte> abyRemappedValue(nBufDTSize);
2866
0
        GDALCopyWords(&dfRemappedValue, GDT_Float64, 0, abyRemappedValue.data(),
2867
0
                      eBufType, 0, 1);
2868
0
        for (int iY = 0; iY < nOutYSize; iY++)
2869
0
        {
2870
0
            GSpacing nDstOffset = iY * nLineSpace;
2871
0
            for (int iX = 0; iX < nOutXSize; iX++)
2872
0
            {
2873
0
                if (eSrcMaskBandDT == GDT_UInt8)
2874
0
                {
2875
0
                    dfMaskVal = oWorkingState.m_abyWrkBufferMask[nSrcIdx];
2876
0
                }
2877
0
                else
2878
0
                {
2879
0
                    GDALCopyWords(oWorkingState.m_abyWrkBufferMask.data() +
2880
0
                                      nSrcIdx * nSrcMaskBandDTSize,
2881
0
                                  eSrcMaskBandDT, 0, &dfMaskVal, GDT_Float64, 0,
2882
0
                                  1);
2883
0
                }
2884
0
                void *const pDst =
2885
0
                    pabyOut + static_cast<GPtrDiff_t>(nDstOffset);
2886
0
                if (!(dfMaskVal > m_dfMaskValueThreshold))
2887
0
                {
2888
0
                    memcpy(pDst, abyDstNoData.data(), nBufDTSize);
2889
0
                }
2890
0
                else
2891
0
                {
2892
0
                    const void *const pSrc =
2893
0
                        pabyWrkBuffer + nSrcIdx * nSrcBandDTSize;
2894
0
                    if (eSrcBandDT == eBufType)
2895
0
                    {
2896
                        // coverity[overrun-buffer-arg]
2897
0
                        memcpy(pDst, pSrc, nBufDTSize);
2898
0
                    }
2899
0
                    else
2900
0
                    {
2901
0
                        GDALCopyWords(pSrc, eSrcBandDT, 0, pDst, eBufType, 0,
2902
0
                                      1);
2903
0
                    }
2904
0
                    if (memcmp(pDst, abyDstNoData.data(), nBufDTSize) == 0)
2905
0
                        memcpy(pDst, abyRemappedValue.data(), nBufDTSize);
2906
0
                }
2907
0
                nDstOffset += nPixelSpace;
2908
0
                nSrcIdx++;
2909
0
            }
2910
0
        }
2911
0
    }
2912
2913
0
    if (psExtraArg->pfnProgress)
2914
0
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
2915
2916
0
    return CE_None;
2917
0
}
2918
2919
/************************************************************************/
2920
/*                             GetMinimum()                             */
2921
/************************************************************************/
2922
2923
double VRTNoDataFromMaskSource::GetMinimum(int /* nXSize */, int /* nYSize */,
2924
                                           int *pbSuccess)
2925
0
{
2926
0
    *pbSuccess = FALSE;
2927
0
    return 0.0;
2928
0
}
2929
2930
/************************************************************************/
2931
/*                             GetMaximum()                             */
2932
/************************************************************************/
2933
2934
double VRTNoDataFromMaskSource::GetMaximum(int /* nXSize */, int /* nYSize */,
2935
                                           int *pbSuccess)
2936
0
{
2937
0
    *pbSuccess = FALSE;
2938
0
    return 0.0;
2939
0
}
2940
2941
/************************************************************************/
2942
/*                            GetHistogram()                            */
2943
/************************************************************************/
2944
2945
CPLErr VRTNoDataFromMaskSource::GetHistogram(
2946
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
2947
    int /* nBuckets */, GUIntBig * /* panHistogram */,
2948
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
2949
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
2950
0
{
2951
0
    return CE_Failure;
2952
0
}
2953
2954
/************************************************************************/
2955
/* ==================================================================== */
2956
/*                          VRTComplexSource                            */
2957
/* ==================================================================== */
2958
/************************************************************************/
2959
2960
/************************************************************************/
2961
/*                          VRTComplexSource()                          */
2962
/************************************************************************/
2963
2964
VRTComplexSource::VRTComplexSource(const VRTComplexSource *poSrcSource,
2965
                                   double dfXDstRatio, double dfYDstRatio)
2966
0
    : VRTSimpleSource(poSrcSource, dfXDstRatio, dfYDstRatio),
2967
0
      m_nProcessingFlags(poSrcSource->m_nProcessingFlags),
2968
0
      m_dfNoDataValue(poSrcSource->m_dfNoDataValue),
2969
0
      m_osNoDataValueOri(poSrcSource->m_osNoDataValueOri),
2970
0
      m_dfScaleOff(poSrcSource->m_dfScaleOff),
2971
0
      m_dfScaleRatio(poSrcSource->m_dfScaleRatio),
2972
0
      m_bSrcMinMaxDefined(poSrcSource->m_bSrcMinMaxDefined),
2973
0
      m_dfSrcMin(poSrcSource->m_dfSrcMin), m_dfSrcMax(poSrcSource->m_dfSrcMax),
2974
0
      m_dfDstMin(poSrcSource->m_dfDstMin), m_dfDstMax(poSrcSource->m_dfDstMax),
2975
0
      m_dfExponent(poSrcSource->m_dfExponent), m_bClip(poSrcSource->m_bClip),
2976
0
      m_nColorTableComponent(poSrcSource->m_nColorTableComponent),
2977
0
      m_adfLUTInputs(poSrcSource->m_adfLUTInputs),
2978
0
      m_adfLUTOutputs(poSrcSource->m_adfLUTOutputs)
2979
0
{
2980
0
}
2981
2982
/************************************************************************/
2983
/*                           GetTypeStatic()                            */
2984
/************************************************************************/
2985
2986
const char *VRTComplexSource::GetTypeStatic()
2987
0
{
2988
0
    static const char *TYPE = "ComplexSource";
2989
0
    return TYPE;
2990
0
}
2991
2992
/************************************************************************/
2993
/*                              GetType()                               */
2994
/************************************************************************/
2995
2996
const char *VRTComplexSource::GetType() const
2997
0
{
2998
0
    return GetTypeStatic();
2999
0
}
3000
3001
/************************************************************************/
3002
/*                           SetNoDataValue()                           */
3003
/************************************************************************/
3004
3005
void VRTComplexSource::SetNoDataValue(double dfNewNoDataValue)
3006
3007
0
{
3008
0
    if (dfNewNoDataValue == VRT_NODATA_UNSET)
3009
0
    {
3010
0
        m_nProcessingFlags &= ~PROCESSING_FLAG_NODATA;
3011
0
        m_dfNoDataValue = VRT_NODATA_UNSET;
3012
0
        return;
3013
0
    }
3014
3015
0
    m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
3016
0
    m_dfNoDataValue = dfNewNoDataValue;
3017
0
}
3018
3019
/************************************************************************/
3020
/*                       GetAdjustedNoDataValue()                       */
3021
/************************************************************************/
3022
3023
double VRTComplexSource::GetAdjustedNoDataValue() const
3024
0
{
3025
0
    if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
3026
0
    {
3027
0
        auto l_band = GetRasterBand();
3028
0
        if (l_band && l_band->GetRasterDataType() == GDT_Float32)
3029
0
        {
3030
0
            return GDALAdjustNoDataCloseToFloatMax(m_dfNoDataValue);
3031
0
        }
3032
0
    }
3033
0
    return m_dfNoDataValue;
3034
0
}
3035
3036
/************************************************************************/
3037
/*                           SerializeToXML()                           */
3038
/************************************************************************/
3039
3040
CPLXMLNode *VRTComplexSource::SerializeToXML(const char *pszVRTPath)
3041
3042
0
{
3043
0
    CPLXMLNode *psSrc = VRTSimpleSource::SerializeToXML(pszVRTPath);
3044
3045
0
    if (psSrc == nullptr)
3046
0
        return nullptr;
3047
3048
0
    CPLFree(psSrc->pszValue);
3049
0
    psSrc->pszValue = CPLStrdup(GetTypeStatic());
3050
3051
0
    if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0)
3052
0
    {
3053
0
        CPLSetXMLValue(psSrc, "UseMaskBand", "true");
3054
0
    }
3055
3056
0
    if ((m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0)
3057
0
    {
3058
0
        if (!m_osNoDataValueOri.empty() && GetRasterBandNoOpen() == nullptr)
3059
0
        {
3060
0
            CPLSetXMLValue(psSrc, "NODATA", m_osNoDataValueOri.c_str());
3061
0
        }
3062
0
        else
3063
0
        {
3064
0
            GDALDataType eBandDT = GDT_Unknown;
3065
0
            double dfNoDataValue = m_dfNoDataValue;
3066
0
            const auto kMaxFloat = std::numeric_limits<float>::max();
3067
0
            if (std::fabs(std::fabs(m_dfNoDataValue) - kMaxFloat) <
3068
0
                1e-10 * kMaxFloat)
3069
0
            {
3070
0
                auto l_band = GetRasterBand();
3071
0
                if (l_band)
3072
0
                {
3073
0
                    dfNoDataValue = GetAdjustedNoDataValue();
3074
0
                    eBandDT = l_band->GetRasterDataType();
3075
0
                }
3076
0
            }
3077
0
            CPLSetXMLValue(
3078
0
                psSrc, "NODATA",
3079
0
                VRTSerializeNoData(dfNoDataValue, eBandDT, 18).c_str());
3080
0
        }
3081
0
    }
3082
3083
0
    if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
3084
0
    {
3085
0
        CPLSetXMLValue(psSrc, "ScaleOffset", CPLSPrintf("%g", m_dfScaleOff));
3086
0
        CPLSetXMLValue(psSrc, "ScaleRatio", CPLSPrintf("%g", m_dfScaleRatio));
3087
0
    }
3088
0
    else if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
3089
0
    {
3090
0
        CPLSetXMLValue(psSrc, "Exponent", CPLSPrintf("%g", m_dfExponent));
3091
0
        if (m_bSrcMinMaxDefined)
3092
0
        {
3093
0
            CPLSetXMLValue(psSrc, "SrcMin", CPLSPrintf("%g", m_dfSrcMin));
3094
0
            CPLSetXMLValue(psSrc, "SrcMax", CPLSPrintf("%g", m_dfSrcMax));
3095
0
        }
3096
0
        CPLSetXMLValue(psSrc, "DstMin", CPLSPrintf("%g", m_dfDstMin));
3097
0
        CPLSetXMLValue(psSrc, "DstMax", CPLSPrintf("%g", m_dfDstMax));
3098
0
        CPLSetXMLValue(psSrc, "Clip", m_bClip ? "true" : "false");
3099
0
    }
3100
3101
0
    if (!m_adfLUTInputs.empty())
3102
0
    {
3103
        // Make sure we print with sufficient precision to address really close
3104
        // entries (#6422).
3105
0
        CPLString osLUT;
3106
0
        if (m_adfLUTInputs.size() >= 2 &&
3107
0
            CPLString().Printf("%g", m_adfLUTInputs[0]) ==
3108
0
                CPLString().Printf("%g", m_adfLUTInputs[1]))
3109
0
        {
3110
0
            osLUT = CPLString().Printf("%.17g:%g", m_adfLUTInputs[0],
3111
0
                                       m_adfLUTOutputs[0]);
3112
0
        }
3113
0
        else
3114
0
        {
3115
0
            osLUT = CPLString().Printf("%g:%g", m_adfLUTInputs[0],
3116
0
                                       m_adfLUTOutputs[0]);
3117
0
        }
3118
0
        for (size_t i = 1; i < m_adfLUTInputs.size(); i++)
3119
0
        {
3120
0
            if (CPLString().Printf("%g", m_adfLUTInputs[i]) ==
3121
0
                    CPLString().Printf("%g", m_adfLUTInputs[i - 1]) ||
3122
0
                (i + 1 < m_adfLUTInputs.size() &&
3123
0
                 CPLString().Printf("%g", m_adfLUTInputs[i]) ==
3124
0
                     CPLString().Printf("%g", m_adfLUTInputs[i + 1])))
3125
0
            {
3126
                // TODO(schwehr): An explanation of the 18 would be helpful.
3127
                // Can someone distill the issue down to a quick comment?
3128
                // https://trac.osgeo.org/gdal/ticket/6422
3129
0
                osLUT += CPLString().Printf(",%.17g:%g", m_adfLUTInputs[i],
3130
0
                                            m_adfLUTOutputs[i]);
3131
0
            }
3132
0
            else
3133
0
            {
3134
0
                osLUT += CPLString().Printf(",%g:%g", m_adfLUTInputs[i],
3135
0
                                            m_adfLUTOutputs[i]);
3136
0
            }
3137
0
        }
3138
0
        CPLSetXMLValue(psSrc, "LUT", osLUT);
3139
0
    }
3140
3141
0
    if (m_nColorTableComponent)
3142
0
    {
3143
0
        CPLSetXMLValue(psSrc, "ColorTableComponent",
3144
0
                       CPLSPrintf("%d", m_nColorTableComponent));
3145
0
    }
3146
3147
0
    return psSrc;
3148
0
}
3149
3150
/************************************************************************/
3151
/*                              XMLInit()                               */
3152
/************************************************************************/
3153
3154
CPLErr VRTComplexSource::XMLInit(const CPLXMLNode *psSrc,
3155
                                 const char *pszVRTPath,
3156
                                 VRTMapSharedResources &oMapSharedSources)
3157
3158
0
{
3159
    /* -------------------------------------------------------------------- */
3160
    /*      Do base initialization.                                         */
3161
    /* -------------------------------------------------------------------- */
3162
0
    {
3163
0
        const CPLErr eErr =
3164
0
            VRTSimpleSource::XMLInit(psSrc, pszVRTPath, oMapSharedSources);
3165
0
        if (eErr != CE_None)
3166
0
            return eErr;
3167
0
    }
3168
3169
    /* -------------------------------------------------------------------- */
3170
    /*      Complex parameters.                                             */
3171
    /* -------------------------------------------------------------------- */
3172
0
    const char *pszScaleOffset = CPLGetXMLValue(psSrc, "ScaleOffset", nullptr);
3173
0
    const char *pszScaleRatio = CPLGetXMLValue(psSrc, "ScaleRatio", nullptr);
3174
0
    if (pszScaleOffset || pszScaleRatio)
3175
0
    {
3176
0
        m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
3177
0
        if (pszScaleOffset)
3178
0
            m_dfScaleOff = CPLAtof(pszScaleOffset);
3179
0
        if (pszScaleRatio)
3180
0
            m_dfScaleRatio = CPLAtof(pszScaleRatio);
3181
0
    }
3182
0
    else if (CPLGetXMLValue(psSrc, "Exponent", nullptr) != nullptr &&
3183
0
             CPLGetXMLValue(psSrc, "DstMin", nullptr) != nullptr &&
3184
0
             CPLGetXMLValue(psSrc, "DstMax", nullptr) != nullptr)
3185
0
    {
3186
0
        m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
3187
0
        m_dfExponent = CPLAtof(CPLGetXMLValue(psSrc, "Exponent", "1.0"));
3188
3189
0
        const char *pszSrcMin = CPLGetXMLValue(psSrc, "SrcMin", nullptr);
3190
0
        const char *pszSrcMax = CPLGetXMLValue(psSrc, "SrcMax", nullptr);
3191
0
        if (pszSrcMin && pszSrcMax)
3192
0
        {
3193
0
            m_dfSrcMin = CPLAtof(pszSrcMin);
3194
0
            m_dfSrcMax = CPLAtof(pszSrcMax);
3195
0
            m_bSrcMinMaxDefined = true;
3196
0
        }
3197
3198
0
        m_dfDstMin = CPLAtof(CPLGetXMLValue(psSrc, "DstMin", "0.0"));
3199
0
        m_dfDstMax = CPLAtof(CPLGetXMLValue(psSrc, "DstMax", "0.0"));
3200
0
        m_bClip = CPLTestBool(CPLGetXMLValue(psSrc, "Clip", "true"));
3201
0
    }
3202
3203
0
    if (const char *pszNODATA = CPLGetXMLValue(psSrc, "NODATA", nullptr))
3204
0
    {
3205
0
        m_nProcessingFlags |= PROCESSING_FLAG_NODATA;
3206
0
        m_osNoDataValueOri = pszNODATA;
3207
0
        m_dfNoDataValue = CPLAtofM(m_osNoDataValueOri.c_str());
3208
0
    }
3209
3210
0
    const char *pszUseMaskBand = CPLGetXMLValue(psSrc, "UseMaskBand", nullptr);
3211
0
    if (pszUseMaskBand && CPLTestBool(pszUseMaskBand))
3212
0
    {
3213
0
        m_nProcessingFlags |= PROCESSING_FLAG_USE_MASK_BAND;
3214
0
    }
3215
3216
0
    const char *pszLUT = CPLGetXMLValue(psSrc, "LUT", nullptr);
3217
0
    if (pszLUT)
3218
0
    {
3219
0
        const CPLStringList aosValues(
3220
0
            CSLTokenizeString2(pszLUT, ",:", CSLT_ALLOWEMPTYTOKENS));
3221
3222
0
        const int nLUTItemCount = aosValues.size() / 2;
3223
0
        try
3224
0
        {
3225
0
            m_adfLUTInputs.resize(nLUTItemCount);
3226
0
            m_adfLUTOutputs.resize(nLUTItemCount);
3227
0
        }
3228
0
        catch (const std::bad_alloc &e)
3229
0
        {
3230
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
3231
0
            m_adfLUTInputs.clear();
3232
0
            m_adfLUTOutputs.clear();
3233
0
            return CE_Failure;
3234
0
        }
3235
3236
0
        for (int nIndex = 0; nIndex < nLUTItemCount; nIndex++)
3237
0
        {
3238
0
            m_adfLUTInputs[nIndex] = CPLAtof(aosValues[nIndex * 2]);
3239
0
            m_adfLUTOutputs[nIndex] = CPLAtof(aosValues[nIndex * 2 + 1]);
3240
3241
            // Enforce the requirement that the LUT input array is
3242
            // monotonically non-decreasing.
3243
0
            if (std::isnan(m_adfLUTInputs[nIndex]) && nIndex != 0)
3244
0
            {
3245
0
                CPLError(CE_Failure, CPLE_AppDefined,
3246
0
                         "A Not-A-Number (NaN) source value should be the "
3247
0
                         "first one of the LUT.");
3248
0
                m_adfLUTInputs.clear();
3249
0
                m_adfLUTOutputs.clear();
3250
0
                return CE_Failure;
3251
0
            }
3252
0
            else if (nIndex > 0 &&
3253
0
                     m_adfLUTInputs[nIndex] < m_adfLUTInputs[nIndex - 1])
3254
0
            {
3255
0
                CPLError(CE_Failure, CPLE_AppDefined,
3256
0
                         "Source values of the LUT are not listed in a "
3257
0
                         "monotonically non-decreasing order");
3258
0
                m_adfLUTInputs.clear();
3259
0
                m_adfLUTOutputs.clear();
3260
0
                return CE_Failure;
3261
0
            }
3262
0
        }
3263
3264
0
        m_nProcessingFlags |= PROCESSING_FLAG_LUT;
3265
0
    }
3266
3267
0
    const char *pszColorTableComponent =
3268
0
        CPLGetXMLValue(psSrc, "ColorTableComponent", nullptr);
3269
0
    if (pszColorTableComponent)
3270
0
    {
3271
0
        m_nColorTableComponent = atoi(pszColorTableComponent);
3272
0
        m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
3273
0
    }
3274
3275
0
    return CE_None;
3276
0
}
3277
3278
/************************************************************************/
3279
/*                               SetLUT()                               */
3280
/************************************************************************/
3281
3282
void VRTComplexSource::SetLUT(const std::vector<double> &adfLUTInputs,
3283
                              const std::vector<double> &adfLUTOutputs)
3284
0
{
3285
0
    m_adfLUTInputs = adfLUTInputs;
3286
0
    m_adfLUTOutputs = adfLUTOutputs;
3287
0
    m_nProcessingFlags |= PROCESSING_FLAG_LUT;
3288
0
}
3289
3290
/************************************************************************/
3291
/*                            LookupValue()                             */
3292
/************************************************************************/
3293
3294
double VRTComplexSource::LookupValue(double dfInput)
3295
0
{
3296
0
    auto beginIter = m_adfLUTInputs.begin();
3297
0
    auto endIter = m_adfLUTInputs.end();
3298
0
    size_t offset = 0;
3299
0
    if (std::isnan(m_adfLUTInputs[0]))
3300
0
    {
3301
0
        if (std::isnan(dfInput) || m_adfLUTInputs.size() == 1)
3302
0
            return m_adfLUTOutputs[0];
3303
0
        ++beginIter;
3304
0
        offset = 1;
3305
0
    }
3306
3307
    // Find the index of the first element in the LUT input array that
3308
    // is not smaller than the input value.
3309
0
    const size_t i =
3310
0
        offset +
3311
0
        std::distance(beginIter, std::lower_bound(beginIter, endIter, dfInput));
3312
3313
0
    if (i == offset)
3314
0
        return m_adfLUTOutputs[offset];
3315
3316
    // If the index is beyond the end of the LUT input array, the input
3317
    // value is larger than all the values in the array.
3318
0
    if (i == m_adfLUTInputs.size())
3319
0
        return m_adfLUTOutputs.back();
3320
3321
0
    if (m_adfLUTInputs[i] == dfInput)
3322
0
        return m_adfLUTOutputs[i];
3323
3324
    // Otherwise, interpolate.
3325
0
    return m_adfLUTOutputs[i - 1] +
3326
0
           (dfInput - m_adfLUTInputs[i - 1]) *
3327
0
               ((m_adfLUTOutputs[i] - m_adfLUTOutputs[i - 1]) /
3328
0
                (m_adfLUTInputs[i] - m_adfLUTInputs[i - 1]));
3329
0
}
3330
3331
/************************************************************************/
3332
/*                          SetLinearScaling()                          */
3333
/************************************************************************/
3334
3335
void VRTComplexSource::SetLinearScaling(double dfOffset, double dfScale)
3336
0
{
3337
0
    m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_EXPONENTIAL;
3338
0
    m_nProcessingFlags |= PROCESSING_FLAG_SCALING_LINEAR;
3339
0
    m_dfScaleOff = dfOffset;
3340
0
    m_dfScaleRatio = dfScale;
3341
0
}
3342
3343
/************************************************************************/
3344
/*                          SetPowerScaling()                           */
3345
/************************************************************************/
3346
3347
void VRTComplexSource::SetPowerScaling(double dfExponentIn, double dfSrcMinIn,
3348
                                       double dfSrcMaxIn, double dfDstMinIn,
3349
                                       double dfDstMaxIn, bool bClip)
3350
0
{
3351
0
    m_nProcessingFlags &= ~PROCESSING_FLAG_SCALING_LINEAR;
3352
0
    m_nProcessingFlags |= PROCESSING_FLAG_SCALING_EXPONENTIAL;
3353
0
    m_dfExponent = dfExponentIn;
3354
0
    m_dfSrcMin = dfSrcMinIn;
3355
0
    m_dfSrcMax = dfSrcMaxIn;
3356
0
    m_dfDstMin = dfDstMinIn;
3357
0
    m_dfDstMax = dfDstMaxIn;
3358
0
    m_bSrcMinMaxDefined = true;
3359
0
    m_bClip = bClip;
3360
0
}
3361
3362
/************************************************************************/
3363
/*                       SetColorTableComponent()                       */
3364
/************************************************************************/
3365
3366
void VRTComplexSource::SetColorTableComponent(int nComponent)
3367
0
{
3368
0
    m_nProcessingFlags |= PROCESSING_FLAG_COLOR_TABLE_EXPANSION;
3369
0
    m_nColorTableComponent = nComponent;
3370
0
}
3371
3372
/************************************************************************/
3373
/*                              RasterIO()                              */
3374
/************************************************************************/
3375
3376
CPLErr VRTComplexSource::RasterIO(GDALDataType eVRTBandDataType, int nXOff,
3377
                                  int nYOff, int nXSize, int nYSize,
3378
                                  void *pData, int nBufXSize, int nBufYSize,
3379
                                  GDALDataType eBufType, GSpacing nPixelSpace,
3380
                                  GSpacing nLineSpace,
3381
                                  GDALRasterIOExtraArg *psExtraArgIn,
3382
                                  WorkingState &oWorkingState)
3383
3384
0
{
3385
0
    GDALRasterIOExtraArg sExtraArg;
3386
0
    INIT_RASTERIO_EXTRA_ARG(sExtraArg);
3387
0
    GDALRasterIOExtraArg *psExtraArg = &sExtraArg;
3388
3389
0
    double dfXOff = nXOff;
3390
0
    double dfYOff = nYOff;
3391
0
    double dfXSize = nXSize;
3392
0
    double dfYSize = nYSize;
3393
0
    if (psExtraArgIn != nullptr && psExtraArgIn->bFloatingPointWindowValidity)
3394
0
    {
3395
0
        dfXOff = psExtraArgIn->dfXOff;
3396
0
        dfYOff = psExtraArgIn->dfYOff;
3397
0
        dfXSize = psExtraArgIn->dfXSize;
3398
0
        dfYSize = psExtraArgIn->dfYSize;
3399
0
    }
3400
3401
    // The window we will actually request from the source raster band.
3402
0
    double dfReqXOff = 0.0;
3403
0
    double dfReqYOff = 0.0;
3404
0
    double dfReqXSize = 0.0;
3405
0
    double dfReqYSize = 0.0;
3406
0
    int nReqXOff = 0;
3407
0
    int nReqYOff = 0;
3408
0
    int nReqXSize = 0;
3409
0
    int nReqYSize = 0;
3410
3411
    // The window we will actual set _within_ the pData buffer.
3412
0
    int nOutXOff = 0;
3413
0
    int nOutYOff = 0;
3414
0
    int nOutXSize = 0;
3415
0
    int nOutYSize = 0;
3416
3417
0
    if (!m_osResampling.empty())
3418
0
    {
3419
0
        psExtraArg->eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
3420
0
    }
3421
0
    else if (psExtraArgIn != nullptr)
3422
0
    {
3423
0
        psExtraArg->eResampleAlg = psExtraArgIn->eResampleAlg;
3424
0
    }
3425
0
    if (psExtraArgIn)
3426
0
        psExtraArg->bOperateInBufType =
3427
0
            GDAL_GET_OPERATE_IN_BUF_TYPE(*psExtraArgIn);
3428
3429
0
    bool bError = false;
3430
0
    if (!GetSrcDstWindow(dfXOff, dfYOff, dfXSize, dfYSize, nBufXSize, nBufYSize,
3431
0
                         psExtraArg->eResampleAlg, &dfReqXOff, &dfReqYOff,
3432
0
                         &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff,
3433
0
                         &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
3434
0
                         &nOutXSize, &nOutYSize, bError))
3435
0
    {
3436
0
        return bError ? CE_Failure : CE_None;
3437
0
    }
3438
#if DEBUG_VERBOSE
3439
    CPLDebug("VRT",
3440
             "nXOff=%d, nYOff=%d, nXSize=%d, nYSize=%d, nBufXSize=%d, "
3441
             "nBufYSize=%d,\n"
3442
             "dfReqXOff=%g, dfReqYOff=%g, dfReqXSize=%g, dfReqYSize=%g,\n"
3443
             "nReqXOff=%d, nReqYOff=%d, nReqXSize=%d, nReqYSize=%d,\n"
3444
             "nOutXOff=%d, nOutYOff=%d, nOutXSize=%d, nOutYSize=%d",
3445
             nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, dfReqXOff,
3446
             dfReqYOff, dfReqXSize, dfReqYSize, nReqXOff, nReqYOff, nReqXSize,
3447
             nReqYSize, nOutXOff, nOutYOff, nOutXSize, nOutYSize);
3448
#endif
3449
3450
0
    auto poSourceBand = GetRasterBand();
3451
0
    if (!poSourceBand)
3452
0
        return CE_Failure;
3453
3454
0
    psExtraArg->bFloatingPointWindowValidity = TRUE;
3455
0
    psExtraArg->dfXOff = dfReqXOff;
3456
0
    psExtraArg->dfYOff = dfReqYOff;
3457
0
    psExtraArg->dfXSize = dfReqXSize;
3458
0
    psExtraArg->dfYSize = dfReqYSize;
3459
0
    if (psExtraArgIn)
3460
0
    {
3461
0
        psExtraArg->pfnProgress = psExtraArgIn->pfnProgress;
3462
0
        psExtraArg->pProgressData = psExtraArgIn->pProgressData;
3463
0
        if (psExtraArgIn->nVersion >= 2)
3464
0
        {
3465
0
            psExtraArg->bUseOnlyThisScale = psExtraArgIn->bUseOnlyThisScale;
3466
0
        }
3467
0
        psExtraArg->bOperateInBufType =
3468
0
            GDAL_GET_OPERATE_IN_BUF_TYPE(*psExtraArgIn);
3469
0
    }
3470
3471
0
    GByte *const pabyOut = static_cast<GByte *>(pData) +
3472
0
                           nPixelSpace * nOutXOff +
3473
0
                           static_cast<GPtrDiff_t>(nLineSpace) * nOutYOff;
3474
0
    const auto eSourceType = poSourceBand->GetRasterDataType();
3475
0
    if (m_nProcessingFlags == PROCESSING_FLAG_NODATA)
3476
0
    {
3477
        // Optimization if doing only nodata processing
3478
0
        if (eBufType != eSourceType && psExtraArg->bOperateInBufType)
3479
0
        {
3480
0
            if (eBufType == GDT_Float32 &&
3481
0
                GDALDataTypeUnion(eBufType, eSourceType) == eBufType)
3482
0
            {
3483
0
                return RasterIOProcessNoData<float, GDT_Float32>(
3484
0
                    poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff,
3485
0
                    nReqXSize, nReqYSize, pabyOut, nOutXSize, nOutYSize,
3486
0
                    eBufType, nPixelSpace, nLineSpace, psExtraArg,
3487
0
                    oWorkingState);
3488
0
            }
3489
0
            else if (eBufType == GDT_Float64 &&
3490
0
                     GDALDataTypeUnion(eBufType, eSourceType) == eBufType)
3491
0
            {
3492
0
                return RasterIOProcessNoData<double, GDT_Float64>(
3493
0
                    poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff,
3494
0
                    nReqXSize, nReqYSize, pabyOut, nOutXSize, nOutYSize,
3495
0
                    eBufType, nPixelSpace, nLineSpace, psExtraArg,
3496
0
                    oWorkingState);
3497
0
            }
3498
0
        }
3499
0
        else if (eSourceType == GDT_UInt8)
3500
0
        {
3501
0
            if (!GDALIsValueInRange<GByte>(m_dfNoDataValue))
3502
0
            {
3503
0
                return VRTSimpleSource::RasterIO(
3504
0
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3505
0
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3506
0
                    psExtraArgIn, oWorkingState);
3507
0
            }
3508
0
            return RasterIOProcessNoData<GByte, GDT_UInt8>(
3509
0
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3510
0
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3511
0
                nLineSpace, psExtraArg, oWorkingState);
3512
0
        }
3513
0
        else if (eSourceType == GDT_Int16)
3514
0
        {
3515
0
            if (!GDALIsValueInRange<int16_t>(m_dfNoDataValue))
3516
0
            {
3517
0
                return VRTSimpleSource::RasterIO(
3518
0
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3519
0
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3520
0
                    psExtraArgIn, oWorkingState);
3521
0
            }
3522
3523
0
            return RasterIOProcessNoData<int16_t, GDT_Int16>(
3524
0
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3525
0
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3526
0
                nLineSpace, psExtraArg, oWorkingState);
3527
0
        }
3528
0
        else if (eSourceType == GDT_UInt16)
3529
0
        {
3530
0
            if (!GDALIsValueInRange<uint16_t>(m_dfNoDataValue))
3531
0
            {
3532
0
                return VRTSimpleSource::RasterIO(
3533
0
                    eVRTBandDataType, nXOff, nYOff, nXSize, nYSize, pData,
3534
0
                    nBufXSize, nBufYSize, eBufType, nPixelSpace, nLineSpace,
3535
0
                    psExtraArgIn, oWorkingState);
3536
0
            }
3537
3538
0
            return RasterIOProcessNoData<uint16_t, GDT_UInt16>(
3539
0
                poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3540
0
                nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3541
0
                nLineSpace, psExtraArg, oWorkingState);
3542
0
        }
3543
0
    }
3544
3545
0
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
3546
0
    CPLErr eErr;
3547
    // For Int32, float32 isn't sufficiently precise as working data type
3548
0
    if (eVRTBandDataType == GDT_CInt32 || eVRTBandDataType == GDT_CFloat64 ||
3549
0
        eVRTBandDataType == GDT_Int32 || eVRTBandDataType == GDT_UInt32 ||
3550
0
        eVRTBandDataType == GDT_Int64 || eVRTBandDataType == GDT_UInt64 ||
3551
0
        eVRTBandDataType == GDT_Float64 || eSourceType == GDT_Int32 ||
3552
0
        eSourceType == GDT_UInt32 || eSourceType == GDT_Int64 ||
3553
0
        eSourceType == GDT_UInt64)
3554
0
    {
3555
0
        eErr = RasterIOInternal<double>(
3556
0
            poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3557
0
            nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3558
0
            nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat64 : GDT_Float64,
3559
0
            oWorkingState);
3560
0
    }
3561
0
    else
3562
0
    {
3563
0
        eErr = RasterIOInternal<float>(
3564
0
            poSourceBand, eVRTBandDataType, nReqXOff, nReqYOff, nReqXSize,
3565
0
            nReqYSize, pabyOut, nOutXSize, nOutYSize, eBufType, nPixelSpace,
3566
0
            nLineSpace, psExtraArg, bIsComplex ? GDT_CFloat32 : GDT_Float32,
3567
0
            oWorkingState);
3568
0
    }
3569
3570
0
    if (psExtraArg->pfnProgress)
3571
0
        psExtraArg->pfnProgress(1.0, "", psExtraArg->pProgressData);
3572
3573
0
    return eErr;
3574
0
}
3575
3576
/************************************************************************/
3577
/*                            hasZeroByte()                             */
3578
/************************************************************************/
3579
3580
CPL_NOSANITIZE_UNSIGNED_INT_OVERFLOW
3581
static inline bool hasZeroByte(uint32_t v)
3582
0
{
3583
    // Cf https://graphics.stanford.edu/~seander/bithacks.html#ZeroInWord
3584
0
    return (((v)-0x01010101U) & ~(v) & 0x80808080U) != 0;
3585
0
}
3586
3587
/************************************************************************/
3588
/*                       RasterIOProcessNoData()                        */
3589
/************************************************************************/
3590
3591
// This method is an optimization of the generic RasterIOInternal()
3592
// that deals with a VRTComplexSource with only a NODATA value in it, and
3593
// no other processing flags.
3594
3595
// nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3596
// referential.
3597
template <class WorkingDT, GDALDataType eWorkingDT>
3598
CPLErr VRTComplexSource::RasterIOProcessNoData(
3599
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3600
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3601
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3602
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3603
    WorkingState &oWorkingState)
3604
0
{
3605
0
    CPLAssert(m_nProcessingFlags == PROCESSING_FLAG_NODATA);
3606
0
    CPLAssert(GDALIsValueExactAs<WorkingDT>(m_dfNoDataValue));
3607
0
    const int nWorkDTSize = GDALGetDataTypeSizeBytes(eWorkingDT);
3608
0
    assert(nWorkDTSize != 0);
3609
3610
    /* -------------------------------------------------------------------- */
3611
    /*      Read into a temporary buffer.                                   */
3612
    /* -------------------------------------------------------------------- */
3613
0
    try
3614
0
    {
3615
        // Cannot overflow since pData should at least have that number of
3616
        // elements
3617
0
        const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
3618
0
        if (nPixelCount >
3619
0
            static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
3620
0
                nWorkDTSize)
3621
0
        {
3622
0
            CPLError(CE_Failure, CPLE_OutOfMemory,
3623
0
                     "Too large temporary buffer");
3624
0
            return CE_Failure;
3625
0
        }
3626
0
        oWorkingState.m_abyWrkBuffer.resize(nWorkDTSize * nPixelCount);
3627
0
    }
3628
0
    catch (const std::bad_alloc &e)
3629
0
    {
3630
0
        CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
3631
0
        return CE_Failure;
3632
0
    }
3633
0
    auto paSrcData =
3634
0
        reinterpret_cast<WorkingDT *>(oWorkingState.m_abyWrkBuffer.data());
3635
3636
0
    GDALRasterIOExtraArg sExtraArg;
3637
0
    GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
3638
0
    if (!m_osResampling.empty())
3639
0
    {
3640
0
        sExtraArg.eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
3641
0
    }
3642
0
    sExtraArg.bOperateInBufType = true;
3643
3644
0
    const CPLErr eErr = poSourceBand->RasterIO(
3645
0
        GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3646
0
        oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize, eWorkingDT,
3647
0
        nWorkDTSize, nWorkDTSize * static_cast<GSpacing>(nOutXSize),
3648
0
        &sExtraArg);
3649
3650
0
    if (eErr != CE_None)
3651
0
    {
3652
0
        return eErr;
3653
0
    }
3654
3655
0
    const auto nNoDataValue = static_cast<WorkingDT>(m_dfNoDataValue);
3656
0
    size_t idxBuffer = 0;
3657
0
    if (eWorkingDT == eBufType &&
3658
0
        !GDALDataTypeIsConversionLossy(eWorkingDT, eVRTBandDataType))
3659
0
    {
3660
        // Most optimized case: the output type is the same as the working type,
3661
        // and conversion from the working type to the VRT band data type is
3662
        // not lossy
3663
0
        for (int iY = 0; iY < nOutYSize; iY++)
3664
0
        {
3665
0
            GByte *pDstLocation = static_cast<GByte *>(pData) +
3666
0
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
3667
3668
0
            int iX = 0;
3669
0
            if (sizeof(WorkingDT) == 1 && nPixelSpace == 1)
3670
0
            {
3671
                // Optimization to detect more quickly if source pixels are
3672
                // at nodata.
3673
0
                const GByte byNoDataValue = static_cast<GByte>(nNoDataValue);
3674
0
                const uint32_t wordNoData =
3675
0
                    (static_cast<uint32_t>(byNoDataValue) << 24) |
3676
0
                    (byNoDataValue << 16) | (byNoDataValue << 8) |
3677
0
                    byNoDataValue;
3678
3679
                // Warning: hasZeroByte() assumes WORD_SIZE = 4
3680
0
                constexpr int WORD_SIZE = 4;
3681
0
                for (; iX < nOutXSize - (WORD_SIZE - 1); iX += WORD_SIZE)
3682
0
                {
3683
0
                    uint32_t v;
3684
0
                    static_assert(sizeof(v) == WORD_SIZE,
3685
0
                                  "sizeof(v) == WORD_SIZE");
3686
0
                    memcpy(&v, paSrcData + idxBuffer, sizeof(v));
3687
                    // Cf https://graphics.stanford.edu/~seander/bithacks.html#ValueInWord
3688
0
                    if (!hasZeroByte(v ^ wordNoData))
3689
0
                    {
3690
                        // No bytes are at nodata
3691
0
                        memcpy(pDstLocation, &v, WORD_SIZE);
3692
0
                        idxBuffer += WORD_SIZE;
3693
0
                        pDstLocation += WORD_SIZE;
3694
0
                    }
3695
0
                    else if (v == wordNoData)
3696
0
                    {
3697
                        // All bytes are at nodata
3698
0
                        idxBuffer += WORD_SIZE;
3699
0
                        pDstLocation += WORD_SIZE;
3700
0
                    }
3701
0
                    else
3702
0
                    {
3703
                        // There are both bytes at nodata and valid bytes
3704
0
                        for (int k = 0; k < WORD_SIZE; ++k)
3705
0
                        {
3706
0
                            if (paSrcData[idxBuffer] != nNoDataValue)
3707
0
                            {
3708
0
                                memcpy(pDstLocation, &paSrcData[idxBuffer],
3709
0
                                       sizeof(WorkingDT));
3710
0
                            }
3711
0
                            idxBuffer++;
3712
0
                            pDstLocation += nPixelSpace;
3713
0
                        }
3714
0
                    }
3715
0
                }
3716
0
            }
3717
3718
0
            for (; iX < nOutXSize;
3719
0
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
3720
0
            {
3721
                if constexpr (eWorkingDT == GDT_Float32 ||
3722
                              eWorkingDT == GDT_Float64)
3723
0
                {
3724
0
                    if (std::isnan(paSrcData[idxBuffer]))
3725
0
                    {
3726
0
                        continue;
3727
0
                    }
3728
0
                }
3729
0
                if (paSrcData[idxBuffer] != nNoDataValue)
3730
0
                {
3731
0
                    memcpy(pDstLocation, &paSrcData[idxBuffer],
3732
0
                           sizeof(WorkingDT));
3733
0
                }
3734
0
            }
3735
0
        }
3736
0
    }
3737
0
    else if (!GDALDataTypeIsConversionLossy(eWorkingDT, eVRTBandDataType))
3738
0
    {
3739
        // Conversion from the work type to the VRT band data type is
3740
        // not lossy, so we can directly convert from the work type to
3741
        // the the output type
3742
0
        for (int iY = 0; iY < nOutYSize; iY++)
3743
0
        {
3744
0
            GByte *pDstLocation = static_cast<GByte *>(pData) +
3745
0
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
3746
3747
0
            for (int iX = 0; iX < nOutXSize;
3748
0
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
3749
0
            {
3750
                if constexpr (eWorkingDT == GDT_Float32 ||
3751
                              eWorkingDT == GDT_Float64)
3752
0
                {
3753
0
                    if (std::isnan(paSrcData[idxBuffer]))
3754
0
                    {
3755
0
                        continue;
3756
0
                    }
3757
0
                }
3758
0
                if (paSrcData[idxBuffer] != nNoDataValue)
3759
0
                {
3760
0
                    CopyWordOut(&paSrcData[idxBuffer], eWorkingDT, pDstLocation,
3761
0
                                eBufType);
3762
0
                }
3763
0
            }
3764
0
        }
3765
0
    }
3766
0
    else
3767
0
    {
3768
0
        const bool bClampToVRTBandType =
3769
0
            GDAL_GET_OPERATE_IN_BUF_TYPE(*psExtraArg);
3770
3771
0
        GByte abyTemp[2 * sizeof(double)];
3772
0
        for (int iY = 0; iY < nOutYSize; iY++)
3773
0
        {
3774
0
            GByte *pDstLocation = static_cast<GByte *>(pData) +
3775
0
                                  static_cast<GPtrDiff_t>(nLineSpace) * iY;
3776
3777
0
            for (int iX = 0; iX < nOutXSize;
3778
0
                 iX++, pDstLocation += nPixelSpace, idxBuffer++)
3779
0
            {
3780
                if constexpr (eWorkingDT == GDT_Float32 ||
3781
                              eWorkingDT == GDT_Float64)
3782
0
                {
3783
0
                    if (std::isnan(paSrcData[idxBuffer]))
3784
0
                    {
3785
0
                        continue;
3786
0
                    }
3787
0
                }
3788
0
                if (paSrcData[idxBuffer] != nNoDataValue)
3789
0
                {
3790
0
                    if (bClampToVRTBandType)
3791
0
                    {
3792
0
                        GDALClampValueToType(&paSrcData[idxBuffer],
3793
0
                                             eVRTBandDataType);
3794
0
                        CopyWordOut(&paSrcData[idxBuffer], eWorkingDT,
3795
0
                                    pDstLocation, eBufType);
3796
0
                    }
3797
0
                    else
3798
0
                    {
3799
                        // Convert first to the VRTRasterBand data type
3800
                        // to get its clamping, before outputting to buffer data type
3801
0
                        CopyWordOut(&paSrcData[idxBuffer], eWorkingDT, abyTemp,
3802
0
                                    eVRTBandDataType);
3803
0
                        GDALCopyWords(abyTemp, eVRTBandDataType, 0,
3804
0
                                      pDstLocation, eBufType, 0, 1);
3805
0
                    }
3806
0
                }
3807
0
            }
3808
0
        }
3809
0
    }
3810
3811
0
    return CE_None;
3812
0
}
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOProcessNoData<float, (GDALDataType)6>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, VRTSource::WorkingState&)
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOProcessNoData<double, (GDALDataType)7>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, VRTSource::WorkingState&)
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOProcessNoData<unsigned char, (GDALDataType)1>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, VRTSource::WorkingState&)
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOProcessNoData<short, (GDALDataType)3>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, VRTSource::WorkingState&)
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOProcessNoData<unsigned short, (GDALDataType)2>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, VRTSource::WorkingState&)
3813
3814
/************************************************************************/
3815
/*                          RasterIOInternal()                          */
3816
/************************************************************************/
3817
3818
// nReqXOff, nReqYOff, nReqXSize, nReqYSize are expressed in source band
3819
// referential.
3820
template <class WorkingDT>
3821
CPLErr VRTComplexSource::RasterIOInternal(
3822
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
3823
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
3824
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
3825
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
3826
    GDALDataType eWrkDataType, WorkingState &oWorkingState)
3827
0
{
3828
0
    const GDALColorTable *poColorTable = nullptr;
3829
0
    const bool bIsComplex = CPL_TO_BOOL(GDALDataTypeIsComplex(eBufType));
3830
0
    const int nWorkDTSize = GDALGetDataTypeSizeBytes(eWrkDataType);
3831
0
    assert(nWorkDTSize != 0);
3832
3833
    // If no explicit <NODATA> is set, but UseMaskBand is set, and the band
3834
    // has a nodata value, then use it as if it was set as <NODATA>
3835
0
    int bNoDataSet = (m_nProcessingFlags & PROCESSING_FLAG_NODATA) != 0;
3836
0
    double dfNoDataValue = GetAdjustedNoDataValue();
3837
3838
0
    if ((m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
3839
0
        poSourceBand->GetMaskFlags() == GMF_NODATA)
3840
0
    {
3841
0
        dfNoDataValue = poSourceBand->GetNoDataValue(&bNoDataSet);
3842
0
    }
3843
3844
0
    const bool bNoDataSetIsNan = bNoDataSet && std::isnan(dfNoDataValue);
3845
0
    const bool bNoDataSetAndNotNan =
3846
0
        bNoDataSet && !std::isnan(dfNoDataValue) &&
3847
0
        GDALIsValueInRange<WorkingDT>(dfNoDataValue);
3848
0
    const auto fWorkingDataTypeNoData = static_cast<WorkingDT>(dfNoDataValue);
3849
3850
0
    const GByte *pabyMask = nullptr;
3851
0
    const WorkingDT *pafData = nullptr;
3852
0
    if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0 &&
3853
0
        m_dfScaleRatio == 0 && bNoDataSet == FALSE &&
3854
0
        (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) == 0)
3855
0
    {
3856
        /* ------------------------------------------------------------------ */
3857
        /*      Optimization when writing a constant value */
3858
        /*      (used by the -addalpha option of gdalbuildvrt) */
3859
        /* ------------------------------------------------------------------ */
3860
        // Already set to NULL when defined.
3861
        // pafData = NULL;
3862
0
    }
3863
0
    else
3864
0
    {
3865
        /* ---------------------------------------------------------------- */
3866
        /*      Read into a temporary buffer.                               */
3867
        /* ---------------------------------------------------------------- */
3868
0
        const size_t nPixelCount = static_cast<size_t>(nOutXSize) * nOutYSize;
3869
0
        try
3870
0
        {
3871
            // Cannot overflow since pData should at least have that number of
3872
            // elements
3873
0
            if (nPixelCount >
3874
0
                static_cast<size_t>(std::numeric_limits<ptrdiff_t>::max()) /
3875
0
                    static_cast<size_t>(nWorkDTSize))
3876
0
            {
3877
0
                CPLError(CE_Failure, CPLE_OutOfMemory,
3878
0
                         "Too large temporary buffer");
3879
0
                return CE_Failure;
3880
0
            }
3881
0
            oWorkingState.m_abyWrkBuffer.resize(nWorkDTSize * nPixelCount);
3882
0
        }
3883
0
        catch (const std::bad_alloc &e)
3884
0
        {
3885
0
            CPLError(CE_Failure, CPLE_OutOfMemory, "%s", e.what());
3886
0
            return CE_Failure;
3887
0
        }
3888
0
        pafData = reinterpret_cast<const WorkingDT *>(
3889
0
            oWorkingState.m_abyWrkBuffer.data());
3890
3891
0
        GDALRasterIOExtraArg sExtraArg;
3892
0
        GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
3893
0
        if (!m_osResampling.empty())
3894
0
        {
3895
0
            sExtraArg.eResampleAlg = GDALRasterIOGetResampleAlg(m_osResampling);
3896
0
        }
3897
0
        sExtraArg.bOperateInBufType = true;
3898
3899
0
        const CPLErr eErr = poSourceBand->RasterIO(
3900
0
            GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3901
0
            oWorkingState.m_abyWrkBuffer.data(), nOutXSize, nOutYSize,
3902
0
            eWrkDataType, nWorkDTSize,
3903
0
            nWorkDTSize * static_cast<GSpacing>(nOutXSize), &sExtraArg);
3904
3905
0
        if (eErr != CE_None)
3906
0
        {
3907
0
            return eErr;
3908
0
        }
3909
3910
        // Allocate and read mask band if needed
3911
0
        if (!bNoDataSet &&
3912
0
            (m_nProcessingFlags & PROCESSING_FLAG_USE_MASK_BAND) != 0 &&
3913
0
            (poSourceBand->GetMaskFlags() != GMF_ALL_VALID ||
3914
0
             poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
3915
0
             GetMaskBandMainBand() != nullptr))
3916
0
        {
3917
0
            try
3918
0
            {
3919
0
                oWorkingState.m_abyWrkBufferMask.resize(nPixelCount);
3920
0
            }
3921
0
            catch (const std::exception &)
3922
0
            {
3923
0
                CPLError(CE_Failure, CPLE_OutOfMemory,
3924
0
                         "Out of memory when allocating mask buffer");
3925
0
                return CE_Failure;
3926
0
            }
3927
0
            pabyMask = reinterpret_cast<const GByte *>(
3928
0
                oWorkingState.m_abyWrkBufferMask.data());
3929
0
            auto poMaskBand =
3930
0
                (poSourceBand->GetColorInterpretation() == GCI_AlphaBand ||
3931
0
                 GetMaskBandMainBand() != nullptr)
3932
0
                    ? poSourceBand
3933
0
                    : poSourceBand->GetMaskBand();
3934
0
            if (poMaskBand->RasterIO(
3935
0
                    GF_Read, nReqXOff, nReqYOff, nReqXSize, nReqYSize,
3936
0
                    oWorkingState.m_abyWrkBufferMask.data(), nOutXSize,
3937
0
                    nOutYSize, GDT_UInt8, 1, static_cast<GSpacing>(nOutXSize),
3938
0
                    psExtraArg) != CE_None)
3939
0
            {
3940
0
                return CE_Failure;
3941
0
            }
3942
0
        }
3943
3944
0
        if (m_nColorTableComponent != 0)
3945
0
        {
3946
0
            poColorTable = poSourceBand->GetColorTable();
3947
0
            if (poColorTable == nullptr)
3948
0
            {
3949
0
                CPLError(CE_Failure, CPLE_AppDefined,
3950
0
                         "Source band has no color table.");
3951
0
                return CE_Failure;
3952
0
            }
3953
0
        }
3954
0
    }
3955
3956
    /* -------------------------------------------------------------------- */
3957
    /*      Selectively copy into output buffer with nodata masking,        */
3958
    /*      and/or scaling.                                                 */
3959
    /* -------------------------------------------------------------------- */
3960
3961
0
    const bool bTwoStepDataTypeConversion =
3962
0
        CPL_TO_BOOL(
3963
0
            GDALDataTypeIsConversionLossy(eWrkDataType, eVRTBandDataType)) &&
3964
0
        !CPL_TO_BOOL(GDALDataTypeIsConversionLossy(eVRTBandDataType, eBufType));
3965
3966
0
    size_t idxBuffer = 0;
3967
0
    for (int iY = 0; iY < nOutYSize; iY++)
3968
0
    {
3969
0
        GByte *pDstLocation = static_cast<GByte *>(pData) +
3970
0
                              static_cast<GPtrDiff_t>(nLineSpace) * iY;
3971
3972
0
        for (int iX = 0; iX < nOutXSize;
3973
0
             iX++, pDstLocation += nPixelSpace, idxBuffer++)
3974
0
        {
3975
0
            WorkingDT afResult[2];
3976
0
            if (pafData && !bIsComplex)
3977
0
            {
3978
0
                WorkingDT fResult = pafData[idxBuffer];
3979
0
                if (bNoDataSetIsNan && std::isnan(fResult))
3980
0
                    continue;
3981
0
                if (bNoDataSetAndNotNan &&
3982
0
                    ARE_REAL_EQUAL(fResult, fWorkingDataTypeNoData))
3983
0
                    continue;
3984
0
                if (pabyMask && pabyMask[idxBuffer] == 0)
3985
0
                    continue;
3986
3987
0
                if (poColorTable)
3988
0
                {
3989
0
                    const GDALColorEntry *poEntry =
3990
0
                        poColorTable->GetColorEntry(static_cast<int>(fResult));
3991
0
                    if (poEntry)
3992
0
                    {
3993
0
                        if (m_nColorTableComponent == 1)
3994
0
                            fResult = poEntry->c1;
3995
0
                        else if (m_nColorTableComponent == 2)
3996
0
                            fResult = poEntry->c2;
3997
0
                        else if (m_nColorTableComponent == 3)
3998
0
                            fResult = poEntry->c3;
3999
0
                        else if (m_nColorTableComponent == 4)
4000
0
                            fResult = poEntry->c4;
4001
0
                    }
4002
0
                    else
4003
0
                    {
4004
0
                        CPLErrorOnce(CE_Failure, CPLE_AppDefined,
4005
0
                                     "No entry %d.", static_cast<int>(fResult));
4006
0
                        continue;
4007
0
                    }
4008
0
                }
4009
4010
0
                if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
4011
0
                {
4012
0
                    fResult = static_cast<WorkingDT>(fResult * m_dfScaleRatio +
4013
0
                                                     m_dfScaleOff);
4014
0
                }
4015
0
                else if ((m_nProcessingFlags &
4016
0
                          PROCESSING_FLAG_SCALING_EXPONENTIAL) != 0)
4017
0
                {
4018
0
                    if (!m_bSrcMinMaxDefined)
4019
0
                    {
4020
0
                        int bSuccessMin = FALSE;
4021
0
                        int bSuccessMax = FALSE;
4022
0
                        double adfMinMax[2] = {
4023
0
                            poSourceBand->GetMinimum(&bSuccessMin),
4024
0
                            poSourceBand->GetMaximum(&bSuccessMax)};
4025
0
                        if ((bSuccessMin && bSuccessMax) ||
4026
0
                            poSourceBand->ComputeRasterMinMax(
4027
0
                                TRUE, adfMinMax) == CE_None)
4028
0
                        {
4029
0
                            m_dfSrcMin = adfMinMax[0];
4030
0
                            m_dfSrcMax = adfMinMax[1];
4031
0
                            m_bSrcMinMaxDefined = true;
4032
0
                        }
4033
0
                        else
4034
0
                        {
4035
0
                            CPLError(CE_Failure, CPLE_AppDefined,
4036
0
                                     "Cannot determine source min/max value");
4037
0
                            return CE_Failure;
4038
0
                        }
4039
0
                    }
4040
4041
0
                    double dfPowVal = (m_dfSrcMin == m_dfSrcMax)
4042
0
                                          ? 0
4043
0
                                          : (fResult - m_dfSrcMin) /
4044
0
                                                (m_dfSrcMax - m_dfSrcMin);
4045
0
                    if (m_bClip)
4046
0
                    {
4047
0
                        if (dfPowVal < 0.0)
4048
0
                            dfPowVal = 0.0;
4049
0
                        else if (dfPowVal > 1.0)
4050
0
                            dfPowVal = 1.0;
4051
0
                    }
4052
0
                    fResult =
4053
0
                        static_cast<WorkingDT>((m_dfDstMax - m_dfDstMin) *
4054
0
                                                   pow(dfPowVal, m_dfExponent) +
4055
0
                                               m_dfDstMin);
4056
0
                }
4057
4058
0
                if (!m_adfLUTInputs.empty())
4059
0
                    fResult = static_cast<WorkingDT>(LookupValue(fResult));
4060
4061
0
                if (m_nMaxValue != 0 && fResult > m_nMaxValue)
4062
0
                    fResult = static_cast<WorkingDT>(m_nMaxValue);
4063
4064
0
                afResult[0] = fResult;
4065
0
                afResult[1] = 0;
4066
0
            }
4067
0
            else if (pafData && bIsComplex)
4068
0
            {
4069
0
                afResult[0] = pafData[2 * idxBuffer];
4070
0
                afResult[1] = pafData[2 * idxBuffer + 1];
4071
4072
                // Do not use color table.
4073
0
                if ((m_nProcessingFlags & PROCESSING_FLAG_SCALING_LINEAR) != 0)
4074
0
                {
4075
0
                    afResult[0] = static_cast<WorkingDT>(
4076
0
                        afResult[0] * m_dfScaleRatio + m_dfScaleOff);
4077
0
                    afResult[1] = static_cast<WorkingDT>(
4078
0
                        afResult[1] * m_dfScaleRatio + m_dfScaleOff);
4079
0
                }
4080
4081
                /* Do not use LUT */
4082
0
            }
4083
0
            else
4084
0
            {
4085
0
                afResult[0] = static_cast<WorkingDT>(m_dfScaleOff);
4086
0
                afResult[1] = 0;
4087
4088
0
                if (!m_adfLUTInputs.empty())
4089
0
                    afResult[0] =
4090
0
                        static_cast<WorkingDT>(LookupValue(afResult[0]));
4091
4092
0
                if (m_nMaxValue != 0 && afResult[0] > m_nMaxValue)
4093
0
                    afResult[0] = static_cast<WorkingDT>(m_nMaxValue);
4094
0
            }
4095
4096
0
            if (eBufType == GDT_UInt8 && eVRTBandDataType == GDT_UInt8)
4097
0
            {
4098
0
                *pDstLocation = static_cast<GByte>(std::min(
4099
0
                    255.0f,
4100
0
                    std::max(0.0f, static_cast<float>(afResult[0]) + 0.5f)));
4101
0
            }
4102
0
            else if (!bTwoStepDataTypeConversion)
4103
0
            {
4104
0
                CopyWordOut(afResult, eWrkDataType, pDstLocation, eBufType);
4105
0
            }
4106
0
            else if (eVRTBandDataType == GDT_Float32 && eBufType == GDT_Float64)
4107
0
            {
4108
                // Particular case of the below 2-step conversion.
4109
                // Helps a bit for some geolocation based warping with Sentinel3
4110
                // data where the longitude/latitude arrays are Int32 bands,
4111
                // rescaled in VRT as Float32 and requested as Float64
4112
0
                float fVal;
4113
0
                GDALCopyWord(afResult[0], fVal);
4114
0
                *reinterpret_cast<double *>(pDstLocation) = fVal;
4115
0
            }
4116
0
            else
4117
0
            {
4118
0
                GByte abyTemp[2 * sizeof(double)];
4119
                // Convert first to the VRTRasterBand data type
4120
                // to get its clamping, before outputting to buffer data type
4121
0
                CopyWordOut(afResult, eWrkDataType, abyTemp, eVRTBandDataType);
4122
0
                GDALCopyWords(abyTemp, eVRTBandDataType, 0, pDstLocation,
4123
0
                              eBufType, 0, 1);
4124
0
            }
4125
0
        }
4126
0
    }
4127
4128
0
    return CE_None;
4129
0
}
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOInternal<float>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, GDALDataType, VRTSource::WorkingState&)
Unexecuted instantiation: CPLErr VRTComplexSource::RasterIOInternal<double>(GDALRasterBand*, GDALDataType, int, int, int, int, void*, int, int, GDALDataType, long long, long long, GDALRasterIOExtraArg*, GDALDataType, VRTSource::WorkingState&)
4130
4131
// Explicitly instantiate template method, as it is used in another file.
4132
template CPLErr VRTComplexSource::RasterIOInternal<float>(
4133
    GDALRasterBand *poSourceBand, GDALDataType eVRTBandDataType, int nReqXOff,
4134
    int nReqYOff, int nReqXSize, int nReqYSize, void *pData, int nOutXSize,
4135
    int nOutYSize, GDALDataType eBufType, GSpacing nPixelSpace,
4136
    GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg,
4137
    GDALDataType eWrkDataType, WorkingState &oWorkingState);
4138
4139
/************************************************************************/
4140
/*                         AreValuesUnchanged()                         */
4141
/************************************************************************/
4142
4143
bool VRTComplexSource::AreValuesUnchanged() const
4144
0
{
4145
0
    return m_dfScaleOff == 0.0 && m_dfScaleRatio == 1.0 &&
4146
0
           m_adfLUTInputs.empty() && m_nColorTableComponent == 0 &&
4147
0
           (m_nProcessingFlags & PROCESSING_FLAG_SCALING_EXPONENTIAL) == 0;
4148
0
}
4149
4150
/************************************************************************/
4151
/*                             GetMinimum()                             */
4152
/************************************************************************/
4153
4154
double VRTComplexSource::GetMinimum(int nXSize, int nYSize, int *pbSuccess)
4155
0
{
4156
0
    if (AreValuesUnchanged())
4157
0
    {
4158
0
        return VRTSimpleSource::GetMinimum(nXSize, nYSize, pbSuccess);
4159
0
    }
4160
4161
0
    *pbSuccess = FALSE;
4162
0
    return 0;
4163
0
}
4164
4165
/************************************************************************/
4166
/*                             GetMaximum()                             */
4167
/************************************************************************/
4168
4169
double VRTComplexSource::GetMaximum(int nXSize, int nYSize, int *pbSuccess)
4170
0
{
4171
0
    if (AreValuesUnchanged())
4172
0
    {
4173
0
        return VRTSimpleSource::GetMaximum(nXSize, nYSize, pbSuccess);
4174
0
    }
4175
4176
0
    *pbSuccess = FALSE;
4177
0
    return 0;
4178
0
}
4179
4180
/************************************************************************/
4181
/*                            GetHistogram()                            */
4182
/************************************************************************/
4183
4184
CPLErr VRTComplexSource::GetHistogram(int nXSize, int nYSize, double dfMin,
4185
                                      double dfMax, int nBuckets,
4186
                                      GUIntBig *panHistogram,
4187
                                      int bIncludeOutOfRange, int bApproxOK,
4188
                                      GDALProgressFunc pfnProgress,
4189
                                      void *pProgressData)
4190
0
{
4191
0
    if (AreValuesUnchanged())
4192
0
    {
4193
0
        return VRTSimpleSource::GetHistogram(
4194
0
            nXSize, nYSize, dfMin, dfMax, nBuckets, panHistogram,
4195
0
            bIncludeOutOfRange, bApproxOK, pfnProgress, pProgressData);
4196
0
    }
4197
4198
0
    return CE_Failure;
4199
0
}
4200
4201
/************************************************************************/
4202
/* ==================================================================== */
4203
/*                          VRTFuncSource                               */
4204
/* ==================================================================== */
4205
/************************************************************************/
4206
4207
/************************************************************************/
4208
/*                           VRTFuncSource()                            */
4209
/************************************************************************/
4210
4211
VRTFuncSource::VRTFuncSource()
4212
0
    : pfnReadFunc(nullptr), pCBData(nullptr), eType(GDT_UInt8),
4213
0
      fNoDataValue(static_cast<float>(VRT_NODATA_UNSET))
4214
0
{
4215
0
}
4216
4217
/************************************************************************/
4218
/*                           ~VRTFuncSource()                           */
4219
/************************************************************************/
4220
4221
VRTFuncSource::~VRTFuncSource()
4222
{
4223
}
4224
4225
/************************************************************************/
4226
/*                              GetType()                               */
4227
/************************************************************************/
4228
4229
const char *VRTFuncSource::GetType() const
4230
0
{
4231
0
    static const char *TYPE = "FuncSource";
4232
0
    return TYPE;
4233
0
}
4234
4235
/************************************************************************/
4236
/*                           SerializeToXML()                           */
4237
/************************************************************************/
4238
4239
CPLXMLNode *VRTFuncSource::SerializeToXML(CPL_UNUSED const char *pszVRTPath)
4240
0
{
4241
0
    return nullptr;
4242
0
}
4243
4244
/************************************************************************/
4245
/*                              RasterIO()                              */
4246
/************************************************************************/
4247
4248
CPLErr VRTFuncSource::RasterIO(GDALDataType /*eVRTBandDataType*/, int nXOff,
4249
                               int nYOff, int nXSize, int nYSize, void *pData,
4250
                               int nBufXSize, int nBufYSize,
4251
                               GDALDataType eBufType, GSpacing nPixelSpace,
4252
                               GSpacing nLineSpace,
4253
                               GDALRasterIOExtraArg * /* psExtraArg */,
4254
                               WorkingState & /* oWorkingState */)
4255
0
{
4256
0
    if (nPixelSpace == GDALGetDataTypeSizeBytes(eBufType) &&
4257
0
        nLineSpace == nPixelSpace * nXSize && nBufXSize == nXSize &&
4258
0
        nBufYSize == nYSize && eBufType == eType)
4259
0
    {
4260
0
        return pfnReadFunc(pCBData, nXOff, nYOff, nXSize, nYSize, pData);
4261
0
    }
4262
0
    else
4263
0
    {
4264
0
        CPLError(CE_Failure, CPLE_AppDefined,
4265
0
                 "VRTFuncSource::RasterIO() - Irregular request.");
4266
0
        CPLDebug("VRT", "Irregular request: %d,%d  %d,%d, %d,%d %d,%d %d,%d",
4267
0
                 static_cast<int>(nPixelSpace),
4268
0
                 GDALGetDataTypeSizeBytes(eBufType),
4269
0
                 static_cast<int>(nLineSpace),
4270
0
                 static_cast<int>(nPixelSpace) * nXSize, nBufXSize, nXSize,
4271
0
                 nBufYSize, nYSize, static_cast<int>(eBufType),
4272
0
                 static_cast<int>(eType));
4273
4274
0
        return CE_Failure;
4275
0
    }
4276
0
}
4277
4278
/************************************************************************/
4279
/*                             GetMinimum()                             */
4280
/************************************************************************/
4281
4282
double VRTFuncSource::GetMinimum(int /* nXSize */, int /* nYSize */,
4283
                                 int *pbSuccess)
4284
0
{
4285
0
    *pbSuccess = FALSE;
4286
0
    return 0;
4287
0
}
4288
4289
/************************************************************************/
4290
/*                             GetMaximum()                             */
4291
/************************************************************************/
4292
4293
double VRTFuncSource::GetMaximum(int /* nXSize */, int /* nYSize */,
4294
                                 int *pbSuccess)
4295
0
{
4296
0
    *pbSuccess = FALSE;
4297
0
    return 0;
4298
0
}
4299
4300
/************************************************************************/
4301
/*                            GetHistogram()                            */
4302
/************************************************************************/
4303
4304
CPLErr VRTFuncSource::GetHistogram(
4305
    int /* nXSize */, int /* nYSize */, double /* dfMin */, double /* dfMax */,
4306
    int /* nBuckets */, GUIntBig * /* panHistogram */,
4307
    int /* bIncludeOutOfRange */, int /* bApproxOK */,
4308
    GDALProgressFunc /* pfnProgress */, void * /* pProgressData */)
4309
0
{
4310
0
    return CE_Failure;
4311
0
}
4312
4313
/************************************************************************/
4314
/*                        VRTParseCoreSources()                         */
4315
/************************************************************************/
4316
4317
VRTSource *VRTParseCoreSources(const CPLXMLNode *psChild,
4318
                               const char *pszVRTPath,
4319
                               VRTMapSharedResources &oMapSharedSources)
4320
4321
0
{
4322
0
    VRTSource *poSource = nullptr;
4323
4324
0
    if (EQUAL(psChild->pszValue, VRTAveragedSource::GetTypeStatic()) ||
4325
0
        (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()) &&
4326
0
         STARTS_WITH_CI(CPLGetXMLValue(psChild, "Resampling", "Nearest"),
4327
0
                        "Aver")))
4328
0
    {
4329
0
        poSource = new VRTAveragedSource();
4330
0
    }
4331
0
    else if (EQUAL(psChild->pszValue, VRTSimpleSource::GetTypeStatic()))
4332
0
    {
4333
0
        poSource = new VRTSimpleSource();
4334
0
    }
4335
0
    else if (EQUAL(psChild->pszValue, VRTComplexSource::GetTypeStatic()))
4336
0
    {
4337
0
        poSource = new VRTComplexSource();
4338
0
    }
4339
0
    else if (EQUAL(psChild->pszValue, VRTNoDataFromMaskSource::GetTypeStatic()))
4340
0
    {
4341
0
        poSource = new VRTNoDataFromMaskSource();
4342
0
    }
4343
0
    else
4344
0
    {
4345
0
        CPLError(CE_Failure, CPLE_AppDefined,
4346
0
                 "VRTParseCoreSources() - Unknown source : %s",
4347
0
                 psChild->pszValue);
4348
0
        return nullptr;
4349
0
    }
4350
4351
0
    if (poSource->XMLInit(psChild, pszVRTPath, oMapSharedSources) == CE_None)
4352
0
        return poSource;
4353
4354
0
    delete poSource;
4355
0
    return nullptr;
4356
0
}
4357
4358
/*! @endcond */