Coverage Report

Created: 2026-04-01 06:20

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdal/frmts/vrt/vrtderivedrasterband.cpp
Line
Count
Source
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 "gdal_priv.h"
18
#include "vrtdataset.h"
19
#include "cpl_multiproc.h"
20
#include "gdalpython.h"
21
#include "gdalantirecursion.h"
22
23
#include <algorithm>
24
#include <array>
25
#include <map>
26
#include <vector>
27
#include <utility>
28
29
/*! @cond Doxygen_Suppress */
30
31
using namespace GDALPy;
32
33
// #define GDAL_VRT_DISABLE_PYTHON
34
35
#ifndef GDAL_VRT_ENABLE_PYTHON_DEFAULT
36
// Can be YES, NO or TRUSTED_MODULES
37
0
#define GDAL_VRT_ENABLE_PYTHON_DEFAULT "TRUSTED_MODULES"
38
#endif
39
40
/* Flags for getting buffers */
41
0
#define PyBUF_WRITABLE 0x0001
42
0
#define PyBUF_FORMAT 0x0004
43
0
#define PyBUF_ND 0x0008
44
0
#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
45
0
#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
46
0
#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT)
47
48
/************************************************************************/
49
/*                        GDALCreateNumpyArray()                        */
50
/************************************************************************/
51
52
static PyObject *GDALCreateNumpyArray(PyObject *pCreateArray, void *pBuffer,
53
                                      GDALDataType eType, int nHeight,
54
                                      int nWidth)
55
0
{
56
0
    PyObject *poPyBuffer;
57
0
    const size_t nSize =
58
0
        static_cast<size_t>(nHeight) * nWidth * GDALGetDataTypeSizeBytes(eType);
59
0
    Py_buffer pybuffer;
60
0
    if (PyBuffer_FillInfo(&pybuffer, nullptr, static_cast<char *>(pBuffer),
61
0
                          nSize, 0, PyBUF_FULL) != 0)
62
0
    {
63
0
        return nullptr;
64
0
    }
65
0
    poPyBuffer = PyMemoryView_FromBuffer(&pybuffer);
66
0
    PyObject *pArgsCreateArray = PyTuple_New(4);
67
0
    PyTuple_SetItem(pArgsCreateArray, 0, poPyBuffer);
68
0
    const char *pszDataType = nullptr;
69
0
    switch (eType)
70
0
    {
71
0
        case GDT_UInt8:
72
0
            pszDataType = "uint8";
73
0
            break;
74
0
        case GDT_Int8:
75
0
            pszDataType = "int8";
76
0
            break;
77
0
        case GDT_UInt16:
78
0
            pszDataType = "uint16";
79
0
            break;
80
0
        case GDT_Int16:
81
0
            pszDataType = "int16";
82
0
            break;
83
0
        case GDT_UInt32:
84
0
            pszDataType = "uint32";
85
0
            break;
86
0
        case GDT_Int32:
87
0
            pszDataType = "int32";
88
0
            break;
89
0
        case GDT_Int64:
90
0
            pszDataType = "int64";
91
0
            break;
92
0
        case GDT_UInt64:
93
0
            pszDataType = "uint64";
94
0
            break;
95
0
        case GDT_Float16:
96
0
            pszDataType = "float16";
97
0
            break;
98
0
        case GDT_Float32:
99
0
            pszDataType = "float32";
100
0
            break;
101
0
        case GDT_Float64:
102
0
            pszDataType = "float64";
103
0
            break;
104
0
        case GDT_CInt16:
105
0
        case GDT_CInt32:
106
0
            CPLAssert(FALSE);
107
0
            break;
108
0
        case GDT_CFloat16:
109
0
            CPLAssert(FALSE);
110
0
            break;
111
0
        case GDT_CFloat32:
112
0
            pszDataType = "complex64";
113
0
            break;
114
0
        case GDT_CFloat64:
115
0
            pszDataType = "complex128";
116
0
            break;
117
0
        case GDT_Unknown:
118
0
        case GDT_TypeCount:
119
0
            CPLAssert(FALSE);
120
0
            break;
121
0
    }
122
0
    PyTuple_SetItem(
123
0
        pArgsCreateArray, 1,
124
0
        PyBytes_FromStringAndSize(pszDataType, strlen(pszDataType)));
125
0
    PyTuple_SetItem(pArgsCreateArray, 2, PyLong_FromLong(nHeight));
126
0
    PyTuple_SetItem(pArgsCreateArray, 3, PyLong_FromLong(nWidth));
127
0
    PyObject *poNumpyArray =
128
0
        PyObject_Call(pCreateArray, pArgsCreateArray, nullptr);
129
0
    Py_DecRef(pArgsCreateArray);
130
0
    if (PyErr_Occurred())
131
0
        PyErr_Print();
132
0
    return poNumpyArray;
133
0
}
134
135
/************************************************************************/
136
/* ==================================================================== */
137
/*                     VRTDerivedRasterBandPrivateData                  */
138
/* ==================================================================== */
139
/************************************************************************/
140
141
class VRTDerivedRasterBandPrivateData
142
{
143
    VRTDerivedRasterBandPrivateData(const VRTDerivedRasterBandPrivateData &) =
144
        delete;
145
    VRTDerivedRasterBandPrivateData &
146
    operator=(const VRTDerivedRasterBandPrivateData &) = delete;
147
148
  public:
149
    CPLString m_osCode{};
150
    CPLString m_osLanguage = "C";
151
    int m_nBufferRadius = 0;
152
    PyObject *m_poGDALCreateNumpyArray = nullptr;
153
    PyObject *m_poUserFunction = nullptr;
154
    bool m_bPythonInitializationDone = false;
155
    bool m_bPythonInitializationSuccess = false;
156
    bool m_bExclusiveLock = false;
157
    bool m_bFirstTime = true;
158
    std::vector<std::pair<CPLString, CPLString>> m_oFunctionArgs{};
159
    bool m_bSkipNonContributingSourcesSpecified = false;
160
    bool m_bSkipNonContributingSources = false;
161
    GIntBig m_nAllowedRAMUsage = 0;
162
163
    VRTDerivedRasterBandPrivateData()
164
0
        : m_nAllowedRAMUsage(CPLGetUsablePhysicalRAM() / 10 * 4)
165
0
    {
166
        // Use only up to 40% of RAM to acquire source bands and generate the
167
        // output buffer.
168
        // Only for tests now
169
0
        const char *pszMAX_RAM = "VRT_DERIVED_DATASET_ALLOWED_RAM_USAGE";
170
0
        if (const char *pszVal = CPLGetConfigOption(pszMAX_RAM, nullptr))
171
0
        {
172
0
            CPL_IGNORE_RET_VAL(
173
0
                CPLParseMemorySize(pszVal, &m_nAllowedRAMUsage, nullptr));
174
0
        }
175
0
    }
176
177
    ~VRTDerivedRasterBandPrivateData();
178
};
179
180
VRTDerivedRasterBandPrivateData::~VRTDerivedRasterBandPrivateData()
181
0
{
182
0
    if (m_poGDALCreateNumpyArray)
183
0
        Py_DecRef(m_poGDALCreateNumpyArray);
184
0
    if (m_poUserFunction)
185
0
        Py_DecRef(m_poUserFunction);
186
0
}
187
188
/************************************************************************/
189
/* ==================================================================== */
190
/*                          VRTDerivedRasterBand                        */
191
/* ==================================================================== */
192
/************************************************************************/
193
194
/************************************************************************/
195
/*                        VRTDerivedRasterBand()                        */
196
/************************************************************************/
197
198
VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn)
199
0
    : VRTSourcedRasterBand(poDSIn, nBandIn), m_poPrivate(nullptr),
200
0
      eSourceTransferType(GDT_Unknown)
201
0
{
202
0
    m_poPrivate = new VRTDerivedRasterBandPrivateData;
203
0
}
204
205
/************************************************************************/
206
/*                        VRTDerivedRasterBand()                        */
207
/************************************************************************/
208
209
VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn,
210
                                           GDALDataType eType, int nXSize,
211
                                           int nYSize, int nBlockXSizeIn,
212
                                           int nBlockYSizeIn)
213
0
    : VRTSourcedRasterBand(poDSIn, nBandIn, eType, nXSize, nYSize,
214
0
                           nBlockXSizeIn, nBlockYSizeIn),
215
0
      m_poPrivate(nullptr), eSourceTransferType(GDT_Unknown)
216
0
{
217
0
    m_poPrivate = new VRTDerivedRasterBandPrivateData;
218
0
}
219
220
/************************************************************************/
221
/*                       ~VRTDerivedRasterBand()                        */
222
/************************************************************************/
223
224
VRTDerivedRasterBand::~VRTDerivedRasterBand()
225
226
0
{
227
0
    delete m_poPrivate;
228
0
}
229
230
/************************************************************************/
231
/*                     CopyForCloneWithoutSources()                     */
232
/************************************************************************/
233
234
void VRTDerivedRasterBand::CopyForCloneWithoutSources(
235
    const VRTDerivedRasterBand *poSrcBand)
236
0
{
237
0
    VRTSourcedRasterBand::CopyForCloneWithoutSources(poSrcBand);
238
0
    osFuncName = poSrcBand->osFuncName;
239
0
    eSourceTransferType = poSrcBand->eSourceTransferType;
240
0
    m_poPrivate->m_osCode = poSrcBand->m_poPrivate->m_osCode;
241
0
    m_poPrivate->m_osLanguage = poSrcBand->m_poPrivate->m_osLanguage;
242
0
    m_poPrivate->m_nBufferRadius = poSrcBand->m_poPrivate->m_nBufferRadius;
243
0
    m_poPrivate->m_oFunctionArgs = poSrcBand->m_poPrivate->m_oFunctionArgs;
244
0
    m_poPrivate->m_bSkipNonContributingSources =
245
0
        poSrcBand->m_poPrivate->m_bSkipNonContributingSources;
246
0
}
247
248
/************************************************************************/
249
/*                        CloneWithoutSources()                         */
250
/************************************************************************/
251
252
std::unique_ptr<VRTSourcedRasterBand>
253
VRTDerivedRasterBand::CloneWithoutSources(GDALDataset *poNewDS, int nNewXSize,
254
                                          int nNewYSize) const
255
0
{
256
0
    auto poClone = std::make_unique<VRTDerivedRasterBand>(
257
0
        poNewDS, GetBand(), GetRasterDataType(), nNewXSize, nNewYSize,
258
0
        nBlockXSize, nBlockYSize);
259
0
    poClone->CopyForCloneWithoutSources(this);
260
0
    return poClone;
261
0
}
262
263
/************************************************************************/
264
/*                              Cleanup()                               */
265
/************************************************************************/
266
267
void VRTDerivedRasterBand::Cleanup()
268
0
{
269
0
}
270
271
/************************************************************************/
272
/*                     GetGlobalMapPixelFunction()                      */
273
/************************************************************************/
274
275
static std::map<std::string,
276
                std::pair<VRTDerivedRasterBand::PixelFunc, std::string>> &
