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

OSGeo / gdal / 15885686134

25 Jun 2025 07:44PM UTC coverage: 71.084%. Remained the same
15885686134

push

github

rouault
gdal_priv.h: fix C++11 compatibility

573814 of 807237 relevant lines covered (71.08%)

250621.56 hits per line

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

93.61
/frmts/vrt/vrtderivedrasterband.cpp
1
/******************************************************************************
2
 *
3
 * Project:  Virtual GDAL Datasets
4
 * Purpose:  Implementation of a sourced raster band that derives its raster
5
 *           by applying an algorithm (GDALDerivedPixelFunc) to the sources.
6
 * Author:   Pete Nagy
7
 *
8
 ******************************************************************************
9
 * Copyright (c) 2005 Vexcel Corp.
10
 * Copyright (c) 2008-2011, Even Rouault <even dot rouault at spatialys.com>
11
 *
12
 * SPDX-License-Identifier: MIT
13
 *****************************************************************************/
14

15
#include "cpl_minixml.h"
16
#include "cpl_string.h"
17
#include "vrtdataset.h"
18
#include "cpl_multiproc.h"
19
#include "gdalpython.h"
20

21
#include <algorithm>
22
#include <array>
23
#include <map>
24
#include <vector>
25
#include <utility>
26

27
/*! @cond Doxygen_Suppress */
28

29
using namespace GDALPy;
30

31
// #define GDAL_VRT_DISABLE_PYTHON
32

33
#ifndef GDAL_VRT_ENABLE_PYTHON_DEFAULT
34
// Can be YES, NO or TRUSTED_MODULES
35
#define GDAL_VRT_ENABLE_PYTHON_DEFAULT "TRUSTED_MODULES"
36
#endif
37

38
/* Flags for getting buffers */
39
#define PyBUF_WRITABLE 0x0001
40
#define PyBUF_FORMAT 0x0004
41
#define PyBUF_ND 0x0008
42
#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
43
#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
44
#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT)
45

46
/************************************************************************/
47
/*                        GDALCreateNumpyArray()                        */
48
/************************************************************************/
49

50
static PyObject *GDALCreateNumpyArray(PyObject *pCreateArray, void *pBuffer,
399✔
51
                                      GDALDataType eType, int nHeight,
52
                                      int nWidth)
53
{
54
    PyObject *poPyBuffer;
55
    const size_t nSize =
56
        static_cast<size_t>(nHeight) * nWidth * GDALGetDataTypeSizeBytes(eType);
399✔
57
    Py_buffer pybuffer;
58
    if (PyBuffer_FillInfo(&pybuffer, nullptr, static_cast<char *>(pBuffer),
399✔
59
                          nSize, 0, PyBUF_FULL) != 0)
399✔
60
    {
61
        return nullptr;
×
62
    }
63
    poPyBuffer = PyMemoryView_FromBuffer(&pybuffer);
399✔
64
    PyObject *pArgsCreateArray = PyTuple_New(4);
399✔
65
    PyTuple_SetItem(pArgsCreateArray, 0, poPyBuffer);
399✔
66
    const char *pszDataType = nullptr;
399✔
67
    switch (eType)
399✔
68
    {
69
        case GDT_Byte:
357✔
70
            pszDataType = "uint8";
357✔
71
            break;
357✔
72
        case GDT_Int8:
15✔
73
            pszDataType = "int8";
15✔
74
            break;
15✔
75
        case GDT_UInt16:
2✔
76
            pszDataType = "uint16";
2✔
77
            break;
2✔
78
        case GDT_Int16:
7✔
79
            pszDataType = "int16";
7✔
80
            break;
7✔
81
        case GDT_UInt32:
2✔
82
            pszDataType = "uint32";
2✔
83
            break;
2✔
84
        case GDT_Int32:
2✔
85
            pszDataType = "int32";
2✔
86
            break;
2✔
87
        case GDT_Int64:
2✔
88
            pszDataType = "int64";
2✔
89
            break;
2✔
90
        case GDT_UInt64:
2✔
91
            pszDataType = "uint64";
2✔
92
            break;
2✔
93
        case GDT_Float16:
2✔
94
            pszDataType = "float16";
2✔
95
            break;
2✔
96
        case GDT_Float32:
2✔
97
            pszDataType = "float32";
2✔
98
            break;
2✔
99
        case GDT_Float64:
2✔
100
            pszDataType = "float64";
2✔
101
            break;
2✔
102
        case GDT_CInt16:
×
103
        case GDT_CInt32:
104
            CPLAssert(FALSE);
×
105
            break;
106
        case GDT_CFloat16:
×
107
            CPLAssert(FALSE);
×
108
            break;
109
        case GDT_CFloat32:
2✔
110
            pszDataType = "complex64";
2✔
111
            break;
2✔
112
        case GDT_CFloat64:
2✔
113
            pszDataType = "complex128";
2✔
114
            break;
2✔
115
        case GDT_Unknown:
×
116
        case GDT_TypeCount:
117
            CPLAssert(FALSE);
×
118
            break;
119
    }
120
    PyTuple_SetItem(
399✔
121
        pArgsCreateArray, 1,
122
        PyBytes_FromStringAndSize(pszDataType, strlen(pszDataType)));
123
    PyTuple_SetItem(pArgsCreateArray, 2, PyLong_FromLong(nHeight));
399✔
124
    PyTuple_SetItem(pArgsCreateArray, 3, PyLong_FromLong(nWidth));
399✔
125
    PyObject *poNumpyArray =
126
        PyObject_Call(pCreateArray, pArgsCreateArray, nullptr);
399✔
127
    Py_DecRef(pArgsCreateArray);
399✔
128
    if (PyErr_Occurred())
399✔
129
        PyErr_Print();
×
130
    return poNumpyArray;
399✔
131
}
132

133
/************************************************************************/
134
/* ==================================================================== */
135
/*                     VRTDerivedRasterBandPrivateData                  */
136
/* ==================================================================== */
137
/************************************************************************/
138

139
class VRTDerivedRasterBandPrivateData
140
{
141
    VRTDerivedRasterBandPrivateData(const VRTDerivedRasterBandPrivateData &) =
142
        delete;
143
    VRTDerivedRasterBandPrivateData &
144
    operator=(const VRTDerivedRasterBandPrivateData &) = delete;
145

146
  public:
147
    CPLString m_osCode{};
148
    CPLString m_osLanguage = "C";
149
    int m_nBufferRadius = 0;
150
    PyObject *m_poGDALCreateNumpyArray = nullptr;
151
    PyObject *m_poUserFunction = nullptr;
152
    bool m_bPythonInitializationDone = false;
153
    bool m_bPythonInitializationSuccess = false;
154
    bool m_bExclusiveLock = false;
155
    bool m_bFirstTime = true;
156
    std::vector<std::pair<CPLString, CPLString>> m_oFunctionArgs{};
157
    bool m_bSkipNonContributingSourcesSpecified = false;
158
    bool m_bSkipNonContributingSources = false;
159
    GIntBig m_nAllowedRAMUsage = 0;
160

161
    VRTDerivedRasterBandPrivateData()
1,977✔
162
        : m_nAllowedRAMUsage(CPLGetUsablePhysicalRAM() / 10 * 4)
1,977✔
163
    {
164
        // Use only up to 40% of RAM to acquire source bands and generate the
165
        // output buffer.
166
        // Only for tests now
167
        const char *pszMAX_RAM = "VRT_DERIVED_DATASET_ALLOWED_RAM_USAGE";
1,977✔
168
        if (const char *pszVal = CPLGetConfigOption(pszMAX_RAM, nullptr))
1,977✔
169
        {
170
            CPL_IGNORE_RET_VAL(
1✔
171
                CPLParseMemorySize(pszVal, &m_nAllowedRAMUsage, nullptr));
1✔
172
        }
173
    }
1,977✔
174

175
    ~VRTDerivedRasterBandPrivateData();
176
};
177

178
VRTDerivedRasterBandPrivateData::~VRTDerivedRasterBandPrivateData()
1,977✔
179
{
180
    if (m_poGDALCreateNumpyArray)
1,977✔
181
        Py_DecRef(m_poGDALCreateNumpyArray);
48✔
182
    if (m_poUserFunction)
1,977✔
183
        Py_DecRef(m_poUserFunction);
49✔
184
}
1,977✔
185

186
/************************************************************************/
187
/* ==================================================================== */
188
/*                          VRTDerivedRasterBand                        */
189
/* ==================================================================== */
190
/************************************************************************/
191

192
/************************************************************************/
193
/*                        VRTDerivedRasterBand()                        */
194
/************************************************************************/
195

196
VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn)
1,445✔
197
    : VRTSourcedRasterBand(poDSIn, nBandIn), m_poPrivate(nullptr),
198
      eSourceTransferType(GDT_Unknown)
1,445✔
199
{
200
    m_poPrivate = new VRTDerivedRasterBandPrivateData;
1,445✔
201
}
1,445✔
202

203
/************************************************************************/
204
/*                        VRTDerivedRasterBand()                        */
205
/************************************************************************/
206

207
VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn,
532✔
208
                                           GDALDataType eType, int nXSize,
209
                                           int nYSize, int nBlockXSizeIn,
210
                                           int nBlockYSizeIn)
532✔
211
    : VRTSourcedRasterBand(poDSIn, nBandIn, eType, nXSize, nYSize,
212
                           nBlockXSizeIn, nBlockYSizeIn),
213
      m_poPrivate(nullptr), eSourceTransferType(GDT_Unknown)
532✔
214
{
215
    m_poPrivate = new VRTDerivedRasterBandPrivateData;
532✔
216
}
532✔
217

218
/************************************************************************/
219
/*                       ~VRTDerivedRasterBand()                        */
220
/************************************************************************/
221

222
VRTDerivedRasterBand::~VRTDerivedRasterBand()
3,954✔
223

224
{
225
    delete m_poPrivate;
1,977✔
226
}
3,954✔
227

228
/************************************************************************/
229
/*                               Cleanup()                              */
230
/************************************************************************/
231

232
void VRTDerivedRasterBand::Cleanup()
1,113✔
233
{
234
}
1,113✔
235

236
/************************************************************************/
237
/*                      GetGlobalMapPixelFunction()                     */
238
/************************************************************************/
239

240
static std::map<std::string,
241
                std::pair<VRTDerivedRasterBand::PixelFunc, std::string>> &
242
GetGlobalMapPixelFunction()
52,833✔
243
{
244
    static std::map<std::string,
245
                    std::pair<VRTDerivedRasterBand::PixelFunc, std::string>>
246
        gosMapPixelFunction;
52,833✔
247
    return gosMapPixelFunction;
52,833✔
248
}
249

