Coverage Report

Created: 2025-12-31 06:48

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