277
GetGlobalMapPixelFunction()
278
0
{
279
0
    static std::map<std::string,
280
0
                    std::pair<VRTDerivedRasterBand::PixelFunc, std::string>>
281
0
        gosMapPixelFunction;
282
0
    return gosMapPixelFunction;
283
0
}
284
285
/************************************************************************/
286
/*                          AddPixelFunction()                          */
287
/************************************************************************/
288
289
/*! @endcond */
290
291
/**
292
 * This adds a pixel function to the global list of available pixel
293
 * functions for derived bands.  Pixel functions must be registered
294
 * in this way before a derived band tries to access data.
295
 *
296
 * Derived bands are stored with only the name of the pixel function
297
 * that it will apply, and if a pixel function matching the name is not
298
 * found the IRasterIO() call will do nothing.
299
 *
300
 * @param pszName Name used to access pixel function
301
 * @param pfnNewFunction Pixel function associated with name.  An
302
 *  existing pixel function registered with the same name will be
303
 *  replaced with the new one.
304
 *
305
 * @return CE_None, invalid (NULL) parameters are currently ignored.
306
 */
307
CPLErr CPL_STDCALL GDALAddDerivedBandPixelFunc(
308
    const char *pszName, GDALDerivedPixelFunc pfnNewFunction)
309
0
{
310
0
    if (pszName == nullptr || pszName[0] == '\0' || pfnNewFunction == nullptr)
311
0
    {
312
0
        return CE_None;
313
0
    }
314
315
0
    GetGlobalMapPixelFunction()[pszName] = {
316
0
        [pfnNewFunction](void **papoSources, int nSources, void *pData,
317
0
                         int nBufXSize, int nBufYSize, GDALDataType eSrcType,
318
0
                         GDALDataType eBufType, int nPixelSpace, int nLineSpace,
319
0
                         CSLConstList papszFunctionArgs)
320
0
        {
321
0
            (void)papszFunctionArgs;
322
0
            return pfnNewFunction(papoSources, nSources, pData, nBufXSize,
323
0
                                  nBufYSize, eSrcType, eBufType, nPixelSpace,
324
0
                                  nLineSpace);
325
0
        },
326
0
        ""};
327
328
0
    return CE_None;
329
0
}
330
331
/**
332
 * This adds a pixel function to the global list of available pixel
333
 * functions for derived bands.  Pixel functions must be registered
334
 * in this way before a derived band tries to access data.
335
 *
336
 * Derived bands are stored with only the name of the pixel function
337
 * that it will apply, and if a pixel function matching the name is not
338
 * found the IRasterIO() call will do nothing.
339
 *
340
 * @param pszName Name used to access pixel function
341
 * @param pfnNewFunction Pixel function associated with name.  An
342
 *  existing pixel function registered with the same name will be
343
 *  replaced with the new one.
344
 * @param pszMetadata Pixel function metadata (not currently implemented)
345
 *
346
 * @return CE_None, invalid (NULL) parameters are currently ignored.
347
 * @since GDAL 3.4
348
 */
349
CPLErr CPL_STDCALL GDALAddDerivedBandPixelFuncWithArgs(
350
    const char *pszName, GDALDerivedPixelFuncWithArgs pfnNewFunction,
351
    const char *pszMetadata)
352
0
{
353
0
    if (!pszName || pszName[0] == '\0' || !pfnNewFunction)
354
0
    {
355
0
        return CE_None;
356
0
    }
357
358
0
    GetGlobalMapPixelFunction()[pszName] = {pfnNewFunction,
359
0
                                            pszMetadata ? pszMetadata : ""};
360
361
0
    return CE_None;
362
0
}
363
364
/*! @cond Doxygen_Suppress */
365
366
/**
367
 * This adds a pixel function to the global list of available pixel
368
 * functions for derived bands.
369
 *
370
 * This is the same as the C function GDALAddDerivedBandPixelFunc()
371
 *
372
 * @param pszFuncNameIn Name used to access pixel function
373
 * @param pfnNewFunction Pixel function associated with name.  An
374
 *  existing pixel function registered with the same name will be
375
 *  replaced with the new one.
376
 *
377
 * @return CE_None, invalid (NULL) parameters are currently ignored.
378
 */
379
CPLErr
380
VRTDerivedRasterBand::AddPixelFunction(const char *pszFuncNameIn,
381
                                       GDALDerivedPixelFunc pfnNewFunction)
382
0
{
383
0
    return GDALAddDerivedBandPixelFunc(pszFuncNameIn, pfnNewFunction);
384
0
}
385
386
CPLErr VRTDerivedRasterBand::AddPixelFunction(
387
    const char *pszFuncNameIn, GDALDerivedPixelFuncWithArgs pfnNewFunction,
388
    const char *pszMetadata)
389
0
{
390
0
    return GDALAddDerivedBandPixelFuncWithArgs(pszFuncNameIn, pfnNewFunction,
391
0
                                               pszMetadata);
392
0
}
393
394
/************************************************************************/
395
/*                          GetPixelFunction()                          */
396
/************************************************************************/
397
398
/**
399
 * Get a pixel function previously registered using the global
400
 * AddPixelFunction.
401
 *
402
 * @param pszFuncNameIn The name associated with the pixel function.
403
 *
404
 * @return A pointer to a std::pair whose first element is the pixel
405
 *         function pointer and second element is the pixel function
406
 *         metadata string. If no pixel function has been registered
407
 *         for pszFuncNameIn, nullptr will be returned.
408
 */
409
/* static */
410
const std::pair<VRTDerivedRasterBand::PixelFunc, std::string> *
411
VRTDerivedRasterBand::GetPixelFunction(const char *pszFuncNameIn)
412
0
{
413
0
    if (pszFuncNameIn == nullptr || pszFuncNameIn[0] == '\0')
414
0
    {
415
0
        return nullptr;
416
0
    }
417
418
0
    const auto &oMapPixelFunction = GetGlobalMapPixelFunction();
419
0
    const auto oIter = oMapPixelFunction.find(pszFuncNameIn);
420
421
0
    if (oIter == oMapPixelFunction.end())
422
0
        return nullptr;
423
424
0
    return &(oIter->second);
425
0
}
426
427
/************************************************************************/
428
/*                       GetPixelFunctionNames()                        */
429
/************************************************************************/
430
431
/**
432
 * Return the list of available pixel function names.
433
 */
434
/* static */
435
std::vector<std::string> VRTDerivedRasterBand::GetPixelFunctionNames()
436
0
{
437
0
    std::vector<std::string> res;
438
0
    for (const auto &iter : GetGlobalMapPixelFunction())
439
0
    {
440
0
        res.push_back(iter.first);
441
0
    }
442
0
    return res;
443
0
}
444
445
/************************************************************************/
446
/*                        SetPixelFunctionName()                        */
447
/************************************************************************/
448
449
/**
450
 * Set the pixel function name to be applied to this derived band.  The
451
 * name should match a pixel function registered using AddPixelFunction.
452
 *
453
 * @param pszFuncNameIn Name of pixel function to be applied to this derived
454
 * band.
455
 */
456
void VRTDerivedRasterBand::SetPixelFunctionName(const char *pszFuncNameIn)
457
0
{
458
0
    osFuncName = (pszFuncNameIn == nullptr) ? "" : pszFuncNameIn;
459
0
}
460
461
/************************************************************************/
462
/*                      AddPixelFunctionArgument()                      */
463
/************************************************************************/
464
465
/**
466
 *  Set a pixel function argument to a specified value.
467
 * @param pszArg the argument name
468
 * @param pszValue the argument value
469
 *
470
 * @since 3.12
471
 */
472
void VRTDerivedRasterBand::AddPixelFunctionArgument(const char *pszArg,
473
                                                    const char *pszValue)
474
0
{
475
0
    m_poPrivate->m_oFunctionArgs.emplace_back(pszArg, pszValue);
476
0
}
477
478
/************************************************************************/
479
/*                      SetPixelFunctionLanguage()                      */
480
/************************************************************************/
481
482
/**
483
 * Set the language of the pixel function.
484
 *
485
 * @param pszLanguage Language of the pixel function (only "C" and "Python"
486
 * are supported currently)
487
 * @since GDAL 2.3
488
 */
489
void VRTDerivedRasterBand::SetPixelFunctionLanguage(const char *pszLanguage)
490
0
{
491
0
    m_poPrivate->m_osLanguage = pszLanguage;
492
0
}
493
494
/************************************************************************/
495
/*                   SetSkipNonContributingSources()                    */
496
/************************************************************************/
497
498
/** Whether sources that do not intersect the VRTRasterBand RasterIO() requested
499
 * region should be omitted. By default, data for all sources, including ones
500
 * that do not intersect it, are passed to the pixel function. By setting this
501
 * parameter to true, only sources that intersect the requested region will be
502
 * passed.
503
 *
504
 * @param bSkip whether to skip non-contributing sources
505
 *
506
 * @since 3.12
507
 */
508
void VRTDerivedRasterBand::SetSkipNonContributingSources(bool bSkip)
509
0
{
510
0
    m_poPrivate->m_bSkipNonContributingSources = bSkip;
511
0
    m_poPrivate->m_bSkipNonContributingSourcesSpecified = true;
512
0
}
513
514
/************************************************************************/
515
/*                       SetSourceTransferType()                        */
516
/************************************************************************/
517
518
/**
519
 * Set the transfer type to be used to obtain pixel information from
520
 * all of the sources.  If unset, the transfer type used will be the
521
 * same as the derived band data type.  This makes it possible, for
522
 * example, to pass CFloat32 source pixels to the pixel function, even
523
 * if the pixel function generates a raster for a derived band that
524
 * is of type Byte.
525
 *
526
 * @param eDataTypeIn Data type to use to obtain pixel information from
527
 * the sources to be passed to the derived band pixel function.
528
 */