250
/************************************************************************/
251
/*                           AddPixelFunction()                         */
252
/************************************************************************/
253

254
/*! @endcond */
255

256
/**
257
 * This adds a pixel function to the global list of available pixel
258
 * functions for derived bands.  Pixel functions must be registered
259
 * in this way before a derived band tries to access data.
260
 *
261
 * Derived bands are stored with only the name of the pixel function
262
 * that it will apply, and if a pixel function matching the name is not
263
 * found the IRasterIO() call will do nothing.
264
 *
265
 * @param pszName Name used to access pixel function
266
 * @param pfnNewFunction Pixel function associated with name.  An
267
 *  existing pixel function registered with the same name will be
268
 *  replaced with the new one.
269
 *
270
 * @return CE_None, invalid (NULL) parameters are currently ignored.
271
 */
272
CPLErr CPL_STDCALL GDALAddDerivedBandPixelFunc(
14,292✔
273
    const char *pszName, GDALDerivedPixelFunc pfnNewFunction)
274
{
275
    if (pszName == nullptr || pszName[0] == '\0' || pfnNewFunction == nullptr)
14,292✔
276
    {
277
        return CE_None;
×
278
    }
279

280
    GetGlobalMapPixelFunction()[pszName] = {
28,584✔
281
        [pfnNewFunction](void **papoSources, int nSources, void *pData,
47✔
282
                         int nBufXSize, int nBufYSize, GDALDataType eSrcType,
283
                         GDALDataType eBufType, int nPixelSpace, int nLineSpace,
284
                         CSLConstList papszFunctionArgs)
47✔
285
        {
286
            (void)papszFunctionArgs;
287
            return pfnNewFunction(papoSources, nSources, pData, nBufXSize,
47✔
288
                                  nBufYSize, eSrcType, eBufType, nPixelSpace,
289
                                  nLineSpace);
47✔
290
        },
291
        ""};
42,876✔
292

293
    return CE_None;
14,292✔
294
}
295

296
/**
297
 * This adds a pixel function to the global list of available pixel
298
 * functions for derived bands.  Pixel functions must be registered
299
 * in this way before a derived band tries to access data.
300
 *
301
 * Derived bands are stored with only the name of the pixel function
302
 * that it will apply, and if a pixel function matching the name is not
303
 * found the IRasterIO() call will do nothing.
304
 *
305
 * @param pszName Name used to access pixel function
306
 * @param pfnNewFunction Pixel function associated with name.  An
307
 *  existing pixel function registered with the same name will be
308
 *  replaced with the new one.
309
 * @param pszMetadata Pixel function metadata (not currently implemented)
310
 *
311
 * @return CE_None, invalid (NULL) parameters are currently ignored.
312
 * @since GDAL 3.4
313
 */
314
CPLErr CPL_STDCALL GDALAddDerivedBandPixelFuncWithArgs(
35,727✔
315
    const char *pszName, GDALDerivedPixelFuncWithArgs pfnNewFunction,
316
    const char *pszMetadata)
317
{
318
    if (!pszName || pszName[0] == '\0' || !pfnNewFunction)
35,727✔
319
    {
320
        return CE_None;
×
321
    }
322

323
    GetGlobalMapPixelFunction()[pszName] = {pfnNewFunction,
71,454✔
324
                                            pszMetadata ? pszMetadata : ""};
107,181✔
325

326
    return CE_None;
35,727✔
327
}
328

329
/*! @cond Doxygen_Suppress */
330

331
/**
332
 * This adds a pixel function to the global list of available pixel
333
 * functions for derived bands.
334
 *
335
 * This is the same as the C function GDALAddDerivedBandPixelFunc()
336
 *
337
 * @param pszFuncNameIn Name used to access pixel function
338
 * @param pfnNewFunction Pixel function associated with name.  An
339
 *  existing pixel function registered with the same name will be
340
 *  replaced with the new one.
341
 *
342
 * @return CE_None, invalid (NULL) parameters are currently ignored.
343
 */
344
CPLErr
345
VRTDerivedRasterBand::AddPixelFunction(const char *pszFuncNameIn,
×
346
                                       GDALDerivedPixelFunc pfnNewFunction)
347
{
348
    return GDALAddDerivedBandPixelFunc(pszFuncNameIn, pfnNewFunction);
×
349
}
350

351
CPLErr VRTDerivedRasterBand::AddPixelFunction(
×
352
    const char *pszFuncNameIn, GDALDerivedPixelFuncWithArgs pfnNewFunction,
353
    const char *pszMetadata)
354
{
355
    return GDALAddDerivedBandPixelFuncWithArgs(pszFuncNameIn, pfnNewFunction,
×
356
                                               pszMetadata);
×
357
}
358

359
/************************************************************************/
360
/*                           GetPixelFunction()                         */
361
/************************************************************************/
362

363
/**
364
 * Get a pixel function previously registered using the global
365
 * AddPixelFunction.
366
 *
367
 * @param pszFuncNameIn The name associated with the pixel function.
368
 *
369
 * @return A pointer to a std::pair whose first element is the pixel
370
 *         function pointer and second element is the pixel function
371
 *         metadata string. If no pixel function has been registered
372
 *         for pszFuncNameIn, nullptr will be returned.
373
 */
374
/* static */
375
const std::pair<VRTDerivedRasterBand::PixelFunc, std::string> *
376
VRTDerivedRasterBand::GetPixelFunction(const char *pszFuncNameIn)
2,750✔
377
{
378
    if (pszFuncNameIn == nullptr || pszFuncNameIn[0] == '\0')
2,750✔
379
    {
380
        return nullptr;
×
381
    }
382

383
    const auto &oMapPixelFunction = GetGlobalMapPixelFunction();
2,750✔
384
    const auto oIter = oMapPixelFunction.find(pszFuncNameIn);
2,750✔
385

386
    if (oIter == oMapPixelFunction.end())
2,750✔
387
        return nullptr;
3✔
388

389
    return &(oIter->second);
2,747✔
390
}
391

392
/************************************************************************/
393
/*                        GetPixelFunctionNames()                       */
394
/************************************************************************/
395

396
/**
397
 * Return the list of available pixel function names.
398
 */
399
/* static */
400
std::vector<std::string> VRTDerivedRasterBand::GetPixelFunctionNames()
64✔
401
{
402
    std::vector<std::string> res;
64✔
403
    for (const auto &iter : GetGlobalMapPixelFunction())
2,304✔
404
    {
405
        res.push_back(iter.first);
2,240✔
406
    }
407
    return res;
64✔
408
}
409

410
/************************************************************************/
411
/*                         SetPixelFunctionName()                       */
412
/************************************************************************/
413

414
/**
415
 * Set the pixel function name to be applied to this derived band.  The
416
 * name should match a pixel function registered using AddPixelFunction.
417
 *
418
 * @param pszFuncNameIn Name of pixel function to be applied to this derived
419
 * band.
420
 */
421
void VRTDerivedRasterBand::SetPixelFunctionName(const char *pszFuncNameIn)
1,978✔
422
{
423
    osFuncName = (pszFuncNameIn == nullptr) ? "" : pszFuncNameIn;
1,978✔
424
}
1,978✔
425

426
/************************************************************************/
427
/*                     AddPixelFunctionArgument()                       */
428
/************************************************************************/
429

430
/**
431
 *  Set a pixel function argument to a specified value.
432
 * @param pszArg the argument name
433
 * @param pszValue the argument value
434
 *
435
 * @since 3.12
436
 */
437
void VRTDerivedRasterBand::AddPixelFunctionArgument(const char *pszArg,
2,275✔
438
                                                    const char *pszValue)
439
{
440
    m_poPrivate->m_oFunctionArgs.emplace_back(pszArg, pszValue);
2,275✔
441
}
2,275✔
442

443
/************************************************************************/
444
/*                         SetPixelFunctionLanguage()                   */
445
/************************************************************************/
446

447
/**
448
 * Set the language of the pixel function.
449
 *
450
 * @param pszLanguage Language of the pixel function (only "C" and "Python"
451
 * are supported currently)
452
 * @since GDAL 2.3
453
 */
454
void VRTDerivedRasterBand::SetPixelFunctionLanguage(const char *pszLanguage)
1✔
455
{
456
    m_poPrivate->m_osLanguage = pszLanguage;
1✔
457
}
1✔
458

459
/************************************************************************/
460
/*                 SetSkipNonContributingSources()                      */
461
/************************************************************************/
462

463
/** Whether sources that do not intersect the VRTRasterBand RasterIO() requested
464
 * region should be omitted. By default, data for all sources, including ones
465
 * that do not intersect it, are passed to the pixel function. By setting this
466
 * parameter to true, only sources that intersect the requested region will be
467
 * passed.
468
 *
469
 * @param bSkip whether to skip non-contributing sources
470
 *
471
 * @since 3.12
472
 */
473
void VRTDerivedRasterBand::SetSkipNonContributingSources(bool bSkip)
5✔
474
{
475
    m_poPrivate->m_bSkipNonContributingSources = bSkip;
5✔
476
    m_poPrivate->m_bSkipNonContributingSourcesSpecified = true;
5✔
477
}
5✔
478

479
/************************************************************************/
480
/*                         SetSourceTransferType()                      */
481
/************************************************************************/
482

483
/**
484
 * Set the transfer type to be used to obtain pixel information from
485
 * all of the sources.  If unset, the transfer type used will be the
486
 * same as the derived band data type.  This makes it possible, for
487
 * example, to pass CFloat32 source pixels to the pixel function, even
488
 * if the pixel function generates a raster for a derived band that
489
 * is of type Byte.
490
 *
491
 * @param eDataTypeIn Data type to use to obtain pixel information from
492
 * the sources to be passed to the derived band pixel function.
493
 */
494
void VRTDerivedRasterBand::SetSourceTransferType(GDALDataType eDataTypeIn)
21✔
495
{
496
    eSourceTransferType = eDataTypeIn;
21✔
497
}
21✔
498

499
/************************************************************************/
500
/*                           InitializePython()                         */
501
/************************************************************************/
502

503
bool VRTDerivedRasterBand::InitializePython()
384✔
504
{
505
    if (m_poPrivate->m_bPythonInitializationDone)
384✔
506
        return m_poPrivate->m_bPythonInitializationSuccess;
321✔
507

508
    m_poPrivate->m_bPythonInitializationDone = true;
63✔
509
    m_poPrivate->m_bPythonInitializationSuccess = false;
63✔
510

511
    const size_t nIdxDot = osFuncName.rfind(".");
63✔
512
    CPLString osPythonModule;
126✔
513
    CPLString osPythonFunction;
126✔
514
    if (nIdxDot != std::string::npos)
63✔
515
    {
516
        osPythonModule = osFuncName.substr(0, nIdxDot);
29✔
517
        osPythonFunction = osFuncName.substr(nIdxDot + 1);
29✔
518
    }
519
    else
520
    {
521
        osPythonFunction = osFuncName;
34✔
522
    }
523

524
#ifndef GDAL_VRT_DISABLE_PYTHON
525
    const char *pszPythonEnabled =
526
        CPLGetConfigOption("GDAL_VRT_ENABLE_PYTHON", nullptr);
63✔
527
#else
528
    const char *pszPythonEnabled = "NO";
529
#endif
530
    const CPLString osPythonEnabled(
531
        pszPythonEnabled ? pszPythonEnabled : GDAL_VRT_ENABLE_PYTHON_DEFAULT);
126✔
532

533
    if (EQUAL(osPythonEnabled, "TRUSTED_MODULES"))
63✔
534
    {
535
        bool bIsTrustedModule = false;
12✔
536
        const CPLString osVRTTrustedModules(
537
            CPLGetConfigOption("GDAL_VRT_PYTHON_TRUSTED_MODULES", ""));
12✔
538
        if (!osPythonModule.empty())
12✔
539
        {
540
            char **papszTrustedModules =
541
                CSLTokenizeString2(osVRTTrustedModules, ",", 0);
10✔
542
            for (char **papszIter = papszTrustedModules;
23✔
543
                 !bIsTrustedModule && papszIter && *papszIter; ++papszIter)
23✔
544
            {
545
                const char *pszIterModule = *papszIter;
13✔
546
                size_t nIterModuleLen = strlen(pszIterModule);
13✔
547
                if (nIterModuleLen > 2 &&
13✔
548
                    strncmp(pszIterModule + nIterModuleLen - 2, ".*", 2) == 0)
12✔
549
                {
550
                    bIsTrustedModule =
2✔
551
                        (strncmp(osPythonModule, pszIterModule,
2✔
552
                                 nIterModuleLen - 2) == 0) &&
3✔
553
                        (osPythonModule.size() == nIterModuleLen - 2 ||
1✔
554
                         (osPythonModule.size() >= nIterModuleLen &&
×
555
                          osPythonModule[nIterModuleLen - 1] == '.'));
×
556
                }
557
                else if (nIterModuleLen >= 1 &&
11✔
558
                         pszIterModule[nIterModuleLen - 1] == '*')
11✔
559
                {
560
                    bIsTrustedModule = (strncmp(osPythonModule, pszIterModule,
4✔
561
                                                nIterModuleLen - 1) == 0);
562
                }
563
                else
564
                {
565
                    bIsTrustedModule =
7✔
566
                        (strcmp(osPythonModule, pszIterModule) == 0);
7✔
567
                }
568
            }
569
            CSLDestroy(papszTrustedModules);
10✔
570
        }
571

572
        if (!bIsTrustedModule)
12✔
573
        {
574
            if (osPythonModule.empty())
7✔
575
            {
576
                CPLError(
2✔
577
                    CE_Failure, CPLE_AppDefined,
578
                    "Python code needs to be executed, but it uses inline code "
579
                    "in the VRT whereas the current policy is to trust only "
580
                    "code from external trusted modules (defined in the "
581
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
582
                    "If you trust the code in %s, you can set the "
583
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
584
                    GetDataset() ? GetDataset()->GetDescription()
2✔
585
                                 : "(unknown VRT)");
586
            }
587
            else if (osVRTTrustedModules.empty())
5✔
588
            {
589
                CPLError(
2✔
590
                    CE_Failure, CPLE_AppDefined,
591
                    "Python code needs to be executed, but it uses code "
592
                    "from module '%s', whereas the current policy is to "
593
                    "trust only code from modules defined in the "
594
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option, "
595
                    "which is currently unset. "
596
                    "If you trust the code in '%s', you can add module '%s' "
597
                    "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
598
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
599
                    osPythonModule.c_str(),
600
                    GetDataset() ? GetDataset()->GetDescription()
1✔
601
                                 : "(unknown VRT)",
602
                    osPythonModule.c_str());
603
            }
604
            else
605
            {
606
                CPLError(
8✔
607
                    CE_Failure, CPLE_AppDefined,
608
                    "Python code needs to be executed, but it uses code "
609
                    "from module '%s', whereas the current policy is to "
610
                    "trust only code from modules '%s' (defined in the "
611
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
612
                    "If you trust the code in '%s', you can add module '%s' "
613
                    "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
614
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
615
                    osPythonModule.c_str(), osVRTTrustedModules.c_str(),
616
                    GetDataset() ? GetDataset()->GetDescription()
4✔
617
                                 : "(unknown VRT)",
618
                    osPythonModule.c_str());
619
            }
620
            return false;
7✔
621
        }
622
    }
623

624
#ifdef disabled_because_this_is_probably_broken_by_design
625
    // See https://lwn.net/Articles/574215/
626
    // and http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
627
    else if (EQUAL(osPythonEnabled, "IF_SAFE"))
628
    {
629
        bool bSafe = true;
630
        // If the function comes from another module, then we don't know
631
        if (!osPythonModule.empty())
632
        {
633
            CPLDebug("VRT", "Python function is from another module");
634
            bSafe = false;
635
        }
636

637
        CPLString osCode(m_poPrivate->m_osCode);
638

639
        // Reject all imports except a few trusted modules
640
        const char *const apszTrustedImports[] = {
641
            "import math",
642
            "from math import",
643
            "import numpy",  // caution: numpy has lots of I/O functions !
644
            "from numpy import",
645
            // TODO: not sure if importing arbitrary stuff from numba is OK
646
            // so let's just restrict to jit.
647
            "from numba import jit",
648

649
            // Not imports but still whitelisted, whereas other __ is banned
650
            "__init__",
651
            "__call__",
652
        };
653
        for (size_t i = 0; i < CPL_ARRAYSIZE(apszTrustedImports); ++i)
654
        {
655
            osCode.replaceAll(CPLString(apszTrustedImports[i]), "");
656
        }
657

658
        // Some dangerous built-in functions or numpy functions
659
        const char *const apszUntrusted[] = {
660
            "import",  // and __import__
661
            "eval",       "compile", "open",
662
            "load",        // reload, numpy.load
663
            "file",        // and exec_file, numpy.fromfile, numpy.tofile
664
            "input",       // and raw_input
665
            "save",        // numpy.save
666
            "memmap",      // numpy.memmap
667
            "DataSource",  // numpy.DataSource
668
            "genfromtxt",  // numpy.genfromtxt
669
            "getattr",
670
            "ctypeslib",  // numpy.ctypeslib
671
            "testing",    // numpy.testing
672
            "dump",       // numpy.ndarray.dump
673
            "fromregex",  // numpy.fromregex
674
            "__"};
675
        for (size_t i = 0; i < CPL_ARRAYSIZE(apszUntrusted); ++i)
676
        {
677
            if (osCode.find(apszUntrusted[i]) != std::string::npos)
678
            {
679
                CPLDebug("VRT", "Found '%s' word in Python code",
680
                         apszUntrusted[i]);
681
                bSafe = false;
682
            }
683
        }
684

685
        if (!bSafe)
686
        {
687
            CPLError(CE_Failure, CPLE_AppDefined,
688
                     "Python code needs to be executed, but we cannot verify "
689
                     "if it is safe, so this is disabled by default. "
690
                     "If you trust the code in %s, you can set the "
691
                     "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
692
                     GetDataset() ? GetDataset()->GetDescription()
693
                                  : "(unknown VRT)");
694
            return false;
695
        }
696
    }
697
#endif  // disabled_because_this_is_probably_broken_by_design
698

699
    else if (!EQUAL(osPythonEnabled, "YES") && !EQUAL(osPythonEnabled, "ON") &&
52✔
700
             !EQUAL(osPythonEnabled, "TRUE"))
1✔
701
    {
702
        if (pszPythonEnabled == nullptr)
1✔
703
        {
704
            // Note: this is dead code with our current default policy
705
            // GDAL_VRT_ENABLE_PYTHON == "TRUSTED_MODULES"
706
            CPLError(CE_Failure, CPLE_AppDefined,
×
707
                     "Python code needs to be executed, but this is "
708
                     "disabled by default. If you trust the code in %s, "
709
                     "you can set the GDAL_VRT_ENABLE_PYTHON configuration "
710
                     "option to YES.",
711
                     GetDataset() ? GetDataset()->GetDescription()
×
712
                                  : "(unknown VRT)");
713
        }
714
        else
715
        {
716
            CPLError(
1✔
717
                CE_Failure, CPLE_AppDefined,
718
                "Python code in %s needs to be executed, but this has been "
719
                "explicitly disabled.",
720
                GetDataset() ? GetDataset()->GetDescription()
1✔
721
                             : "(unknown VRT)");
722
        }
723
        return false;
1✔
724
    }
725

726
    if (!GDALPythonInitialize())
55✔
727
        return false;
2✔
728

729
    // Whether we should just use our own global mutex, in addition to Python
730
    // GIL locking.
731
    m_poPrivate->m_bExclusiveLock =
106✔
732
        CPLTestBool(CPLGetConfigOption("GDAL_VRT_PYTHON_EXCLUSIVE_LOCK", "NO"));
53✔
733

734
    // numba jit'ification doesn't seem to be thread-safe, so force use of
735
    // lock now and at first execution of function. Later executions seem to
736
    // be thread-safe. This problem doesn't seem to appear for code in
737
    // regular files
738
    const bool bUseExclusiveLock =
739
        m_poPrivate->m_bExclusiveLock ||
106✔
740
        m_poPrivate->m_osCode.find("@jit") != std::string::npos;
53✔
741
    GIL_Holder oHolder(bUseExclusiveLock);
106✔
742

743
    // As we don't want to depend on numpy C API/ABI, we use a trick to build
744
    // a numpy array object. We define a Python function to which we pass a
745
    // Python buffer object.
746

747
    // We need to build a unique module name, otherwise this will crash in
748
    // multithreaded use cases.
749
    CPLString osModuleName(CPLSPrintf("gdal_vrt_module_%p", this));
106✔
750
    PyObject *poCompiledString = Py_CompileString(
106✔
751
        ("import numpy\n"
752
         "def GDALCreateNumpyArray(buffer, dtype, height, width):\n"
753
         "    return numpy.frombuffer(buffer, str(dtype.decode('ascii')))."
754
         "reshape([height, width])\n"
755
         "\n" +
53✔
756
         m_poPrivate->m_osCode)
53✔
757
            .c_str(),
758
        osModuleName, Py_file_input);
759
    if (poCompiledString == nullptr || PyErr_Occurred())
53✔
760
    {
761
        CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
1✔
762
                 GetPyExceptionString().c_str());
2✔
763
        return false;
1✔
764
    }