529
void VRTDerivedRasterBand::SetSourceTransferType(GDALDataType eDataTypeIn)
530
0
{
531
0
    eSourceTransferType = eDataTypeIn;
532
0
}
533
534
/************************************************************************/
535
/*                          InitializePython()                          */
536
/************************************************************************/
537
538
bool VRTDerivedRasterBand::InitializePython()
539
0
{
540
0
    if (m_poPrivate->m_bPythonInitializationDone)
541
0
        return m_poPrivate->m_bPythonInitializationSuccess;
542
543
0
    m_poPrivate->m_bPythonInitializationDone = true;
544
0
    m_poPrivate->m_bPythonInitializationSuccess = false;
545
546
0
    const size_t nIdxDot = osFuncName.rfind(".");
547
0
    CPLString osPythonModule;
548
0
    CPLString osPythonFunction;
549
0
    if (nIdxDot != std::string::npos)
550
0
    {
551
0
        osPythonModule = osFuncName.substr(0, nIdxDot);
552
0
        osPythonFunction = osFuncName.substr(nIdxDot + 1);
553
0
    }
554
0
    else
555
0
    {
556
0
        osPythonFunction = osFuncName;
557
0
    }
558
559
0
#ifndef GDAL_VRT_DISABLE_PYTHON
560
0
    const char *pszPythonEnabled =
561
0
        CPLGetConfigOption("GDAL_VRT_ENABLE_PYTHON", nullptr);
562
#else
563
    const char *pszPythonEnabled = "NO";
564
#endif
565
0
    const CPLString osPythonEnabled(
566
0
        pszPythonEnabled ? pszPythonEnabled : GDAL_VRT_ENABLE_PYTHON_DEFAULT);
567
568
0
    if (EQUAL(osPythonEnabled, "TRUSTED_MODULES"))
569
0
    {
570
0
        bool bIsTrustedModule = false;
571
0
        const CPLString osVRTTrustedModules(
572
0
            CPLGetConfigOption("GDAL_VRT_PYTHON_TRUSTED_MODULES", ""));
573
0
        if (!osPythonModule.empty())
574
0
        {
575
0
            char **papszTrustedModules =
576
0
                CSLTokenizeString2(osVRTTrustedModules, ",", 0);
577
0
            for (char **papszIter = papszTrustedModules;
578
0
                 !bIsTrustedModule && papszIter && *papszIter; ++papszIter)
579
0
            {
580
0
                const char *pszIterModule = *papszIter;
581
0
                size_t nIterModuleLen = strlen(pszIterModule);
582
0
                if (nIterModuleLen > 2 &&
583
0
                    strncmp(pszIterModule + nIterModuleLen - 2, ".*", 2) == 0)
584
0
                {
585
0
                    bIsTrustedModule =
586
0
                        (strncmp(osPythonModule, pszIterModule,
587
0
                                 nIterModuleLen - 2) == 0) &&
588
0
                        (osPythonModule.size() == nIterModuleLen - 2 ||
589
0
                         (osPythonModule.size() >= nIterModuleLen &&
590
0
                          osPythonModule[nIterModuleLen - 1] == '.'));
591
0
                }
592
0
                else if (nIterModuleLen >= 1 &&
593
0
                         pszIterModule[nIterModuleLen - 1] == '*')
594
0
                {
595
0
                    bIsTrustedModule = (strncmp(osPythonModule, pszIterModule,
596
0
                                                nIterModuleLen - 1) == 0);
597
0
                }
598
0
                else
599
0
                {
600
0
                    bIsTrustedModule =
601
0
                        (strcmp(osPythonModule, pszIterModule) == 0);
602
0
                }
603
0
            }
604
0
            CSLDestroy(papszTrustedModules);
605
0
        }
606
607
0
        if (!bIsTrustedModule)
608
0
        {
609
0
            if (osPythonModule.empty())
610
0
            {
611
0
                CPLError(
612
0
                    CE_Failure, CPLE_AppDefined,
613
0
                    "Python code needs to be executed, but it uses inline code "
614
0
                    "in the VRT whereas the current policy is to trust only "
615
0
                    "code from external trusted modules (defined in the "
616
0
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
617
0
                    "If you trust the code in %s, you can set the "
618
0
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
619
0
                    GetDataset() ? GetDataset()->GetDescription()
620
0
                                 : "(unknown VRT)");
621
0
            }
622
0
            else if (osVRTTrustedModules.empty())
623
0
            {
624
0
                CPLError(
625
0
                    CE_Failure, CPLE_AppDefined,
626
0
                    "Python code needs to be executed, but it uses code "
627
0
                    "from module '%s', whereas the current policy is to "
628
0
                    "trust only code from modules defined in the "
629
0
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option, "
630
0
                    "which is currently unset. "
631
0
                    "If you trust the code in '%s', you can add module '%s' "
632
0
                    "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
633
0
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
634
0
                    osPythonModule.c_str(),
635
0
                    GetDataset() ? GetDataset()->GetDescription()
636
0
                                 : "(unknown VRT)",
637
0
                    osPythonModule.c_str());
638
0
            }
639
0
            else
640
0
            {
641
0
                CPLError(
642
0
                    CE_Failure, CPLE_AppDefined,
643
0
                    "Python code needs to be executed, but it uses code "
644
0
                    "from module '%s', whereas the current policy is to "
645
0
                    "trust only code from modules '%s' (defined in the "
646
0
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
647
0
                    "If you trust the code in '%s', you can add module '%s' "
648
0
                    "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
649
0
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
650
0
                    osPythonModule.c_str(), osVRTTrustedModules.c_str(),
651
0
                    GetDataset() ? GetDataset()->GetDescription()
652
0
                                 : "(unknown VRT)",
653
0
                    osPythonModule.c_str());
654
0
            }
655
0
            return false;
656
0
        }
657
0
    }
658
659
#ifdef disabled_because_this_is_probably_broken_by_design
660
    // See https://lwn.net/Articles/574215/
661
    // and http://nedbatchelder.com/blog/201206/eval_really_is_dangerous.html
662
    else if (EQUAL(osPythonEnabled, "IF_SAFE"))
663
    {
664
        bool bSafe = true;
665
        // If the function comes from another module, then we don't know
666
        if (!osPythonModule.empty())
667
        {
668
            CPLDebug("VRT", "Python function is from another module");
669
            bSafe = false;
670
        }
671
672
        CPLString osCode(m_poPrivate->m_osCode);
673
674
        // Reject all imports except a few trusted modules
675
        const char *const apszTrustedImports[] = {
676
            "import math",
677
            "from math import",
678
            "import numpy",  // caution: numpy has lots of I/O functions !
679
            "from numpy import",
680
            // TODO: not sure if importing arbitrary stuff from numba is OK
681
            // so let's just restrict to jit.
682
            "from numba import jit",
683
684
            // Not imports but still whitelisted, whereas other __ is banned
685
            "__init__",
686
            "__call__",
687
        };
688
        for (size_t i = 0; i < CPL_ARRAYSIZE(apszTrustedImports); ++i)
689
        {
690
            osCode.replaceAll(CPLString(apszTrustedImports[i]), "");
691
        }
692
693
        // Some dangerous built-in functions or numpy functions
694
        const char *const apszUntrusted[] = {
695
            "import",  // and __import__
696
            "eval",       "compile", "open",
697
            "load",        // reload, numpy.load
698
            "file",        // and exec_file, numpy.fromfile, numpy.tofile
699
            "input",       // and raw_input
700
            "save",        // numpy.save
701
            "memmap",      // numpy.memmap
702
            "DataSource",  // numpy.DataSource
703
            "genfromtxt",  // numpy.genfromtxt
704
            "getattr",
705
            "ctypeslib",  // numpy.ctypeslib
706
            "testing",    // numpy.testing
707
            "dump",       // numpy.ndarray.dump
708
            "fromregex",  // numpy.fromregex
709
            "__"};
710
        for (size_t i = 0; i < CPL_ARRAYSIZE(apszUntrusted); ++i)
711
        {
712
            if (osCode.find(apszUntrusted[i]) != std::string::npos)
713
            {
714
                CPLDebug("VRT", "Found '%s' word in Python code",
715
                         apszUntrusted[i]);
716
                bSafe = false;
717
            }
718
        }
719
720
        if (!bSafe)
721
        {
722
            CPLError(CE_Failure, CPLE_AppDefined,
723
                     "Python code needs to be executed, but we cannot verify "
724
                     "if it is safe, so this is disabled by default. "
725
                     "If you trust the code in %s, you can set the "
726
                     "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
727
                     GetDataset() ? GetDataset()->GetDescription()
728
                                  : "(unknown VRT)");
729
            return false;
730
        }
731
    }
732
#endif  // disabled_because_this_is_probably_broken_by_design
733
734
0
    else if (!EQUAL(osPythonEnabled, "YES") && !EQUAL(osPythonEnabled, "ON") &&
735
0
             !EQUAL(osPythonEnabled, "TRUE"))
736
0
    {
737
0
        if (pszPythonEnabled == nullptr)
738
0
        {
739
            // Note: this is dead code with our current default policy
740
            // GDAL_VRT_ENABLE_PYTHON == "TRUSTED_MODULES"
741
0
            CPLError(CE_Failure, CPLE_AppDefined,
742
0
                     "Python code needs to be executed, but this is "
743
0
                     "disabled by default. If you trust the code in %s, "
744
0
                     "you can set the GDAL_VRT_ENABLE_PYTHON configuration "
745
0
                     "option to YES.",
746
0
                     GetDataset() ? GetDataset()->GetDescription()
747
0
                                  : "(unknown VRT)");
748
0
        }
749
0
        else
750
0
        {
751
0
            CPLError(
752
0
                CE_Failure, CPLE_AppDefined,
753
0
                "Python code in %s needs to be executed, but this has been "
754
0
                "explicitly disabled.",
755
0
                GetDataset() ? GetDataset()->GetDescription()
756
0
                             : "(unknown VRT)");
757
0
        }
758
0
        return false;
759
0
    }
760
761
0
    if (!GDALPythonInitialize())
762
0
        return false;
763
764
    // Whether we should just use our own global mutex, in addition to Python
765
    // GIL locking.
766
0
    m_poPrivate->m_bExclusiveLock =
767
0
        CPLTestBool(CPLGetConfigOption("GDAL_VRT_PYTHON_EXCLUSIVE_LOCK", "NO"));
768
769
    // numba jit'ification doesn't seem to be thread-safe, so force use of
770
    // lock now and at first execution of function. Later executions seem to
771
    // be thread-safe. This problem doesn't seem to appear for code in
772
    // regular files
773
0
    const bool bUseExclusiveLock =
774
0
        m_poPrivate->m_bExclusiveLock ||
775
0
        m_poPrivate->m_osCode.find("@jit") != std::string::npos;
776
0
    GIL_Holder oHolder(bUseExclusiveLock);
777
778
    // As we don't want to depend on numpy C API/ABI, we use a trick to build
779
    // a numpy array object. We define a Python function to which we pass a
780
    // Python buffer object.
781
782
    // We need to build a unique module name, otherwise this will crash in
783
    // multithreaded use cases.
784
0
    CPLString osModuleName(CPLSPrintf("gdal_vrt_module_%p", this));
785
0
    PyObject *poCompiledString = Py_CompileString(
786
0
        ("import numpy\n"
787
0
         "def GDALCreateNumpyArray(buffer, dtype, height, width):\n"
788
0
         "    return numpy.frombuffer(buffer, str(dtype.decode('ascii')))."
789
0
         "reshape([height, width])\n"
790
0
         "\n" +
791
0
         m_poPrivate->m_osCode)
792
0
            .c_str(),
793
0
        osModuleName, Py_file_input);
794
0
    if (poCompiledString == nullptr || PyErr_Occurred())
795
0
    {
796
0
        CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
797
0
                 GetPyExceptionString().c_str());
798
0
        return false;
799
0
    }
800
0
    PyObject *poModule =
801
0
        PyImport_ExecCodeModule(osModuleName, poCompiledString);
802
0
    Py_DecRef(poCompiledString);
803
804
0
    if (poModule == nullptr || PyErr_Occurred())