765
    PyObject *poModule =
766
        PyImport_ExecCodeModule(osModuleName, poCompiledString);
52✔
767
    Py_DecRef(poCompiledString);
52✔
768

769
    if (poModule == nullptr || PyErr_Occurred())
52✔
770
    {
771
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
1✔
772
                 GetPyExceptionString().c_str());
2✔
773
        return false;
1✔
774
    }
775

776
    // Fetch user computation function
777
    if (!osPythonModule.empty())
51✔
778
    {
779
        PyObject *poUserModule = PyImport_ImportModule(osPythonModule);
24✔
780
        if (poUserModule == nullptr || PyErr_Occurred())
24✔
781
        {
782
            CPLString osException = GetPyExceptionString();
1✔
783
            if (!osException.empty() && osException.back() == '\n')
1✔
784
            {
785
                osException.pop_back();
1✔
786
            }
787
            if (osException.find("ModuleNotFoundError") == 0)
1✔
788
            {
789
                osException += ". You may need to define PYTHONPATH";
1✔
790
            }
791
            CPLError(CE_Failure, CPLE_AppDefined, "%s", osException.c_str());
1✔
792
            Py_DecRef(poModule);
1✔
793
            return false;
1✔
794
        }
795
        m_poPrivate->m_poUserFunction =
46✔
796
            PyObject_GetAttrString(poUserModule, osPythonFunction);
23✔
797
        Py_DecRef(poUserModule);
23✔
798
    }
799
    else
800
    {
801
        m_poPrivate->m_poUserFunction =
54✔
802
            PyObject_GetAttrString(poModule, osPythonFunction);
27✔
803
    }
804
    if (m_poPrivate->m_poUserFunction == nullptr || PyErr_Occurred())
50✔
805
    {
806
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
1✔
807
                 GetPyExceptionString().c_str());
2✔
808
        Py_DecRef(poModule);
1✔
809
        return false;
1✔
810
    }
811
    if (!PyCallable_Check(m_poPrivate->m_poUserFunction))
49✔
812
    {
813
        CPLError(CE_Failure, CPLE_AppDefined, "Object '%s' is not callable",
1✔
814
                 osPythonFunction.c_str());
815
        Py_DecRef(poModule);
1✔
816
        return false;
1✔
817
    }
818

819
    // Fetch our GDALCreateNumpyArray python function
820
    m_poPrivate->m_poGDALCreateNumpyArray =
96✔
821
        PyObject_GetAttrString(poModule, "GDALCreateNumpyArray");
48✔
822
    if (m_poPrivate->m_poGDALCreateNumpyArray == nullptr || PyErr_Occurred())
48✔
823
    {
824
        // Shouldn't happen normally...
825
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
×
826
                 GetPyExceptionString().c_str());
×
827
        Py_DecRef(poModule);
×
828
        return false;
×
829
    }
830
    Py_DecRef(poModule);
48✔
831

832
    m_poPrivate->m_bPythonInitializationSuccess = true;
48✔
833
    return true;
48✔
834
}
835

836
CPLErr VRTDerivedRasterBand::GetPixelFunctionArguments(
2,677✔
837
    const CPLString &osMetadata,
838
    const std::vector<int> &anMapBufferIdxToSourceIdx, int nXOff, int nYOff,
839
    std::vector<std::pair<CPLString, CPLString>> &oAdditionalArgs)
840
{
841

842
    auto poArgs = CPLXMLTreeCloser(CPLParseXMLString(osMetadata));
5,354✔
843
    if (poArgs != nullptr && poArgs->eType == CXT_Element &&
5,354✔
844
        !strcmp(poArgs->pszValue, "PixelFunctionArgumentsList"))
2,677✔
845
    {
846
        for (CPLXMLNode *psIter = poArgs->psChild; psIter != nullptr;
12,287✔
847
             psIter = psIter->psNext)
9,610✔
848
        {
849
            if (psIter->eType == CXT_Element &&
9,611✔
850
                !strcmp(psIter->pszValue, "Argument"))
9,611✔
851
            {
852
                CPLString osName, osType, osValue;
9,611✔
853
                auto pszName = CPLGetXMLValue(psIter, "name", nullptr);
9,611✔
854
                if (pszName != nullptr)
9,611✔
855
                    osName = pszName;
5,486✔
856
                auto pszType = CPLGetXMLValue(psIter, "type", nullptr);
9,611✔
857
                if (pszType != nullptr)
9,611✔
858
                    osType = pszType;
9,611✔
859
                auto pszValue = CPLGetXMLValue(psIter, "value", nullptr);
9,611✔
860
                if (pszValue != nullptr)
9,611✔
861
                    osValue = pszValue;
4,492✔
862
                if (osType == "constant" && osValue != "" && osName != "")
9,611✔
863
                    oAdditionalArgs.push_back(
1✔
864
                        std::pair<CPLString, CPLString>(osName, osValue));
2✔
865
                if (osType == "builtin")
9,611✔
866
                {
867
                    const CPLString &osArgName = osValue;
4,125✔
868
                    CPLString osVal;
4,125✔
869
                    double dfVal = 0;
4,125✔
870

871
                    int success(FALSE);
4,125✔
872
                    if (osArgName == "NoData")
4,125✔
873
                        dfVal = this->GetNoDataValue(&success);
2,672✔
874
                    else if (osArgName == "scale")
1,453✔
875
                        dfVal = this->GetScale(&success);
3✔
876
                    else if (osArgName == "offset")
1,450✔
877
                        dfVal = this->GetOffset(&success);
2✔
878
                    else if (osArgName == "xoff")
1,448✔
879
                    {
880
                        dfVal = static_cast<double>(nXOff);
362✔
881
                        success = true;
362✔
882
                    }
883
                    else if (osArgName == "yoff")
1,086✔
884
                    {
885
                        dfVal = static_cast<double>(nYOff);
362✔
886
                        success = true;
362✔
887
                    }
888
                    else if (osArgName == "geotransform")
724✔
889
                    {
890
                        GDALGeoTransform gt;
362✔
891
                        if (GetDataset()->GetGeoTransform(gt) != CE_None)
362✔
892
                        {
893
                            // Do not fail here because the argument is most
894
                            // likely not needed by the pixel function. If it
895
                            // is needed, the pixel function can emit the error.
896
                            continue;
139✔
897
                        }
898
                        osVal = CPLSPrintf(
899
                            "%.17g,%.17g,%.17g,%.17g,%.17g,%.17g", gt[0], gt[1],
446✔
900
                            gt[2], gt[3], gt[4], gt[5]);
223✔
901
                        success = true;
223✔
902
                    }
903
                    else if (osArgName == "source_names")
362✔
904
                    {
905
                        for (size_t iBuffer = 0;
957✔
906
                             iBuffer < anMapBufferIdxToSourceIdx.size();
957✔
907
                             iBuffer++)
908
                        {
909
                            int iSource = anMapBufferIdxToSourceIdx[iBuffer];
595✔
910
                            const VRTSource *poSource = papoSources[iSource];
595✔
911

912
                            if (iBuffer > 0)
595✔
913
                            {
914
                                osVal += "|";
240✔
915
                            }
916

917
                            const auto &osSourceName = poSource->GetName();
595✔
918
                            if (osSourceName.empty())
595✔
919
                            {
920
                                osVal += "B" + std::to_string(iBuffer + 1);
42✔
921
                            }
922
                            else
923
                            {
924
                                osVal += osSourceName;
553✔
925
                            }
926
                        }
927

928
                        success = true;
362✔
929
                    }
930
                    else
931
                    {
932
                        CPLError(
×
933
                            CE_Failure, CPLE_NotSupported,
934
                            "PixelFunction builtin argument %s not supported",
935
                            osArgName.c_str());
936
                        return CE_Failure;
×
937
                    }
938
                    if (!success)
3,986✔
939
                    {
940
                        if (CPLTestBool(
2,573✔
941
                                CPLGetXMLValue(psIter, "optional", "false")))
942
                            continue;
2,572✔
943

944
                        CPLError(CE_Failure, CPLE_AppDefined,
1✔
945
                                 "Raster has no %s", osValue.c_str());
946
                        return CE_Failure;
1✔
947
                    }
948

949
                    if (osVal.empty())
1,413✔
950
                    {
951
                        osVal = CPLSPrintf("%.17g", dfVal);
835✔
952
                    }
953

954
                    oAdditionalArgs.push_back(
1,413✔
955
                        std::pair<CPLString, CPLString>(osArgName, osVal));
2,826✔
956
                    CPLDebug("VRT",
1,413✔
957
                             "Added builtin pixel function argument %s = %s",
958
                             osArgName.c_str(), osVal.c_str());
959
                }
960
            }
961
        }
962
    }
963

964
    return CE_None;
2,676✔
965
}
966

967
/************************************************************************/
968
/*                             IRasterIO()                              */
969
/************************************************************************/
970

971
/**
972
 * Read/write a region of image data for this band.
973
 *
974
 * Each of the sources for this derived band will be read and passed to
975
 * the derived band pixel function.  The pixel function is responsible
976
 * for applying whatever algorithm is necessary to generate this band's
977
 * pixels from the sources.
978
 *
979
 * The sources will be read using the transfer type specified for sources
980
 * using SetSourceTransferType().  If no transfer type has been set for
981
 * this derived band, the band's data type will be used as the transfer type.
982
 *
983
 * @see gdalrasterband
984
 *
985
 * @param eRWFlag Either GF_Read to read a region of data, or GT_Write to
986
 * write a region of data.
987
 *
988
 * @param nXOff The pixel offset to the top left corner of the region
989
 * of the band to be accessed.  This would be zero to start from the left side.
990
 *
991
 * @param nYOff The line offset to the top left corner of the region
992
 * of the band to be accessed.  This would be zero to start from the top.
993
 *
994
 * @param nXSize The width of the region of the band to be accessed in pixels.
995
 *
996
 * @param nYSize The height of the region of the band to be accessed in lines.
997
 *
998
 * @param pData The buffer into which the data should be read, or from which
999
 * it should be written.  This buffer must contain at least nBufXSize *
1000
 * nBufYSize words of type eBufType.  It is organized in left to right,
1001
 * top to bottom pixel order.  Spacing is controlled by the nPixelSpace,
1002
 * and nLineSpace parameters.
1003
 *
1004
 * @param nBufXSize The width of the buffer image into which the desired
1005
 * region is to be read, or from which it is to be written.
1006
 *
1007
 * @param nBufYSize The height of the buffer image into which the desired
1008
 * region is to be read, or from which it is to be written.
1009
 *
1010
 * @param eBufType The type of the pixel values in the pData data buffer.  The
1011
 * pixel values will automatically be translated to/from the GDALRasterBand
1012
 * data type as needed.
1013
 *
1014
 * @param nPixelSpace The byte offset from the start of one pixel value in
1015
 * pData to the start of the next pixel value within a scanline.  If defaulted
1016
 * (0) the size of the datatype eBufType is used.
1017
 *
1018
 * @param nLineSpace The byte offset from the start of one scanline in
1019
 * pData to the start of the next.  If defaulted the size of the datatype
1020
 * eBufType * nBufXSize is used.
1021
 *
1022
 * @return CE_Failure if the access fails, otherwise CE_None.
1023
 */
1024
CPLErr VRTDerivedRasterBand::IRasterIO(
4,120✔
1025
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
1026
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1027
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
1028
{
1029
    if (eRWFlag == GF_Write)
4,120✔
1030
    {
1031
        CPLError(CE_Failure, CPLE_AppDefined,
1✔
1032
                 "Writing through VRTSourcedRasterBand is not supported.");
1033
        return CE_Failure;
1✔
1034
    }
1035

1036
    if constexpr (sizeof(GSpacing) > sizeof(int))
1037
    {
1038
        if (nLineSpace > INT_MAX)
4,119✔
1039
        {
1040
            if (nBufYSize == 1)
×
1041
            {
1042
                nLineSpace = 0;
×
1043
            }
1044
            else
1045
            {
1046
                CPLError(CE_Failure, CPLE_NotSupported,
×
1047
                         "VRTDerivedRasterBand::IRasterIO(): nLineSpace > "
1048
                         "INT_MAX not supported");
1049
                return CE_Failure;
×
1050
            }
1051
        }
1052
    }
1053

1054
    const int nBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
4,119✔
1055
    GDALDataType eSrcType = eSourceTransferType;
4,119✔
1056
    if (eSrcType == GDT_Unknown || eSrcType >= GDT_TypeCount)
4,119✔
1057
    {
1058
        // Check the largest data type for all sources
1059
        GDALDataType eAllSrcType = GDT_Unknown;
3,221✔
1060
        for (int iSource = 0; iSource < nSources; iSource++)
107,160✔
1061
        {
1062
            if (papoSources[iSource]->GetType() ==
103,956✔
1063
                VRTSimpleSource::GetTypeStatic())
103,956✔
1064
            {
1065
                const auto poSS =
103,939✔
1066
                    static_cast<VRTSimpleSource *>(papoSources[iSource]);
103,939✔
1067
                auto l_poBand = poSS->GetRasterBand();
103,939✔
1068
                if (l_poBand)
103,939✔
1069
                {
1070
                    eAllSrcType = GDALDataTypeUnion(
103,939✔
1071
                        eAllSrcType, l_poBand->GetRasterDataType());
1072
                }
1073
                else
1074
                {
1075
                    eAllSrcType = GDT_Unknown;
×
1076
                    break;
×
1077
                }
1078
            }
1079
            else
1080
            {
1081
                eAllSrcType = GDT_Unknown;
17✔
1082
                break;
17✔
1083
            }
1084
        }
1085

1086
        if (eAllSrcType != GDT_Unknown)
3,221✔
1087
            eSrcType = eAllSrcType;
2,823✔
1088
        else
1089
            eSrcType = eBufType;
398✔
1090
    }
1091
    const int nSrcTypeSize = GDALGetDataTypeSizeBytes(eSrcType);
4,119✔
1092

1093
    // If acquiring the region of interest in a single time is going
1094
    // to consume too much RAM, split in halves, and that recursively
1095
    // until we get below m_nAllowedRAMUsage.
1096
    if (m_poPrivate->m_nAllowedRAMUsage > 0 && nSources > 0 &&
4,119✔
1097
        nSrcTypeSize > 0 && nBufXSize == nXSize && nBufYSize == nYSize &&
3,735✔
1098
        static_cast<GIntBig>(nBufXSize) * nBufYSize >
3,733✔
1099
            m_poPrivate->m_nAllowedRAMUsage / (nSources * nSrcTypeSize))
3,733✔
1100
    {
1101
        CPLErr eErr = SplitRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
999✔
1102
                                    pData, nBufXSize, nBufYSize, eBufType,
1103
                                    nPixelSpace, nLineSpace, psExtraArg);
1104
        if (eErr != CE_Warning)
999✔
1105
            return eErr;
999✔
1106
    }
1107

1108
    /* -------------------------------------------------------------------- */
1109
    /*      Do we have overviews that would be appropriate to satisfy       */
1110
    /*      this request?                                                   */
1111
    /* -------------------------------------------------------------------- */
1112
    if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
3,120✔
1113
    {
1114
        if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
×
1115
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
1116
                             nLineSpace, psExtraArg) == CE_None)
×
1117
            return CE_None;
×
1118
    }
1119

1120
    /* ---- Get pixel function for band ---- */
1121
    const std::pair<PixelFunc, std::string> *poPixelFunc = nullptr;
3,120✔
1122
    std::vector<std::pair<CPLString, CPLString>> oAdditionalArgs;
6,240✔
1123

1124
    if (EQUAL(m_poPrivate->m_osLanguage, "C"))
3,120✔
1125
    {
1126
        poPixelFunc =
1127
            VRTDerivedRasterBand::GetPixelFunction(osFuncName.c_str());
2,726✔
1128
        if (poPixelFunc == nullptr)
2,726✔
1129
        {
1130
            CPLError(CE_Failure, CPLE_IllegalArg,
1✔
1131
                     "VRTDerivedRasterBand::IRasterIO:"
1132
                     "Derived band pixel function '%s' not registered.",
1133
                     osFuncName.c_str());
1134
            return CE_Failure;
1✔
1135
        }
1136
    }
1137

1138
    /* TODO: It would be nice to use a MallocBlock function for each
1139
       individual buffer that would recycle blocks of memory from a
1140
       cache by reassigning blocks that are nearly the same size.
1141
       A corresponding FreeBlock might only truly free if the total size
1142
       of freed blocks gets to be too great of a percentage of the size
1143
       of the allocated blocks. */
1144

1145
    // Get buffers for each source.
1146
    const int nBufferRadius = m_poPrivate->m_nBufferRadius;
3,119✔
1147
    if (nBufferRadius > (INT_MAX - nBufXSize) / 2 ||
3,119✔
1148
        nBufferRadius > (INT_MAX - nBufYSize) / 2)
3,119✔
1149
    {
1150
        CPLError(CE_Failure, CPLE_AppDefined,
×
1151
                 "Integer overflow: "
1152
                 "nBufferRadius > (INT_MAX - nBufXSize) / 2 || "
1153
                 "nBufferRadius > (INT_MAX - nBufYSize) / 2)");
1154
        return CE_Failure;
×
1155
    }
1156
    const int nExtBufXSize = nBufXSize + 2 * nBufferRadius;
3,119✔
1157
    const int nExtBufYSize = nBufYSize + 2 * nBufferRadius;
3,119✔
1158
    int nBufferCount = 0;
3,119✔
1159

1160
    std::vector<std::unique_ptr<void, VSIFreeReleaser>> apBuffers(nSources);
6,238✔
1161
    std::vector<int> anMapBufferIdxToSourceIdx(nSources);
6,238✔
1162
    bool bSkipOutputBufferInitialization = nSources > 0;
3,119✔
1163
    for (int iSource = 0; iSource < nSources; iSource++)
106,812✔
1164
    {
1165
        if (m_poPrivate->m_bSkipNonContributingSources &&
103,707✔
1166
            papoSources[iSource]->IsSimpleSource())
14✔
1167
        {
1168
            bool bError = false;
14✔
1169
            double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
1170
            int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1171
            int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1172
            auto poSource =
14✔
1173
                static_cast<VRTSimpleSource *>(papoSources[iSource]);
14✔
1174
            if (!poSource->GetSrcDstWindow(
14✔
1175
                    nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1176
                    &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1177
                    &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1178
                    &nOutXSize, &nOutYSize, bError))
1179
            {
1180
                if (bError)
4✔
1181
                {
1182
                    return CE_Failure;
×
1183
                }
1184

1185
                // Skip non contributing source
1186
                bSkipOutputBufferInitialization = false;
4✔
1187
                continue;
4✔
1188
            }
1189
        }
1190

1191
        anMapBufferIdxToSourceIdx[nBufferCount] = iSource;
103,689✔
1192
        apBuffers[nBufferCount].reset(
103,689✔
1193
            VSI_MALLOC3_VERBOSE(nSrcTypeSize, nExtBufXSize, nExtBufYSize));
1194
        if (apBuffers[nBufferCount] == nullptr)
103,689✔
1195
        {
1196
            return CE_Failure;
×
1197
        }
1198

1199
        bool bBufferInit = true;
103,689✔
1200
        if (papoSources[iSource]->IsSimpleSource())
103,689✔
1201
        {
1202
            const auto poSS =
103,688✔
1203
                static_cast<VRTSimpleSource *>(papoSources[iSource]);
103,688✔
1204
            auto l_poBand = poSS->GetRasterBand();
103,688✔
1205
            if (l_poBand != nullptr && poSS->m_dfSrcXOff == 0.0 &&
103,688✔
1206
                poSS->m_dfSrcYOff == 0.0 &&
873✔
1207
                poSS->m_dfSrcXOff + poSS->m_dfSrcXSize ==
1,746✔
1208
                    l_poBand->GetXSize() &&
873✔
1209
                poSS->m_dfSrcYOff + poSS->m_dfSrcYSize ==
1,710✔
1210
                    l_poBand->GetYSize() &&
855✔
1211
                poSS->m_dfDstXOff == 0.0 && poSS->m_dfDstYOff == 0.0 &&
855✔
1212
                poSS->m_dfDstXOff + poSS->m_dfDstXSize == nRasterXSize &&
208,225✔
1213
                poSS->m_dfDstYOff + poSS->m_dfDstYSize == nRasterYSize)
849✔
1214
            {
1215
                if (papoSources[iSource]->GetType() ==
849✔
1216
                    VRTSimpleSource::GetTypeStatic())
849✔
1217
                    bBufferInit = false;
824✔
1218
            }
1219
            else
1220
            {
1221
                bSkipOutputBufferInitialization = false;
102,839✔
1222
            }
1223
        }
1224
        else
1225
        {
1226
            bSkipOutputBufferInitialization = false;
1✔
1227
        }
1228
        if (bBufferInit)
103,689✔
1229
        {
1230
            /* ------------------------------------------------------------ */
1231
            /* #4045: Initialize the newly allocated buffers before handing */
1232
            /* them off to the sources. These buffers are packed, so we     */
1233
            /* don't need any special line-by-line handling when a nonzero  */
1234
            /* nodata value is set.                                         */
1235
            /* ------------------------------------------------------------ */
1236
            if (!m_bNoDataValueSet || m_dfNoDataValue == 0)
102,865✔
1237
            {
1238
                memset(apBuffers[nBufferCount].get(), 0,
102,648✔
1239
                       static_cast<size_t>(nSrcTypeSize) * nExtBufXSize *
102,648✔
1240
                           nExtBufYSize);
102,648✔
1241
            }
1242
            else
1243
            {
1244
                GDALCopyWords64(
434✔
1245
                    &m_dfNoDataValue, GDT_Float64, 0,
217✔
1246
                    static_cast<GByte *>(apBuffers[nBufferCount].get()),
217✔
1247
                    eSrcType, nSrcTypeSize,
1248
                    static_cast<GPtrDiff_t>(nExtBufXSize) * nExtBufYSize);
217✔
1249
            }
1250
        }
1251

1252
        ++nBufferCount;
103,689✔
1253
    }