805
0
    {
806
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
807
0
                 GetPyExceptionString().c_str());
808
0
        return false;
809
0
    }
810
811
    // Fetch user computation function
812
0
    if (!osPythonModule.empty())
813
0
    {
814
0
        PyObject *poUserModule = PyImport_ImportModule(osPythonModule);
815
0
        if (poUserModule == nullptr || PyErr_Occurred())
816
0
        {
817
0
            CPLString osException = GetPyExceptionString();
818
0
            if (!osException.empty() && osException.back() == '\n')
819
0
            {
820
0
                osException.pop_back();
821
0
            }
822
0
            if (osException.find("ModuleNotFoundError") == 0)
823
0
            {
824
0
                osException += ". You may need to define PYTHONPATH";
825
0
            }
826
0
            CPLError(CE_Failure, CPLE_AppDefined, "%s", osException.c_str());
827
0
            Py_DecRef(poModule);
828
0
            return false;
829
0
        }
830
0
        m_poPrivate->m_poUserFunction =
831
0
            PyObject_GetAttrString(poUserModule, osPythonFunction);
832
0
        Py_DecRef(poUserModule);
833
0
    }
834
0
    else
835
0
    {
836
0
        m_poPrivate->m_poUserFunction =
837
0
            PyObject_GetAttrString(poModule, osPythonFunction);
838
0
    }
839
0
    if (m_poPrivate->m_poUserFunction == nullptr || PyErr_Occurred())
840
0
    {
841
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
842
0
                 GetPyExceptionString().c_str());
843
0
        Py_DecRef(poModule);
844
0
        return false;
845
0
    }
846
0
    if (!PyCallable_Check(m_poPrivate->m_poUserFunction))
847
0
    {
848
0
        CPLError(CE_Failure, CPLE_AppDefined, "Object '%s' is not callable",
849
0
                 osPythonFunction.c_str());
850
0
        Py_DecRef(poModule);
851
0
        return false;
852
0
    }
853
854
    // Fetch our GDALCreateNumpyArray python function
855
0
    m_poPrivate->m_poGDALCreateNumpyArray =
856
0
        PyObject_GetAttrString(poModule, "GDALCreateNumpyArray");
857
0
    if (m_poPrivate->m_poGDALCreateNumpyArray == nullptr || PyErr_Occurred())
858
0
    {
859
        // Shouldn't happen normally...
860
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
861
0
                 GetPyExceptionString().c_str());
862
0
        Py_DecRef(poModule);
863
0
        return false;
864
0
    }
865
0
    Py_DecRef(poModule);
866
867
0
    m_poPrivate->m_bPythonInitializationSuccess = true;
868
0
    return true;
869
0
}
870
871
CPLErr VRTDerivedRasterBand::GetPixelFunctionArguments(
872
    const CPLString &osMetadata,
873
    const std::vector<int> &anMapBufferIdxToSourceIdx, int nXOff, int nYOff,
874
    std::vector<std::pair<CPLString, CPLString>> &oAdditionalArgs)
875
0
{
876
877
0
    auto poArgs = CPLXMLTreeCloser(CPLParseXMLString(osMetadata));
878
0
    if (poArgs != nullptr && poArgs->eType == CXT_Element &&
879
0
        !strcmp(poArgs->pszValue, "PixelFunctionArgumentsList"))
880
0
    {
881
0
        for (CPLXMLNode *psIter = poArgs->psChild; psIter != nullptr;
882
0
             psIter = psIter->psNext)
883
0
        {
884
0
            if (psIter->eType == CXT_Element &&
885
0
                !strcmp(psIter->pszValue, "Argument"))
886
0
            {
887
0
                CPLString osName, osType, osValue;
888
0
                auto pszName = CPLGetXMLValue(psIter, "name", nullptr);
889
0
                if (pszName != nullptr)
890
0
                    osName = pszName;
891
0
                auto pszType = CPLGetXMLValue(psIter, "type", nullptr);
892
0
                if (pszType != nullptr)
893
0
                    osType = pszType;
894
0
                auto pszValue = CPLGetXMLValue(psIter, "value", nullptr);
895
0
                if (pszValue != nullptr)
896
0
                    osValue = pszValue;
897
0
                if (osType == "constant" && osValue != "" && osName != "")
898
0
                    oAdditionalArgs.push_back(
899
0
                        std::pair<CPLString, CPLString>(osName, osValue));
900
0
                if (osType == "builtin")
901
0
                {
902
0
                    const CPLString &osArgName = osValue;
903
0
                    CPLString osVal;
904
0
                    double dfVal = 0;
905
906
0
                    int success(FALSE);
907
0
                    if (osArgName == "NoData")
908
0
                        dfVal = this->GetNoDataValue(&success);
909
0
                    else if (osArgName == "scale")
910
0
                        dfVal = this->GetScale(&success);
911
0
                    else if (osArgName == "offset")
912
0
                        dfVal = this->GetOffset(&success);
913
0
                    else if (osArgName == "xoff")
914
0
                    {
915
0
                        dfVal = static_cast<double>(nXOff);
916
0
                        success = true;
917
0
                    }
918
0
                    else if (osArgName == "yoff")
919
0
                    {
920
0
                        dfVal = static_cast<double>(nYOff);
921
0
                        success = true;
922
0
                    }
923
0
                    else if (osArgName == "crs")
924
0
                    {
925
0
                        const auto *crs =
926
0
                            GetDataset()->GetSpatialRefRasterOnly();
927
0
                        if (crs)
928
0
                        {
929
0
                            osVal =
930
0
                                std::to_string(reinterpret_cast<size_t>(crs));
931
0
                            success = true;
932
0
                        }
933
0
                        else
934
0
                        {
935
0
                            CPLError(CE_Failure, CPLE_AppDefined,
936
0
                                     "VRTDataset has no <SRS>");
937
0
                        }
938
0
                    }
939
0
                    else if (osArgName == "geotransform")
940
0
                    {
941
0
                        GDALGeoTransform gt;
942
0
                        if (GetDataset()->GetGeoTransform(gt) != CE_None)
943
0
                        {
944
                            // Do not fail here because the argument is most
945
                            // likely not needed by the pixel function. If it
946
                            // is needed, the pixel function can emit the error.
947
0
                            continue;
948
0
                        }
949
0
                        osVal = gt.ToString();
950
0
                        success = true;
951
0
                    }
952
0
                    else if (osArgName == "source_names")
953
0
                    {
954
0
                        for (size_t iBuffer = 0;
955
0
                             iBuffer < anMapBufferIdxToSourceIdx.size();
956
0
                             iBuffer++)
957
0
                        {
958
0
                            const int iSource =
959
0
                                anMapBufferIdxToSourceIdx[iBuffer];
960
0
                            const VRTSource *poSource =
961
0
                                m_papoSources[iSource].get();
962
963
0
                            if (iBuffer > 0)
964
0
                            {
965
0
                                osVal += "|";
966
0
                            }
967
968
0
                            const auto &osSourceName = poSource->GetName();
969
0
                            if (osSourceName.empty())
970
0
                            {
971
0
                                osVal += "B" + std::to_string(iBuffer + 1);
972
0
                            }
973
0
                            else
974
0
                            {
975
0
                                osVal += osSourceName;
976
0
                            }
977
0
                        }
978
979
0
                        success = true;
980
0
                    }
981
0
                    else
982
0
                    {
983
0
                        CPLError(
984
0
                            CE_Failure, CPLE_NotSupported,
985
0
                            "PixelFunction builtin argument %s not supported",
986
0
                            osArgName.c_str());
987
0
                        return CE_Failure;
988
0
                    }
989
0
                    if (!success)
990
0
                    {
991
0
                        if (CPLTestBool(
992
0
                                CPLGetXMLValue(psIter, "optional", "false")))
993
0
                            continue;
994
995
0
                        CPLError(CE_Failure, CPLE_AppDefined,
996
0
                                 "Raster has no %s", osValue.c_str());
997
0
                        return CE_Failure;
998
0
                    }
999
1000
0
                    if (osVal.empty())
1001
0
                    {
1002
0
                        osVal = CPLSPrintf("%.17g", dfVal);
1003
0
                    }
1004
1005
0
                    oAdditionalArgs.push_back(
1006
0
                        std::pair<CPLString, CPLString>(osArgName, osVal));
1007
0
                    CPLDebug("VRT",
1008
0
                             "Added builtin pixel function argument %s = %s",
1009
0
                             osArgName.c_str(), osVal.c_str());
1010
0
                }
1011
0
            }
1012
0
        }
1013
0
    }
1014
1015
0
    return CE_None;
1016
0
}
1017
1018
/************************************************************************/
1019
/*                   CreateMapBufferIdxToSourceIdx()                    */
1020
/************************************************************************/
1021
1022
static bool CreateMapBufferIdxToSourceIdx(
1023
    const std::vector<std::unique_ptr<VRTSource>> &apoSources,
1024
    bool bSkipNonContributingSources, int nXOff, int nYOff, int nXSize,
1025
    int nYSize, int nBufXSize, int nBufYSize, GDALRasterIOExtraArg *psExtraArg,
1026
    bool &bCreateMapBufferIdxToSourceIdxHasRun,
1027
    std::vector<int> &anMapBufferIdxToSourceIdx,
1028
    bool &bSkipOutputBufferInitialization)