1254

1255
    /* -------------------------------------------------------------------- */
1256
    /*      Initialize the buffer to some background value. Use the         */
1257
    /*      nodata value if available.                                      */
1258
    /* -------------------------------------------------------------------- */
1259
    if (bSkipOutputBufferInitialization)
3,119✔
1260
    {
1261
        // Do nothing
1262
    }
1263
    else if (nPixelSpace == nBufTypeSize &&
2,562✔
1264
             (!m_bNoDataValueSet || m_dfNoDataValue == 0))
2,544✔
1265
    {
1266
        memset(pData, 0,
2,467✔
1267
               static_cast<size_t>(nBufXSize) * nBufYSize * nBufTypeSize);
2,467✔
1268
    }
1269
    else if (m_bNoDataValueSet)
95✔
1270
    {
1271
        double dfWriteValue = m_dfNoDataValue;
77✔
1272

1273
        for (int iLine = 0; iLine < nBufYSize; iLine++)
219✔
1274
        {
1275
            GDALCopyWords64(&dfWriteValue, GDT_Float64, 0,
142✔
1276
                            static_cast<GByte *>(pData) + nLineSpace * iLine,
142✔
1277
                            eBufType, static_cast<int>(nPixelSpace), nBufXSize);
1278
        }
1279
    }
1280

1281
    // No contributing sources and SkipNonContributingSources mode ?
1282
    // Do not call the pixel function and just return the 0/nodata initialized
1283
    // output buffer.
1284
    if (nBufferCount == 0 && m_poPrivate->m_bSkipNonContributingSources)
3,119✔
1285
    {
1286
        return CE_None;
1✔
1287
    }
1288

1289
    GDALRasterIOExtraArg sExtraArg;
1290
    GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
3,118✔
1291

1292
    int nXShiftInBuffer = 0;
3,118✔
1293
    int nYShiftInBuffer = 0;
3,118✔
1294
    int nExtBufXSizeReq = nExtBufXSize;
3,118✔
1295
    int nExtBufYSizeReq = nExtBufYSize;
3,118✔
1296

1297
    int nXOffExt = nXOff;
3,118✔
1298
    int nYOffExt = nYOff;
3,118✔
1299
    int nXSizeExt = nXSize;
3,118✔
1300
    int nYSizeExt = nYSize;
3,118✔
1301

1302
    if (nBufferRadius)
3,118✔
1303
    {
1304
        double dfXRatio = static_cast<double>(nXSize) / nBufXSize;
9✔
1305
        double dfYRatio = static_cast<double>(nYSize) / nBufYSize;
9✔
1306

1307
        if (!sExtraArg.bFloatingPointWindowValidity)
9✔
1308
        {
1309
            sExtraArg.dfXOff = nXOff;
9✔
1310
            sExtraArg.dfYOff = nYOff;
9✔
1311
            sExtraArg.dfXSize = nXSize;
9✔
1312
            sExtraArg.dfYSize = nYSize;
9✔
1313
        }
1314

1315
        sExtraArg.dfXOff -= dfXRatio * nBufferRadius;
9✔
1316
        sExtraArg.dfYOff -= dfYRatio * nBufferRadius;
9✔
1317
        sExtraArg.dfXSize += 2 * dfXRatio * nBufferRadius;
9✔
1318
        sExtraArg.dfYSize += 2 * dfYRatio * nBufferRadius;
9✔
1319
        if (sExtraArg.dfXOff < 0)
9✔
1320
        {
1321
            nXShiftInBuffer = -static_cast<int>(sExtraArg.dfXOff / dfXRatio);
9✔
1322
            nExtBufXSizeReq -= nXShiftInBuffer;
9✔
1323
            sExtraArg.dfXSize += sExtraArg.dfXOff;
9✔
1324
            sExtraArg.dfXOff = 0;
9✔
1325
        }
1326
        if (sExtraArg.dfYOff < 0)
9✔
1327
        {
1328
            nYShiftInBuffer = -static_cast<int>(sExtraArg.dfYOff / dfYRatio);
9✔
1329
            nExtBufYSizeReq -= nYShiftInBuffer;
9✔
1330
            sExtraArg.dfYSize += sExtraArg.dfYOff;
9✔
1331
            sExtraArg.dfYOff = 0;
9✔
1332
        }
1333
        if (sExtraArg.dfXOff + sExtraArg.dfXSize > nRasterXSize)
9✔
1334
        {
1335
            nExtBufXSizeReq -= static_cast<int>(
9✔
1336
                (sExtraArg.dfXOff + sExtraArg.dfXSize - nRasterXSize) /
9✔
1337
                dfXRatio);
1338
            sExtraArg.dfXSize = nRasterXSize - sExtraArg.dfXOff;
9✔
1339
        }
1340
        if (sExtraArg.dfYOff + sExtraArg.dfYSize > nRasterYSize)
9✔
1341
        {
1342
            nExtBufYSizeReq -= static_cast<int>(
9✔
1343
                (sExtraArg.dfYOff + sExtraArg.dfYSize - nRasterYSize) /
9✔
1344
                dfYRatio);
1345
            sExtraArg.dfYSize = nRasterYSize - sExtraArg.dfYOff;
9✔
1346
        }
1347

1348
        nXOffExt = static_cast<int>(sExtraArg.dfXOff);
9✔
1349
        nYOffExt = static_cast<int>(sExtraArg.dfYOff);
9✔
1350
        nXSizeExt = std::min(static_cast<int>(sExtraArg.dfXSize + 0.5),
18✔
1351
                             nRasterXSize - nXOffExt);
9✔
1352
        nYSizeExt = std::min(static_cast<int>(sExtraArg.dfYSize + 0.5),
18✔
1353
                             nRasterYSize - nYOffExt);
9✔
1354
    }
1355

1356
    // Load values for sources into packed buffers.
1357
    CPLErr eErr = CE_None;
3,118✔
1358
    VRTSource::WorkingState oWorkingState;
6,236✔
1359
    for (int iBuffer = 0; iBuffer < nBufferCount && eErr == CE_None; iBuffer++)
106,807✔
1360
    {
1361
        const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
103,689✔
1362
        GByte *pabyBuffer = static_cast<GByte *>(apBuffers[iBuffer].get());
103,689✔
1363
        eErr = static_cast<VRTSource *>(papoSources[iSource])
103,689✔
1364
                   ->RasterIO(
207,378✔
1365
                       eSrcType, nXOffExt, nYOffExt, nXSizeExt, nYSizeExt,
1366
                       pabyBuffer + (static_cast<size_t>(nYShiftInBuffer) *
103,689✔
1367
                                         nExtBufXSize +
103,689✔
1368
                                     nXShiftInBuffer) *
103,689✔
1369
                                        nSrcTypeSize,
103,689✔
1370
                       nExtBufXSizeReq, nExtBufYSizeReq, eSrcType, nSrcTypeSize,
1371
                       static_cast<GSpacing>(nSrcTypeSize) * nExtBufXSize,
103,689✔
1372
                       &sExtraArg, oWorkingState);
103,689✔
1373

1374
        // Extend first lines
1375
        for (int iY = 0; iY < nYShiftInBuffer; iY++)
103,698✔
1376
        {
1377
            memcpy(pabyBuffer +
9✔
1378
                       static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
9✔
1379
                   pabyBuffer + static_cast<size_t>(nYShiftInBuffer) *
9✔
1380
                                    nExtBufXSize * nSrcTypeSize,
9✔
1381
                   static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
9✔
1382
        }
1383
        // Extend last lines
1384
        for (int iY = nYShiftInBuffer + nExtBufYSizeReq; iY < nExtBufYSize;
103,698✔
1385
             iY++)
1386
        {
1387
            memcpy(pabyBuffer +
9✔
1388
                       static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
9✔
1389
                   pabyBuffer + static_cast<size_t>(nYShiftInBuffer +
9✔
1390
                                                    nExtBufYSizeReq - 1) *
9✔
1391
                                    nExtBufXSize * nSrcTypeSize,
9✔
1392
                   static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
9✔
1393
        }
1394
        // Extend first cols
1395
        if (nXShiftInBuffer)
103,689✔
1396
        {
1397
            for (int iY = 0; iY < nExtBufYSize; iY++)
1,116✔
1398
            {
1399
                for (int iX = 0; iX < nXShiftInBuffer; iX++)
2,214✔
1400
                {
1401
                    memcpy(pabyBuffer +
1,107✔
1402
                               static_cast<size_t>(iY * nExtBufXSize + iX) *
1,107✔
1403
                                   nSrcTypeSize,
1,107✔
1404
                           pabyBuffer +
1,107✔
1405
                               (static_cast<size_t>(iY) * nExtBufXSize +
1,107✔
1406
                                nXShiftInBuffer) *
1,107✔
1407
                                   nSrcTypeSize,
1,107✔
1408
                           nSrcTypeSize);
1409
                }
1410
            }
1411
        }
1412
        // Extent last cols
1413
        if (nXShiftInBuffer + nExtBufXSizeReq < nExtBufXSize)
103,689✔
1414
        {
1415
            for (int iY = 0; iY < nExtBufYSize; iY++)
1,116✔
1416
            {
1417
                for (int iX = nXShiftInBuffer + nExtBufXSizeReq;
1,107✔
1418
                     iX < nExtBufXSize; iX++)
2,214✔
1419
                {
1420
                    memcpy(pabyBuffer +
1,107✔
1421
                               (static_cast<size_t>(iY) * nExtBufXSize + iX) *
1,107✔
1422
                                   nSrcTypeSize,
1,107✔
1423
                           pabyBuffer +
1,107✔
1424
                               (static_cast<size_t>(iY) * nExtBufXSize +
1,107✔
1425
                                nXShiftInBuffer + nExtBufXSizeReq - 1) *
1,107✔
1426
                                   nSrcTypeSize,
1,107✔
1427
                           nSrcTypeSize);
1428
                }
1429
            }
1430
        }
1431
    }
1432

1433
    // Collect any pixel function arguments
1434
    if (poPixelFunc != nullptr && !poPixelFunc->second.empty())
3,118✔
1435
    {
1436
        if (GetPixelFunctionArguments(poPixelFunc->second,
5,354✔
1437
                                      anMapBufferIdxToSourceIdx, nXOff, nYOff,
1438
                                      oAdditionalArgs) != CE_None)
2,677✔
1439
        {
1440
            eErr = CE_Failure;
1✔
1441
        }
1442
    }
1443

1444
    // Apply pixel function.
1445
    if (eErr == CE_None && EQUAL(m_poPrivate->m_osLanguage, "Python"))
3,118✔
1446
    {
1447
        // numpy doesn't have native cint16/cint32/cfloat16
1448
        if (eSrcType == GDT_CInt16 || eSrcType == GDT_CInt32 ||
393✔
1449
            eSrcType == GDT_CFloat16)
1450
        {
1451
            CPLError(CE_Failure, CPLE_AppDefined,
2✔
1452
                     "CInt16/CInt32/CFloat16 data type not supported for "
1453
                     "SourceTransferType");
1454
            return CE_Failure;
24✔
1455
        }
1456
        if (eDataType == GDT_CInt16 || eDataType == GDT_CInt32 ||
391✔
1457
            eDataType == GDT_CFloat16)
387✔
1458
        {
1459
            CPLError(
7✔
1460
                CE_Failure, CPLE_AppDefined,
1461
                "CInt16/CInt32/CFloat16 data type not supported for data type");
1462
            return CE_Failure;
7✔
1463
        }
1464

1465
        if (!InitializePython())
384✔
1466
            return CE_Failure;
15✔
1467

1468
        std::unique_ptr<GByte, VSIFreeReleaser> pabyTmpBuffer;
×
1469
        // Do we need a temporary buffer or can we use directly the output
1470
        // buffer ?
1471
        if (nBufferRadius != 0 || eDataType != eBufType ||
369✔
1472
            nPixelSpace != nBufTypeSize ||
25✔
1473
            nLineSpace != static_cast<GSpacing>(nBufTypeSize) * nBufXSize)
25✔
1474
        {
1475
            pabyTmpBuffer.reset(static_cast<GByte *>(VSI_CALLOC_VERBOSE(
344✔
1476
                static_cast<size_t>(nExtBufXSize) * nExtBufYSize,
1477
                GDALGetDataTypeSizeBytes(eDataType))));
1478
            if (!pabyTmpBuffer)
344✔
1479
                return CE_Failure;
×
1480
        }
1481

1482
        {
1483
            const bool bUseExclusiveLock =
1484
                m_poPrivate->m_bExclusiveLock ||
738✔
1485
                (m_poPrivate->m_bFirstTime &&
417✔
1486
                 m_poPrivate->m_osCode.find("@jit") != std::string::npos);
48✔
1487
            m_poPrivate->m_bFirstTime = false;
369✔
1488
            GIL_Holder oHolder(bUseExclusiveLock);
369✔
1489

1490
            // Prepare target numpy array
1491
            PyObject *poPyDstArray = GDALCreateNumpyArray(
369✔
1492
                m_poPrivate->m_poGDALCreateNumpyArray,
369✔
1493
                pabyTmpBuffer ? pabyTmpBuffer.get() : pData, eDataType,
713✔
1494
                nExtBufYSize, nExtBufXSize);
1495
            if (!poPyDstArray)
369✔
1496
            {
1497
                return CE_Failure;
×
1498
            }
1499

1500
            // Wrap source buffers as input numpy arrays
1501
            PyObject *pyArgInputArray = PyTuple_New(nBufferCount);
369✔
1502
            for (int i = 0; i < nBufferCount; i++)
399✔
1503
            {
1504
                GByte *pabyBuffer = static_cast<GByte *>(apBuffers[i].get());
30✔
1505
                PyObject *poPySrcArray = GDALCreateNumpyArray(
60✔
1506
                    m_poPrivate->m_poGDALCreateNumpyArray, pabyBuffer, eSrcType,
30✔
1507
                    nExtBufYSize, nExtBufXSize);
1508
                CPLAssert(poPySrcArray);
30✔
1509
                PyTuple_SetItem(pyArgInputArray, i, poPySrcArray);
30✔
1510
            }
1511

1512
            // Create arguments
1513
            PyObject *pyArgs = PyTuple_New(10);
369✔
1514
            PyTuple_SetItem(pyArgs, 0, pyArgInputArray);
369✔
1515
            PyTuple_SetItem(pyArgs, 1, poPyDstArray);
369✔
1516
            PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(nXOff));
369✔
1517
            PyTuple_SetItem(pyArgs, 3, PyLong_FromLong(nYOff));
369✔
1518
            PyTuple_SetItem(pyArgs, 4, PyLong_FromLong(nXSize));
369✔
1519
            PyTuple_SetItem(pyArgs, 5, PyLong_FromLong(nYSize));
369✔
1520
            PyTuple_SetItem(pyArgs, 6, PyLong_FromLong(nRasterXSize));
369✔
1521
            PyTuple_SetItem(pyArgs, 7, PyLong_FromLong(nRasterYSize));
369✔
1522
            PyTuple_SetItem(pyArgs, 8, PyLong_FromLong(nBufferRadius));
369✔
1523

1524
            GDALGeoTransform gt;
369✔
1525
            if (GetDataset())
369✔
1526
                GetDataset()->GetGeoTransform(gt);
369✔
1527
            PyObject *pyGT = PyTuple_New(6);
369✔
1528
            for (int i = 0; i < 6; i++)
2,583✔
1529
                PyTuple_SetItem(pyGT, i, PyFloat_FromDouble(gt[i]));
2,214✔
1530
            PyTuple_SetItem(pyArgs, 9, pyGT);
369✔
1531

1532
            // Prepare kwargs
1533
            PyObject *pyKwargs = PyDict_New();
369✔
1534
            for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
379✔
1535
            {
1536
                const char *pszKey =
1537
                    m_poPrivate->m_oFunctionArgs[i].first.c_str();
10✔
1538
                const char *pszValue =
1539
                    m_poPrivate->m_oFunctionArgs[i].second.c_str();
10✔
1540
                PyDict_SetItemString(
10✔
1541
                    pyKwargs, pszKey,
1542
                    PyBytes_FromStringAndSize(pszValue, strlen(pszValue)));
1543
            }
1544

1545
            // Call user function
1546
            PyObject *pRetValue =
1547
                PyObject_Call(m_poPrivate->m_poUserFunction, pyArgs, pyKwargs);
369✔
1548

1549
            Py_DecRef(pyArgs);
369✔
1550
            Py_DecRef(pyKwargs);
369✔
1551

1552
            if (ErrOccurredEmitCPLError())
369✔
1553
            {
1554
                eErr = CE_Failure;
2✔
1555
            }
1556
            if (pRetValue)
369✔
1557
                Py_DecRef(pRetValue);
367✔
1558
        }  // End of GIL section
1559

1560
        if (pabyTmpBuffer)
369✔
1561
        {
1562
            // Copy numpy destination array to user buffer
1563
            for (int iY = 0; iY < nBufYSize; iY++)
41,227✔
1564
            {
1565
                size_t nSrcOffset =
1566
                    (static_cast<size_t>(iY + nBufferRadius) * nExtBufXSize +
40,881✔
1567
                     nBufferRadius) *
40,881✔
1568
                    GDALGetDataTypeSizeBytes(eDataType);
40,881✔
1569
                GDALCopyWords64(pabyTmpBuffer.get() + nSrcOffset, eDataType,
40,875✔
1570
                                GDALGetDataTypeSizeBytes(eDataType),
1571
                                static_cast<GByte *>(pData) + iY * nLineSpace,
40,876✔
1572
                                eBufType, static_cast<int>(nPixelSpace),
1573
                                nBufXSize);
1574
            }
1575
        }
1576
    }
1577
    else if (eErr == CE_None && poPixelFunc != nullptr)
2,725✔
1578
    {
1579
        CPLStringList aosArgs;
2,724✔
1580

1581
        oAdditionalArgs.insert(oAdditionalArgs.end(),
2,724✔
1582
                               m_poPrivate->m_oFunctionArgs.begin(),
2,724✔
1583
                               m_poPrivate->m_oFunctionArgs.end());
5,448✔
1584
        for (const auto &oArg : oAdditionalArgs)
6,126✔
1585
        {
1586
            const char *pszKey = oArg.first.c_str();
3,402✔
1587
            const char *pszValue = oArg.second.c_str();
3,402✔
1588
            aosArgs.SetNameValue(pszKey, pszValue);
3,402✔
1589
        }
1590

1591
        static_assert(sizeof(apBuffers[0]) == sizeof(void *));
1592
        eErr = (poPixelFunc->first)(
2,724✔
1593
            // We cast vector<unique_ptr<void>>.data() as void**. This is OK
1594
            // given above static_assert
1595
            reinterpret_cast<void **>(apBuffers.data()), nBufferCount, pData,
2,724✔
1596
            nBufXSize, nBufYSize, eSrcType, eBufType,
1597
            static_cast<int>(nPixelSpace), static_cast<int>(nLineSpace),
1598
            aosArgs.List());
2,724✔
1599
    }
1600

1601
    return eErr;
3,094✔
1602
}
1603