1029
0
{
1030
0
    CPLAssert(!bCreateMapBufferIdxToSourceIdxHasRun);
1031
0
    bCreateMapBufferIdxToSourceIdxHasRun = true;
1032
0
    anMapBufferIdxToSourceIdx.reserve(apoSources.size());
1033
0
    for (int iSource = 0; iSource < static_cast<int>(apoSources.size());
1034
0
         iSource++)
1035
0
    {
1036
0
        if (bSkipNonContributingSources &&
1037
0
            apoSources[iSource]->IsSimpleSource())
1038
0
        {
1039
0
            bool bError = false;
1040
0
            double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
1041
0
            int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1042
0
            int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1043
0
            auto poSource =
1044
0
                static_cast<VRTSimpleSource *>(apoSources[iSource].get());
1045
0
            if (!poSource->GetSrcDstWindow(
1046
0
                    nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1047
0
                    psExtraArg->eResampleAlg, &dfReqXOff, &dfReqYOff,
1048
0
                    &dfReqXSize, &dfReqYSize, &nReqXOff, &nReqYOff, &nReqXSize,
1049
0
                    &nReqYSize, &nOutXOff, &nOutYOff, &nOutXSize, &nOutYSize,
1050
0
                    bError))
1051
0
            {
1052
0
                if (bError)
1053
0
                {
1054
0
                    return false;
1055
0
                }
1056
1057
                // Skip non contributing source
1058
0
                bSkipOutputBufferInitialization = false;
1059
0
                continue;
1060
0
            }
1061
0
        }
1062
1063
0
        anMapBufferIdxToSourceIdx.push_back(iSource);
1064
0
    }
1065
0
    return true;
1066
0
}
1067
1068
/************************************************************************/
1069
/*                             IRasterIO()                              */
1070
/************************************************************************/
1071
1072
/**
1073
 * Read/write a region of image data for this band.
1074
 *
1075
 * Each of the sources for this derived band will be read and passed to
1076
 * the derived band pixel function.  The pixel function is responsible
1077
 * for applying whatever algorithm is necessary to generate this band's
1078
 * pixels from the sources.
1079
 *
1080
 * The sources will be read using the transfer type specified for sources
1081
 * using SetSourceTransferType().  If no transfer type has been set for
1082
 * this derived band, the band's data type will be used as the transfer type.
1083
 *
1084
 * @see gdalrasterband
1085
 *
1086
 * @param eRWFlag Either GF_Read to read a region of data, or GT_Write to
1087
 * write a region of data.
1088
 *
1089
 * @param nXOff The pixel offset to the top left corner of the region
1090
 * of the band to be accessed.  This would be zero to start from the left side.
1091
 *
1092
 * @param nYOff The line offset to the top left corner of the region
1093
 * of the band to be accessed.  This would be zero to start from the top.
1094
 *
1095
 * @param nXSize The width of the region of the band to be accessed in pixels.
1096
 *
1097
 * @param nYSize The height of the region of the band to be accessed in lines.
1098
 *
1099
 * @param pData The buffer into which the data should be read, or from which
1100
 * it should be written.  This buffer must contain at least nBufXSize *
1101
 * nBufYSize words of type eBufType.  It is organized in left to right,
1102
 * top to bottom pixel order.  Spacing is controlled by the nPixelSpace,
1103
 * and nLineSpace parameters.
1104
 *
1105
 * @param nBufXSize The width of the buffer image into which the desired
1106
 * region is to be read, or from which it is to be written.
1107
 *
1108
 * @param nBufYSize The height of the buffer image into which the desired
1109
 * region is to be read, or from which it is to be written.
1110
 *
1111
 * @param eBufType The type of the pixel values in the pData data buffer.  The
1112
 * pixel values will automatically be translated to/from the GDALRasterBand
1113
 * data type as needed.
1114
 *
1115
 * @param nPixelSpace The byte offset from the start of one pixel value in
1116
 * pData to the start of the next pixel value within a scanline.  If defaulted
1117
 * (0) the size of the datatype eBufType is used.
1118
 *
1119
 * @param nLineSpace The byte offset from the start of one scanline in
1120
 * pData to the start of the next.  If defaulted the size of the datatype
1121
 * eBufType * nBufXSize is used.
1122
 *
1123
 * @return CE_Failure if the access fails, otherwise CE_None.
1124
 */