1604
/************************************************************************/
1605
/*                         IGetDataCoverageStatus()                     */
1606
/************************************************************************/
1607

1608
int VRTDerivedRasterBand::IGetDataCoverageStatus(
57✔
1609
    int /* nXOff */, int /* nYOff */, int /* nXSize */, int /* nYSize */,
1610
    int /* nMaskFlagStop */, double *pdfDataPct)
1611
{
1612
    if (pdfDataPct != nullptr)
57✔
1613
        *pdfDataPct = -1.0;
×
1614
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
1615
           GDAL_DATA_COVERAGE_STATUS_DATA;
57✔
1616
}
1617

1618
/************************************************************************/
1619
/*                              XMLInit()                               */
1620
/************************************************************************/
1621

1622
CPLErr VRTDerivedRasterBand::XMLInit(const CPLXMLNode *psTree,
1,445✔
1623
                                     const char *pszVRTPath,
1624
                                     VRTMapSharedResources &oMapSharedSources)
1625

1626
{
1627
    const CPLErr eErr =
1628
        VRTSourcedRasterBand::XMLInit(psTree, pszVRTPath, oMapSharedSources);
1,445✔
1629
    if (eErr != CE_None)
1,445✔
1630
        return eErr;
×
1631

1632
    // Read derived pixel function type.
1633
    SetPixelFunctionName(CPLGetXMLValue(psTree, "PixelFunctionType", nullptr));
1,445✔
1634
    if (osFuncName.empty())
1,445✔
1635
    {
1636
        CPLError(CE_Failure, CPLE_AppDefined, "PixelFunctionType missing");
1✔
1637
        return CE_Failure;
1✔
1638
    }
1639

1640
    m_poPrivate->m_osLanguage =
1,444✔
1641
        CPLGetXMLValue(psTree, "PixelFunctionLanguage", "C");
1,444✔
1642
    if (!EQUAL(m_poPrivate->m_osLanguage, "C") &&
1,519✔
1643
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
75✔
1644
    {
1645
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1646
                 "Unsupported PixelFunctionLanguage");
1647
        return CE_Failure;
1✔
1648
    }
1649

1650
    m_poPrivate->m_osCode = CPLGetXMLValue(psTree, "PixelFunctionCode", "");
1,443✔
1651
    if (!m_poPrivate->m_osCode.empty() &&
1,482✔
1652
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
39✔
1653
    {
1654
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1655
                 "PixelFunctionCode can only be used with Python");
1656
        return CE_Failure;
1✔
1657
    }
1658

1659
    m_poPrivate->m_nBufferRadius =
1,442✔
1660
        atoi(CPLGetXMLValue(psTree, "BufferRadius", "0"));
1,442✔
1661
    if (m_poPrivate->m_nBufferRadius < 0 || m_poPrivate->m_nBufferRadius > 1024)
1,442✔
1662
    {
1663
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for BufferRadius");
1✔
1664
        return CE_Failure;
1✔
1665
    }
1666
    if (m_poPrivate->m_nBufferRadius != 0 &&
1,452✔
1667
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
11✔
1668
    {
1669
        CPLError(CE_Failure, CPLE_NotSupported,
1✔
1670
                 "BufferRadius can only be used with Python");
1671
        return CE_Failure;
1✔
1672
    }
1673

1674
    const CPLXMLNode *const psArgs =
1675
        CPLGetXMLNode(psTree, "PixelFunctionArguments");
1,440✔
1676
    if (psArgs != nullptr)
1,440✔
1677
    {
1678
        for (const CPLXMLNode *psIter = psArgs->psChild; psIter;
2,581✔
1679
             psIter = psIter->psNext)
1,371✔
1680
        {
1681
            if (psIter->eType == CXT_Attribute)
1,371✔
1682
            {
1683
                AddPixelFunctionArgument(psIter->pszValue,
1,371✔
1684
                                         psIter->psChild->pszValue);
1,371✔
1685
            }
1686
        }
1687
    }
1688

1689
    // Read optional source transfer data type.
1690
    const char *pszTypeName =
1691
        CPLGetXMLValue(psTree, "SourceTransferType", nullptr);
1,440✔
1692
    if (pszTypeName != nullptr)
1,440✔
1693
    {
1694
        eSourceTransferType = GDALGetDataTypeByName(pszTypeName);
888✔
1695
    }
1696

1697
    // Whether to skip non contributing sources
1698
    const char *pszSkipNonContributingSources =
1699
        CPLGetXMLValue(psTree, "SkipNonContributingSources", nullptr);
1,440✔
1700
    if (pszSkipNonContributingSources)
1,440✔
1701
    {
1702
        SetSkipNonContributingSources(
2✔
1703
            CPLTestBool(pszSkipNonContributingSources));
2✔
1704
    }
1705

1706
    return CE_None;
1,440✔
1707
}
1708

1709
/************************************************************************/
1710
/*                           SerializeToXML()                           */
1711
/************************************************************************/
1712

1713
CPLXMLNode *VRTDerivedRasterBand::SerializeToXML(const char *pszVRTPath,
47✔
1714
                                                 bool &bHasWarnedAboutRAMUsage,
1715
                                                 size_t &nAccRAMUsage)
1716
{
1717
    CPLXMLNode *psTree = VRTSourcedRasterBand::SerializeToXML(
47✔
1718
        pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
1719

1720
    /* -------------------------------------------------------------------- */
1721
    /*      Set subclass.                                                   */
1722
    /* -------------------------------------------------------------------- */
1723
    CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "subClass"),
47✔
1724
                     CXT_Text, "VRTDerivedRasterBand");
1725

1726
    /* ---- Encode DerivedBand-specific fields ---- */
1727
    if (!EQUAL(m_poPrivate->m_osLanguage, "C"))
47✔
1728
    {
1729
        CPLSetXMLValue(psTree, "PixelFunctionLanguage",
5✔
1730
                       m_poPrivate->m_osLanguage);
5✔
1731
    }
1732
    if (!osFuncName.empty())
47✔
1733
        CPLSetXMLValue(psTree, "PixelFunctionType", osFuncName.c_str());
46✔
1734
    if (!m_poPrivate->m_oFunctionArgs.empty())
47✔
1735
    {
1736
        CPLXMLNode *psArgs =
1737
            CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionArguments");
40✔
1738
        for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
109✔
1739
        {
1740
            const char *pszKey = m_poPrivate->m_oFunctionArgs[i].first.c_str();
69✔
1741
            const char *pszValue =
1742
                m_poPrivate->m_oFunctionArgs[i].second.c_str();
69✔
1743
            CPLCreateXMLNode(CPLCreateXMLNode(psArgs, CXT_Attribute, pszKey),
69✔
1744
                             CXT_Text, pszValue);
1745
        }
1746
    }
1747
    if (!m_poPrivate->m_osCode.empty())
47✔
1748
    {
1749
        if (m_poPrivate->m_osCode.find("<![CDATA[") == std::string::npos)
4✔
1750
        {
1751
            CPLCreateXMLNode(
4✔
1752
                CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionCode"),
1753
                CXT_Literal,
1754
                ("<![CDATA[" + m_poPrivate->m_osCode + "]]>").c_str());
8✔
1755
        }
1756
        else
1757
        {
1758
            CPLSetXMLValue(psTree, "PixelFunctionCode", m_poPrivate->m_osCode);
×
1759
        }
1760
    }
1761
    if (m_poPrivate->m_nBufferRadius != 0)
47✔
1762
        CPLSetXMLValue(psTree, "BufferRadius",
1✔
1763
                       CPLSPrintf("%d", m_poPrivate->m_nBufferRadius));
1✔
1764
    if (this->eSourceTransferType != GDT_Unknown)
47✔
1765
        CPLSetXMLValue(psTree, "SourceTransferType",
4✔
1766
                       GDALGetDataTypeName(eSourceTransferType));
1767

1768
    if (m_poPrivate->m_bSkipNonContributingSourcesSpecified)
47✔
1769
    {
1770
        CPLSetXMLValue(psTree, "SkipNonContributingSources",
1✔
1771
                       m_poPrivate->m_bSkipNonContributingSources ? "true"
1✔
1772
                                                                  : "false");
1773
    }
1774

1775
    return psTree;
47✔
1776
}
1777

1778
/************************************************************************/
1779
/*                             GetMinimum()                             */
1780
/************************************************************************/
1781

1782
double VRTDerivedRasterBand::GetMinimum(int *pbSuccess)
5✔
1783
{
1784
    return GDALRasterBand::GetMinimum(pbSuccess);
5✔
1785
}
1786

1787
/************************************************************************/
1788
/*                             GetMaximum()                             */
1789
/************************************************************************/
1790

1791
double VRTDerivedRasterBand::GetMaximum(int *pbSuccess)
5✔
1792
{
1793
    return GDALRasterBand::GetMaximum(pbSuccess);
5✔
1794
}
1795

1796
/************************************************************************/
1797
/*                       ComputeRasterMinMax()                          */
1798
/************************************************************************/
1799

1800
CPLErr VRTDerivedRasterBand::ComputeRasterMinMax(int bApproxOK,
15✔
1801
                                                 double *adfMinMax)
1802
{
1803
    return GDALRasterBand::ComputeRasterMinMax(bApproxOK, adfMinMax);
15✔
1804
}
1805

1806
/************************************************************************/
1807
/*                         ComputeStatistics()                          */
1808
/************************************************************************/
1809

1810
CPLErr VRTDerivedRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
1✔
1811
                                               double *pdfMax, double *pdfMean,
1812
                                               double *pdfStdDev,
1813
                                               GDALProgressFunc pfnProgress,
1814
                                               void *pProgressData)
1815

1816
{
1817
    return GDALRasterBand::ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
1✔
1818
                                             pdfStdDev, pfnProgress,
1819
                                             pProgressData);
1✔
1820
}
1821

1822
/************************************************************************/
1823
/*                            GetHistogram()                            */
1824
/************************************************************************/
1825

1826
CPLErr VRTDerivedRasterBand::GetHistogram(double dfMin, double dfMax,
1✔
1827
                                          int nBuckets, GUIntBig *panHistogram,
1828
                                          int bIncludeOutOfRange, int bApproxOK,
1829
                                          GDALProgressFunc pfnProgress,
1830
                                          void *pProgressData)
1831

1832
{
1833
    return VRTRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
1✔
1834
                                       bIncludeOutOfRange, bApproxOK,
1835
                                       pfnProgress, pProgressData);
1✔
1836
}
1837

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

© 2025 Coveralls, Inc