1125
CPLErr VRTDerivedRasterBand::IRasterIO(
1126
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
1127
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1128
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
1129
0
{
1130
0
    if (eRWFlag == GF_Write)
1131
0
    {
1132
0
        CPLError(CE_Failure, CPLE_AppDefined,
1133
0
                 "Writing through VRTSourcedRasterBand is not supported.");
1134
0
        return CE_Failure;
1135
0
    }
1136
1137
0
    const std::string osFctId("VRTDerivedRasterBand::IRasterIO");
1138
0
    GDALAntiRecursionGuard oGuard(osFctId);
1139
0
    if (oGuard.GetCallDepth() >= 32)
1140
0
    {
1141
0
        CPLError(
1142
0
            CE_Failure, CPLE_AppDefined,
1143
0
            "VRTDerivedRasterBand::IRasterIO(): Recursion detected (case 1)");
1144
0
        return CE_Failure;
1145
0
    }
1146
1147
0
    GDALAntiRecursionGuard oGuard2(oGuard, poDS->GetDescription());
1148
    // Allow multiple recursion depths on the same dataset in case the split strategy is applied
1149
0
    if (oGuard2.GetCallDepth() > 15)
1150
0
    {
1151
0
        CPLError(
1152
0
            CE_Failure, CPLE_AppDefined,
1153
0
            "VRTDerivedRasterBand::IRasterIO(): Recursion detected (case 2)");
1154
0
        return CE_Failure;
1155
0
    }
1156
1157
    if constexpr (sizeof(GSpacing) > sizeof(int))
1158
0
    {
1159
0
        if (nLineSpace > INT_MAX)
1160
0
        {
1161
0
            if (nBufYSize == 1)
1162
0
            {
1163
0
                nLineSpace = 0;
1164
0
            }
1165
0
            else
1166
0
            {
1167
0
                CPLError(CE_Failure, CPLE_NotSupported,
1168
0
                         "VRTDerivedRasterBand::IRasterIO(): nLineSpace > "
1169
0
                         "INT_MAX not supported");
1170
0
                return CE_Failure;
1171
0
            }
1172
0
        }
1173
0
    }
1174
1175
    /* -------------------------------------------------------------------- */
1176
    /*      Do we have overviews that would be appropriate to satisfy       */
1177
    /*      this request?                                                   */
1178
    /* -------------------------------------------------------------------- */
1179
0
    auto l_poDS = dynamic_cast<VRTDataset *>(poDS);
1180
0
    if (l_poDS &&
1181
0
        l_poDS->m_apoOverviews.empty() &&  // do not use virtual overviews
1182
0
        (nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
1183
0
    {
1184
0
        if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1185
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
1186
0
                             nLineSpace, psExtraArg) == CE_None)
1187
0
            return CE_None;
1188
0
    }
1189
1190
0
    const int nBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
1191
0
    GDALDataType eSrcType = eSourceTransferType;
1192
0
    if (eSrcType == GDT_Unknown || eSrcType >= GDT_TypeCount)
1193
0
    {
1194
        // Check the largest data type for all sources
1195
0
        GDALDataType eAllSrcType = GDT_Unknown;
1196
0
        for (auto &poSource : m_papoSources)
1197
0
        {
1198
0
            if (poSource->IsSimpleSource())
1199
0
            {
1200
0
                const auto poSS =
1201
0
                    static_cast<VRTSimpleSource *>(poSource.get());
1202
0
                auto l_poBand = poSS->GetRasterBand();
1203
0
                if (l_poBand)
1204
0
                {
1205
0
                    eAllSrcType = GDALDataTypeUnion(
1206
0
                        eAllSrcType, l_poBand->GetRasterDataType());
1207
0
                }
1208
0
                else
1209
0
                {
1210
0
                    eAllSrcType = GDT_Unknown;
1211
0
                    break;
1212
0
                }
1213
0
            }
1214
0
            else
1215
0
            {
1216
0
                eAllSrcType = GDT_Unknown;
1217
0
                break;
1218
0
            }
1219
0
        }
1220
1221
0
        if (eAllSrcType != GDT_Unknown)
1222
0
            eSrcType = GDALDataTypeUnion(eAllSrcType, eDataType);
1223
0
        else
1224
0
            eSrcType = GDALDataTypeUnion(GDT_Float64, eDataType);
1225
0
    }
1226
0
    const int nSrcTypeSize = GDALGetDataTypeSizeBytes(eSrcType);
1227
1228
0
    std::vector<int> anMapBufferIdxToSourceIdx;
1229
0
    bool bSkipOutputBufferInitialization = !m_papoSources.empty();
1230
0
    bool bCreateMapBufferIdxToSourceIdxHasRun = false;
1231
1232
    // If acquiring the region of interest in a single time is going
1233
    // to consume too much RAM, split in halves, and that recursively
1234
    // until we get below m_nAllowedRAMUsage.
1235
0
    if (m_poPrivate->m_nAllowedRAMUsage > 0 && !m_papoSources.empty() &&
1236
0
        nSrcTypeSize > 0 && nBufXSize == nXSize && nBufYSize == nYSize &&
1237
0
        static_cast<GIntBig>(nBufXSize) * nBufYSize >
1238
0
            m_poPrivate->m_nAllowedRAMUsage /
1239
0
                (static_cast<int>(m_papoSources.size()) * nSrcTypeSize))
1240
0
    {
1241
0
        bool bSplit = true;
1242
0
        if (m_poPrivate->m_bSkipNonContributingSources)
1243
0
        {
1244
            // More accurate check by comparing against the number of
1245
            // actually contributing sources.
1246
0
            if (!CreateMapBufferIdxToSourceIdx(
1247
0
                    m_papoSources, m_poPrivate->m_bSkipNonContributingSources,
1248
0
                    nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1249
0
                    psExtraArg, bCreateMapBufferIdxToSourceIdxHasRun,
1250
0
                    anMapBufferIdxToSourceIdx, bSkipOutputBufferInitialization))
1251
0
            {
1252
0
                return CE_Failure;
1253
0
            }
1254
0
            bSplit =
1255
0
                !anMapBufferIdxToSourceIdx.empty() &&
1256
0
                static_cast<GIntBig>(nBufXSize) * nBufYSize >
1257
0
                    m_poPrivate->m_nAllowedRAMUsage /
1258
0
                        (static_cast<int>(anMapBufferIdxToSourceIdx.size()) *
1259
0
                         nSrcTypeSize);
1260
0
        }
1261
0
        if (bSplit)
1262
0
        {
1263
0
            CPLErr eErr = SplitRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1264
0
                                        pData, nBufXSize, nBufYSize, eBufType,
1265
0
                                        nPixelSpace, nLineSpace, psExtraArg);
1266
0
            if (eErr != CE_Warning)
1267
0
                return eErr;
1268
0
        }
1269
0
    }
1270
1271
    /* ---- Get pixel function for band ---- */
1272
0
    const std::pair<PixelFunc, std::string> *poPixelFunc = nullptr;
1273
0
    std::vector<std::pair<CPLString, CPLString>> oAdditionalArgs;
1274
1275
0
    if (EQUAL(m_poPrivate->m_osLanguage, "C"))
1276
0
    {
1277
0
        poPixelFunc =
1278
0
            VRTDerivedRasterBand::GetPixelFunction(osFuncName.c_str());
1279
0
        if (poPixelFunc == nullptr)
1280
0
        {
1281
0
            CPLError(CE_Failure, CPLE_IllegalArg,
1282
0
                     "VRTDerivedRasterBand::IRasterIO:"
1283
0
                     "Derived band pixel function '%s' not registered.",
1284
0
                     osFuncName.c_str());
1285
0
            return CE_Failure;
1286
0
        }
1287
0
    }
1288
1289
    /* TODO: It would be nice to use a MallocBlock function for each
1290
       individual buffer that would recycle blocks of memory from a
1291
       cache by reassigning blocks that are nearly the same size.
1292
       A corresponding FreeBlock might only truly free if the total size
1293
       of freed blocks gets to be too great of a percentage of the size
1294
       of the allocated blocks. */
1295
1296
    // Get buffers for each source.
1297
0
    const int nBufferRadius = m_poPrivate->m_nBufferRadius;
1298
0
    if (nBufferRadius > (INT_MAX - nBufXSize) / 2 ||
1299
0
        nBufferRadius > (INT_MAX - nBufYSize) / 2)
1300
0
    {
1301
0
        CPLError(CE_Failure, CPLE_AppDefined,
1302
0
                 "Integer overflow: "
1303
0
                 "nBufferRadius > (INT_MAX - nBufXSize) / 2 || "
1304
0
                 "nBufferRadius > (INT_MAX - nBufYSize) / 2)");
1305
0
        return CE_Failure;
1306
0
    }
1307
0
    const int nExtBufXSize = nBufXSize + 2 * nBufferRadius;
1308
0
    const int nExtBufYSize = nBufYSize + 2 * nBufferRadius;
1309
1310
0
    if (!bCreateMapBufferIdxToSourceIdxHasRun)
1311
0
    {
1312
0
        if (!CreateMapBufferIdxToSourceIdx(
1313
0
                m_papoSources, m_poPrivate->m_bSkipNonContributingSources,
1314
0
                nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize, psExtraArg,
1315
0
                bCreateMapBufferIdxToSourceIdxHasRun, anMapBufferIdxToSourceIdx,
1316
0
                bSkipOutputBufferInitialization))
1317
0
        {
1318
0
            return CE_Failure;
1319
0
        }
1320
0
    }
1321
0
    std::vector<std::unique_ptr<void, VSIFreeReleaser>> apBuffers(
1322
0
        anMapBufferIdxToSourceIdx.size());
1323
0
    for (size_t iBuffer = 0; iBuffer < anMapBufferIdxToSourceIdx.size();
1324
0
         ++iBuffer)
1325
0
    {
1326
0
        apBuffers[iBuffer].reset(
1327
0
            VSI_MALLOC3_VERBOSE(nSrcTypeSize, nExtBufXSize, nExtBufYSize));
1328
0
        if (apBuffers[iBuffer] == nullptr)
1329
0
        {
1330
0
            return CE_Failure;
1331
0
        }
1332
1333
0
        bool bBufferInit = true;
1334
0
        const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
1335
0
        if (m_papoSources[iSource]->IsSimpleSource())
1336
0
        {
1337
0
            const auto poSS =
1338
0
                static_cast<VRTSimpleSource *>(m_papoSources[iSource].get());
1339
0
            auto l_poBand = poSS->GetRasterBand();
1340
0
            if (l_poBand != nullptr && poSS->m_dfSrcXOff == 0.0 &&
1341
0
                poSS->m_dfSrcYOff == 0.0 &&
1342
0
                poSS->m_dfSrcXOff + poSS->m_dfSrcXSize ==
1343
0
                    l_poBand->GetXSize() &&
1344
0
                poSS->m_dfSrcYOff + poSS->m_dfSrcYSize ==
1345
0
                    l_poBand->GetYSize() &&
1346
0
                poSS->m_dfDstXOff == 0.0 && poSS->m_dfDstYOff == 0.0 &&
1347
0
                poSS->m_dfDstXOff + poSS->m_dfDstXSize == nRasterXSize &&
1348
0
                poSS->m_dfDstYOff + poSS->m_dfDstYSize == nRasterYSize)
1349
0
            {
1350
0
                if (m_papoSources[iSource]->GetType() ==
1351
0
                    VRTSimpleSource::GetTypeStatic())
1352
0
                    bBufferInit = false;
1353
0
            }
1354
0
            else
1355
0
            {
1356
0
                bSkipOutputBufferInitialization = false;
1357
0
            }
1358
0
        }
1359
0
        else
1360
0
        {
1361
0
            bSkipOutputBufferInitialization = false;
1362
0
        }
1363
0
        if (bBufferInit)
1364
0
        {
1365
            /* ------------------------------------------------------------ */
1366
            /* #4045: Initialize the newly allocated buffers before handing */
1367
            /* them off to the sources. These buffers are packed, so we     */
1368
            /* don't need any special line-by-line handling when a nonzero  */
1369
            /* nodata value is set.                                         */
1370
            /* ------------------------------------------------------------ */
1371
0
            if (!m_bNoDataValueSet || m_dfNoDataValue == 0)
1372
0
            {
1373
0
                memset(apBuffers[iBuffer].get(), 0,
1374
0
                       static_cast<size_t>(nSrcTypeSize) * nExtBufXSize *
1375
0
                           nExtBufYSize);
1376
0
            }
1377
0
            else
1378
0
            {
1379
0
                GDALCopyWords64(&m_dfNoDataValue, GDT_Float64, 0,
1380
0
                                static_cast<GByte *>(apBuffers[iBuffer].get()),
1381
0
                                eSrcType, nSrcTypeSize,
1382
0
                                static_cast<GPtrDiff_t>(nExtBufXSize) *
1383
0
                                    nExtBufYSize);
1384
0
            }
1385
0
        }
1386
0
    }
1387
1388
    /* -------------------------------------------------------------------- */
1389
    /*      Initialize the buffer to some background value. Use the         */
1390
    /*      nodata value if available.                                      */
1391
    /* -------------------------------------------------------------------- */
1392
0
    if (!bSkipOutputBufferInitialization)
1393
0
    {
1394
0
        InitializeOutputBuffer(pData, nBufXSize, nBufYSize, eBufType,
1395
0
                               nPixelSpace, nLineSpace);
1396
0
    }
1397
1398
    // No contributing sources and SkipNonContributingSources mode ?
1399
    // Do not call the pixel function and just return the 0/nodata initialized
1400
    // output buffer.
1401
0
    if (anMapBufferIdxToSourceIdx.empty() &&
1402
0
        m_poPrivate->m_bSkipNonContributingSources)
1403
0
    {
1404
0
        return CE_None;
1405
0
    }
1406
1407
0
    GDALRasterIOExtraArg sExtraArg;
1408
0
    GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
1409
1410
0
    int nXShiftInBuffer = 0;
1411
0
    int nYShiftInBuffer = 0;
1412
0
    int nExtBufXSizeReq = nExtBufXSize;
1413
0
    int nExtBufYSizeReq = nExtBufYSize;
1414
1415
0
    int nXOffExt = nXOff;
1416
0
    int nYOffExt = nYOff;
1417
0
    int nXSizeExt = nXSize;
1418
0
    int nYSizeExt = nYSize;
1419
1420
0
    if (nBufferRadius)
1421
0
    {
1422
0
        double dfXRatio = static_cast<double>(nXSize) / nBufXSize;
1423
0
        double dfYRatio = static_cast<double>(nYSize) / nBufYSize;
1424
1425
0
        if (!sExtraArg.bFloatingPointWindowValidity)
1426
0
        {
1427
0
            sExtraArg.dfXOff = nXOff;
1428
0
            sExtraArg.dfYOff = nYOff;
1429
0
            sExtraArg.dfXSize = nXSize;
1430
0
            sExtraArg.dfYSize = nYSize;
1431
0
        }
1432
1433
0
        sExtraArg.dfXOff -= dfXRatio * nBufferRadius;
1434
0
        sExtraArg.dfYOff -= dfYRatio * nBufferRadius;
1435
0
        sExtraArg.dfXSize += 2 * dfXRatio * nBufferRadius;
1436
0
        sExtraArg.dfYSize += 2 * dfYRatio * nBufferRadius;
1437
0
        if (sExtraArg.dfXOff < 0)
1438
0
        {
1439
0
            nXShiftInBuffer = -static_cast<int>(sExtraArg.dfXOff / dfXRatio);
1440
0
            nExtBufXSizeReq -= nXShiftInBuffer;
1441
0
            sExtraArg.dfXSize += sExtraArg.dfXOff;
1442
0
            sExtraArg.dfXOff = 0;
1443
0
        }
1444
0
        if (sExtraArg.dfYOff < 0)
1445
0
        {
1446
0
            nYShiftInBuffer = -static_cast<int>(sExtraArg.dfYOff / dfYRatio);
1447
0
            nExtBufYSizeReq -= nYShiftInBuffer;
1448
0
            sExtraArg.dfYSize += sExtraArg.dfYOff;
1449
0
            sExtraArg.dfYOff = 0;
1450
0
        }
1451
0
        if (sExtraArg.dfXOff + sExtraArg.dfXSize > nRasterXSize)
1452
0
        {
1453
0
            nExtBufXSizeReq -= static_cast<int>(
1454
0
                (sExtraArg.dfXOff + sExtraArg.dfXSize - nRasterXSize) /
1455
0
                dfXRatio);
1456
0
            sExtraArg.dfXSize = nRasterXSize - sExtraArg.dfXOff;
1457
0
        }
1458
0
        if (sExtraArg.dfYOff + sExtraArg.dfYSize > nRasterYSize)
1459
0
        {
1460
0
            nExtBufYSizeReq -= static_cast<int>(
1461
0
                (sExtraArg.dfYOff + sExtraArg.dfYSize - nRasterYSize) /
1462
0
                dfYRatio);
1463
0
            sExtraArg.dfYSize = nRasterYSize - sExtraArg.dfYOff;
1464
0
        }
1465
1466
0
        nXOffExt = static_cast<int>(sExtraArg.dfXOff);
1467
0
        nYOffExt = static_cast<int>(sExtraArg.dfYOff);
1468
0
        nXSizeExt = std::min(static_cast<int>(sExtraArg.dfXSize + 0.5),
1469
0
                             nRasterXSize - nXOffExt);
1470
0
        nYSizeExt = std::min(static_cast<int>(sExtraArg.dfYSize + 0.5),
1471
0
                             nRasterYSize - nYOffExt);
1472
0
    }
1473
1474
    // Load values for sources into packed buffers.
1475
0
    CPLErr eErr = CE_None;
1476
0
    VRTSource::WorkingState oWorkingState;
1477
0
    for (size_t iBuffer = 0;
1478
0
         iBuffer < anMapBufferIdxToSourceIdx.size() && eErr == CE_None;
1479
0
         iBuffer++)
1480
0
    {
1481
0
        const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
1482
0
        GByte *pabyBuffer = static_cast<GByte *>(apBuffers[iBuffer].get());
1483
0
        eErr = static_cast<VRTSource *>(m_papoSources[iSource].get())
1484
0
                   ->RasterIO(
1485
0
                       eSrcType, nXOffExt, nYOffExt, nXSizeExt, nYSizeExt,
1486
0
                       pabyBuffer + (static_cast<size_t>(nYShiftInBuffer) *
1487
0
                                         nExtBufXSize +
1488
0
                                     nXShiftInBuffer) *
1489
0
                                        nSrcTypeSize,
1490
0
                       nExtBufXSizeReq, nExtBufYSizeReq, eSrcType, nSrcTypeSize,
1491
0
                       static_cast<GSpacing>(nSrcTypeSize) * nExtBufXSize,
1492
0
                       &sExtraArg, oWorkingState);
1493
1494
        // Extend first lines
1495
0
        for (int iY = 0; iY < nYShiftInBuffer; iY++)
1496
0
        {
1497
0
            memcpy(pabyBuffer +
1498
0
                       static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
1499
0
                   pabyBuffer + static_cast<size_t>(nYShiftInBuffer) *
1500
0
                                    nExtBufXSize * nSrcTypeSize,
1501
0
                   static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
1502
0
        }
1503
        // Extend last lines
1504
0
        for (int iY = nYShiftInBuffer + nExtBufYSizeReq; iY < nExtBufYSize;
1505
0
             iY++)
1506
0
        {
1507
0
            memcpy(pabyBuffer +
1508
0
                       static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
1509
0
                   pabyBuffer + static_cast<size_t>(nYShiftInBuffer +
1510
0
                                                    nExtBufYSizeReq - 1) *
1511
0
                                    nExtBufXSize * nSrcTypeSize,
1512
0
                   static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
1513
0
        }
1514
        // Extend first cols
1515
0
        if (nXShiftInBuffer)
1516
0
        {
1517
0
            for (int iY = 0; iY < nExtBufYSize; iY++)
1518
0
            {
1519
0
                for (int iX = 0; iX < nXShiftInBuffer; iX++)
1520
0
                {
1521
0
                    memcpy(pabyBuffer +
1522
0
                               static_cast<size_t>(iY * nExtBufXSize + iX) *
1523
0
                                   nSrcTypeSize,
1524
0
                           pabyBuffer +
1525
0
                               (static_cast<size_t>(iY) * nExtBufXSize +
1526
0
                                nXShiftInBuffer) *
1527
0
                                   nSrcTypeSize,
1528
0
                           nSrcTypeSize);
1529
0
                }
1530
0
            }
1531
0
        }
1532
        // Extent last cols
1533
0
        if (nXShiftInBuffer + nExtBufXSizeReq < nExtBufXSize)
1534
0
        {
1535
0
            for (int iY = 0; iY < nExtBufYSize; iY++)
1536
0
            {
1537
0
                for (int iX = nXShiftInBuffer + nExtBufXSizeReq;
1538
0
                     iX < nExtBufXSize; iX++)
1539
0
                {
1540
0
                    memcpy(pabyBuffer +
1541
0
                               (static_cast<size_t>(iY) * nExtBufXSize + iX) *
1542
0
                                   nSrcTypeSize,
1543
0
                           pabyBuffer +
1544
0
                               (static_cast<size_t>(iY) * nExtBufXSize +
1545
0
                                nXShiftInBuffer + nExtBufXSizeReq - 1) *
1546
0
                                   nSrcTypeSize,
1547
0
                           nSrcTypeSize);
1548
0
                }
1549
0
            }
1550
0
        }
1551
0
    }
1552
1553
    // Collect any pixel function arguments into oAdditionalArgs
1554
0
    if (poPixelFunc != nullptr && !poPixelFunc->second.empty())
1555
0
    {
1556
0
        if (GetPixelFunctionArguments(poPixelFunc->second,
1557
0
                                      anMapBufferIdxToSourceIdx, nXOff, nYOff,
1558
0
                                      oAdditionalArgs) != CE_None)
1559
0
        {
1560
0
            eErr = CE_Failure;
1561
0
        }
1562
0
    }
1563
1564
    // Apply pixel function.
1565
0
    const int nBufferCount = static_cast<int>(anMapBufferIdxToSourceIdx.size());
1566
0
    if (eErr == CE_None && EQUAL(m_poPrivate->m_osLanguage, "Python"))
1567
0
    {
1568
        // numpy doesn't have native cint16/cint32/cfloat16
1569
0
        if (eSrcType == GDT_CInt16 || eSrcType == GDT_CInt32 ||
1570
0
            eSrcType == GDT_CFloat16)
1571
0
        {
1572
0
            CPLError(CE_Failure, CPLE_AppDefined,
1573
0
                     "CInt16/CInt32/CFloat16 data type not supported for "
1574
0
                     "SourceTransferType");
1575
0
            return CE_Failure;
1576
0
        }
1577
0
        if (eDataType == GDT_CInt16 || eDataType == GDT_CInt32 ||
1578
0
            eDataType == GDT_CFloat16)
1579
0
        {
1580
0
            CPLError(
1581
0
                CE_Failure, CPLE_AppDefined,
1582
0
                "CInt16/CInt32/CFloat16 data type not supported for data type");
1583
0
            return CE_Failure;
1584
0
        }
1585
1586
0
        if (!InitializePython())
1587
0
            return CE_Failure;
1588
1589
0
        std::unique_ptr<GByte, VSIFreeReleaser> pabyTmpBuffer;
1590
        // Do we need a temporary buffer or can we use directly the output
1591
        // buffer ?
1592
0
        if (nBufferRadius != 0 || eDataType != eBufType ||
1593
0
            nPixelSpace != nBufTypeSize ||
1594
0
            nLineSpace != static_cast<GSpacing>(nBufTypeSize) * nBufXSize)
1595
0
        {
1596
0
            pabyTmpBuffer.reset(static_cast<GByte *>(VSI_CALLOC_VERBOSE(
1597
0
                static_cast<size_t>(nExtBufXSize) * nExtBufYSize,
1598
0
                GDALGetDataTypeSizeBytes(eDataType))));
1599
0
            if (!pabyTmpBuffer)
1600
0
                return CE_Failure;
1601
0
        }
1602
1603
0
        {
1604
0
            const bool bUseExclusiveLock =
1605
0
                m_poPrivate->m_bExclusiveLock ||
1606
0
                (m_poPrivate->m_bFirstTime &&
1607
0
                 m_poPrivate->m_osCode.find("@jit") != std::string::npos);
1608
0
            m_poPrivate->m_bFirstTime = false;
1609
0
            GIL_Holder oHolder(bUseExclusiveLock);
1610
1611
            // Prepare target numpy array
1612
0
            PyObject *poPyDstArray = GDALCreateNumpyArray(
1613
0
                m_poPrivate->m_poGDALCreateNumpyArray,
1614
0
                pabyTmpBuffer ? pabyTmpBuffer.get() : pData, eDataType,
1615
0
                nExtBufYSize, nExtBufXSize);
1616
0
            if (!poPyDstArray)
1617
0
            {
1618
0
                return CE_Failure;
1619
0
            }
1620
1621
            // Wrap source buffers as input numpy arrays
1622
0
            PyObject *pyArgInputArray = PyTuple_New(nBufferCount);
1623
0
            for (int i = 0; i < nBufferCount; i++)
1624
0
            {
1625
0
                GByte *pabyBuffer = static_cast<GByte *>(apBuffers[i].get());
1626
0
                PyObject *poPySrcArray = GDALCreateNumpyArray(
1627
0
                    m_poPrivate->m_poGDALCreateNumpyArray, pabyBuffer, eSrcType,
1628
0
                    nExtBufYSize, nExtBufXSize);
1629
0
                CPLAssert(poPySrcArray);
1630
0
                PyTuple_SetItem(pyArgInputArray, i, poPySrcArray);
1631
0
            }
1632
1633
            // Create arguments
1634
0
            PyObject *pyArgs = PyTuple_New(10);
1635
0
            PyTuple_SetItem(pyArgs, 0, pyArgInputArray);
1636
0
            PyTuple_SetItem(pyArgs, 1, poPyDstArray);
1637
0
            PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(nXOff));
1638
0
            PyTuple_SetItem(pyArgs, 3, PyLong_FromLong(nYOff));
1639
0
            PyTuple_SetItem(pyArgs, 4, PyLong_FromLong(nXSize));
1640
0
            PyTuple_SetItem(pyArgs, 5, PyLong_FromLong(nYSize));
1641
0
            PyTuple_SetItem(pyArgs, 6, PyLong_FromLong(nRasterXSize));
1642
0
            PyTuple_SetItem(pyArgs, 7, PyLong_FromLong(nRasterYSize));
1643
0
            PyTuple_SetItem(pyArgs, 8, PyLong_FromLong(nBufferRadius));
1644
1645
0
            GDALGeoTransform gt;
1646
0
            if (GetDataset())
1647
0
                GetDataset()->GetGeoTransform(gt);
1648
0
            PyObject *pyGT = PyTuple_New(6);
1649
0
            for (int i = 0; i < 6; i++)
1650
0
                PyTuple_SetItem(pyGT, i, PyFloat_FromDouble(gt[i]));
1651
0
            PyTuple_SetItem(pyArgs, 9, pyGT);
1652
1653
            // Prepare kwargs
1654
0
            PyObject *pyKwargs = PyDict_New();
1655
0
            for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
1656
0
            {
1657
0
                const char *pszKey =
1658
0
                    m_poPrivate->m_oFunctionArgs[i].first.c_str();
1659
0
                const char *pszValue =
1660
0
                    m_poPrivate->m_oFunctionArgs[i].second.c_str();
1661
0
                PyDict_SetItemString(
1662
0
                    pyKwargs, pszKey,
1663
0
                    PyBytes_FromStringAndSize(pszValue, strlen(pszValue)));
1664
0
            }
1665
1666
            // Call user function
1667
0
            PyObject *pRetValue =
1668
0
                PyObject_Call(m_poPrivate->m_poUserFunction, pyArgs, pyKwargs);
1669
1670
0
            Py_DecRef(pyArgs);
1671
0
            Py_DecRef(pyKwargs);
1672
1673
0
            if (ErrOccurredEmitCPLError())
1674
0
            {
1675
0
                eErr = CE_Failure;
1676
0
            }
1677
0
            if (pRetValue)
1678
0
                Py_DecRef(pRetValue);
1679
0
        }  // End of GIL section
1680
1681
0
        if (pabyTmpBuffer)
1682
0
        {
1683
            // Copy numpy destination array to user buffer
1684
0
            for (int iY = 0; iY < nBufYSize; iY++)
1685
0
            {
1686
0
                size_t nSrcOffset =
1687
0
                    (static_cast<size_t>(iY + nBufferRadius) * nExtBufXSize +
1688
0
                     nBufferRadius) *
1689
0
                    GDALGetDataTypeSizeBytes(eDataType);
1690
0
                GDALCopyWords64(pabyTmpBuffer.get() + nSrcOffset, eDataType,
1691
0
                                GDALGetDataTypeSizeBytes(eDataType),
1692
0
                                static_cast<GByte *>(pData) + iY * nLineSpace,
1693
0
                                eBufType, static_cast<int>(nPixelSpace),
1694
0
                                nBufXSize);
1695
0
            }
1696
0
        }
1697
0
    }
1698
0
    else if (eErr == CE_None && poPixelFunc != nullptr)
1699
0
    {
1700
0
        CPLStringList aosArgs;
1701
1702
        // Apply arguments specified using <PixelFunctionArguments>
1703
0
        for (const auto &[pszKey, pszValue] : m_poPrivate->m_oFunctionArgs)
1704
0
        {
1705
0
            aosArgs.SetNameValue(pszKey, pszValue);
1706
0
        }
1707
1708
        // Apply built-in arguments, potentially overwriting those in <PixelFunctionArguments>
1709
        // This is important because some pixel functions rely on built-in arguments being
1710
        // properly formatted, or even being a valid pointer. If a user can override these, we could have a crash.
1711
0
        for (const auto &[pszKey, pszValue] : oAdditionalArgs)
1712
0
        {
1713
0
            aosArgs.SetNameValue(pszKey, pszValue);
1714
0
        }
1715
1716
0
        static_assert(sizeof(apBuffers[0]) == sizeof(void *));
1717
0
        eErr = (poPixelFunc->first)(
1718
            // We cast vector<unique_ptr<void>>.data() as void**. This is OK
1719
            // given above static_assert
1720
0
            reinterpret_cast<void **>(apBuffers.data()), nBufferCount, pData,
1721
0
            nBufXSize, nBufYSize, eSrcType, eBufType,
1722
0
            static_cast<int>(nPixelSpace), static_cast<int>(nLineSpace),
1723
0
            aosArgs.List());
1724
0
    }
1725
1726
0
    return eErr;
1727
0
}
1728
1729
/************************************************************************/
1730
/*                       IGetDataCoverageStatus()                       */
1731
/************************************************************************/
1732
1733
int VRTDerivedRasterBand::IGetDataCoverageStatus(
1734
    int /* nXOff */, int /* nYOff */, int /* nXSize */, int /* nYSize */,
1735
    int /* nMaskFlagStop */, double *pdfDataPct)
1736
0
{
1737
0
    if (pdfDataPct != nullptr)
1738
0
        *pdfDataPct = -1.0;
1739
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
1740
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
1741
0
}
1742
1743
/************************************************************************/
1744
/*                              XMLInit()                               */
1745
/************************************************************************/
1746
1747
CPLErr VRTDerivedRasterBand::XMLInit(const CPLXMLNode *psTree,
1748
                                     const char *pszVRTPath,
1749
                                     VRTMapSharedResources &oMapSharedSources)
1750
1751
0
{
1752
0
    const CPLErr eErr =
1753
0
        VRTSourcedRasterBand::XMLInit(psTree, pszVRTPath, oMapSharedSources);
1754
0
    if (eErr != CE_None)
1755
0
        return eErr;
1756
1757
    // Read derived pixel function type.
1758
0
    SetPixelFunctionName(CPLGetXMLValue(psTree, "PixelFunctionType", nullptr));
1759
0
    if (osFuncName.empty())
1760
0
    {
1761
0
        CPLError(CE_Failure, CPLE_AppDefined, "PixelFunctionType missing");
1762
0
        return CE_Failure;
1763
0
    }
1764
1765
0
    m_poPrivate->m_osLanguage =
1766
0
        CPLGetXMLValue(psTree, "PixelFunctionLanguage", "C");
1767
0
    if (!EQUAL(m_poPrivate->m_osLanguage, "C") &&
1768
0
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1769
0
    {
1770
0
        CPLError(CE_Failure, CPLE_NotSupported,
1771
0
                 "Unsupported PixelFunctionLanguage");
1772
0
        return CE_Failure;
1773
0
    }
1774
1775
0
    m_poPrivate->m_osCode = CPLGetXMLValue(psTree, "PixelFunctionCode", "");
1776
0
    if (!m_poPrivate->m_osCode.empty() &&
1777
0
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1778
0
    {
1779
0
        CPLError(CE_Failure, CPLE_NotSupported,
1780
0
                 "PixelFunctionCode can only be used with Python");
1781
0
        return CE_Failure;
1782
0
    }
1783
1784
0
    m_poPrivate->m_nBufferRadius =
1785
0
        atoi(CPLGetXMLValue(psTree, "BufferRadius", "0"));
1786
0
    if (m_poPrivate->m_nBufferRadius < 0 || m_poPrivate->m_nBufferRadius > 1024)
1787
0
    {
1788
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for BufferRadius");
1789
0
        return CE_Failure;
1790
0
    }
1791
0
    if (m_poPrivate->m_nBufferRadius != 0 &&
1792
0
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1793
0
    {
1794
0
        CPLError(CE_Failure, CPLE_NotSupported,
1795
0
                 "BufferRadius can only be used with Python");
1796
0
        return CE_Failure;
1797
0
    }
1798
1799
0
    const CPLXMLNode *const psArgs =
1800
0
        CPLGetXMLNode(psTree, "PixelFunctionArguments");
1801
0
    if (psArgs != nullptr)
1802
0
    {
1803
0
        for (const CPLXMLNode *psIter = psArgs->psChild; psIter;
1804
0
             psIter = psIter->psNext)
1805
0
        {
1806
0
            if (psIter->eType == CXT_Attribute)
1807
0
            {
1808
0
                AddPixelFunctionArgument(psIter->pszValue,
1809
0
                                         psIter->psChild->pszValue);
1810
0
            }
1811
0
        }
1812
0
    }
1813
1814
    // Read optional source transfer data type.
1815
0
    const char *pszTypeName =
1816
0
        CPLGetXMLValue(psTree, "SourceTransferType", nullptr);
1817
0
    if (pszTypeName != nullptr)
1818
0
    {
1819
0
        eSourceTransferType = GDALGetDataTypeByName(pszTypeName);
1820
0
    }
1821
1822
    // Whether to skip non contributing sources
1823
0
    const char *pszSkipNonContributingSources =
1824
0
        CPLGetXMLValue(psTree, "SkipNonContributingSources", nullptr);
1825
0
    if (pszSkipNonContributingSources)
1826
0
    {
1827
0
        SetSkipNonContributingSources(
1828
0
            CPLTestBool(pszSkipNonContributingSources));
1829
0
    }
1830
1831
0
    return CE_None;
1832
0
}
1833
1834
/************************************************************************/
1835
/*                           SerializeToXML()                           */
1836
/************************************************************************/
1837
1838
CPLXMLNode *VRTDerivedRasterBand::SerializeToXML(const char *pszVRTPath,
1839
                                                 bool &bHasWarnedAboutRAMUsage,
1840
                                                 size_t &nAccRAMUsage)
1841
0
{
1842
0
    CPLXMLNode *psTree = VRTSourcedRasterBand::SerializeToXML(
1843
0
        pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
1844
1845
    /* -------------------------------------------------------------------- */
1846
    /*      Set subclass.                                                   */
1847
    /* -------------------------------------------------------------------- */
1848
0
    CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "subClass"),
1849
0
                     CXT_Text, "VRTDerivedRasterBand");
1850
1851
    /* ---- Encode DerivedBand-specific fields ---- */
1852
0
    if (!EQUAL(m_poPrivate->m_osLanguage, "C"))
1853
0
    {
1854
0
        CPLSetXMLValue(psTree, "PixelFunctionLanguage",
1855
0
                       m_poPrivate->m_osLanguage);
1856
0
    }
1857
0
    if (!osFuncName.empty())
1858
0
        CPLSetXMLValue(psTree, "PixelFunctionType", osFuncName.c_str());
1859
0
    if (!m_poPrivate->m_oFunctionArgs.empty())
1860
0
    {
1861
0
        CPLXMLNode *psArgs =
1862
0
            CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionArguments");
1863
0
        for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
1864
0
        {
1865
0
            const char *pszKey = m_poPrivate->m_oFunctionArgs[i].first.c_str();
1866
0
            const char *pszValue =
1867
0
                m_poPrivate->m_oFunctionArgs[i].second.c_str();
1868
0
            CPLCreateXMLNode(CPLCreateXMLNode(psArgs, CXT_Attribute, pszKey),
1869
0
                             CXT_Text, pszValue);
1870
0
        }
1871
0
    }
1872
0
    if (!m_poPrivate->m_osCode.empty())
1873
0
    {
1874
0
        if (m_poPrivate->m_osCode.find("<![CDATA[") == std::string::npos)
1875
0
        {
1876
0
            CPLCreateXMLNode(
1877
0
                CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionCode"),
1878
0
                CXT_Literal,
1879
0
                ("<![CDATA[" + m_poPrivate->m_osCode + "]]>").c_str());
1880
0
        }
1881
0
        else
1882
0
        {
1883
0
            CPLSetXMLValue(psTree, "PixelFunctionCode", m_poPrivate->m_osCode);
1884
0
        }
1885
0
    }
1886
0
    if (m_poPrivate->m_nBufferRadius != 0)
1887
0
        CPLSetXMLValue(psTree, "BufferRadius",
1888
0
                       CPLSPrintf("%d", m_poPrivate->m_nBufferRadius));
1889
0
    if (this->eSourceTransferType != GDT_Unknown)
1890
0
        CPLSetXMLValue(psTree, "SourceTransferType",
1891
0
                       GDALGetDataTypeName(eSourceTransferType));
1892
1893
0
    if (m_poPrivate->m_bSkipNonContributingSourcesSpecified)
1894
0
    {
1895
0
        CPLSetXMLValue(psTree, "SkipNonContributingSources",
1896
0
                       m_poPrivate->m_bSkipNonContributingSources ? "true"
1897
0
                                                                  : "false");
1898
0
    }
1899
1900
0
    return psTree;
1901
0
}
1902
1903
/************************************************************************/
1904
/*                             GetMinimum()                             */
1905
/************************************************************************/
1906
1907
double VRTDerivedRasterBand::GetMinimum(int *pbSuccess)
1908
0
{
1909
0
    return GDALRasterBand::GetMinimum(pbSuccess);
1910
0
}
1911
1912
/************************************************************************/
1913
/*                             GetMaximum()                             */
1914
/************************************************************************/
1915
1916
double VRTDerivedRasterBand::GetMaximum(int *pbSuccess)
1917
0
{
1918
0
    return GDALRasterBand::GetMaximum(pbSuccess);
1919
0
}
1920
1921
/************************************************************************/
1922
/*                        ComputeRasterMinMax()                         */
1923
/************************************************************************/
1924
1925
CPLErr VRTDerivedRasterBand::ComputeRasterMinMax(int bApproxOK,
1926
                                                 double *adfMinMax)
1927
0
{
1928
0
    return GDALRasterBand::ComputeRasterMinMax(bApproxOK, adfMinMax);
1929
0
}
1930
1931
/************************************************************************/
1932
/*                         ComputeStatistics()                          */
1933
/************************************************************************/
1934
1935
CPLErr VRTDerivedRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
1936
                                               double *pdfMax, double *pdfMean,
1937
                                               double *pdfStdDev,
1938
                                               GDALProgressFunc pfnProgress,
1939
                                               void *pProgressData)
1940
1941
0
{
1942
0
    return GDALRasterBand::ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
1943
0
                                             pdfStdDev, pfnProgress,
1944
0
                                             pProgressData);
1945
0
}
1946
1947
/************************************************************************/
1948
/*                            GetHistogram()                            */
1949
/************************************************************************/
1950
1951
CPLErr VRTDerivedRasterBand::GetHistogram(double dfMin, double dfMax,
1952
                                          int nBuckets, GUIntBig *panHistogram,
1953
                                          int bIncludeOutOfRange, int bApproxOK,
1954
                                          GDALProgressFunc pfnProgress,
1955
                                          void *pProgressData)
1956
1957
0
{
1958
0
    return VRTRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
1959
0
                                       bIncludeOutOfRange, bApproxOK,
1960
0
                                       pfnProgress, pProgressData);
1961
0
}
1962
1963
/*! @endcond */