Coverage Report

Created: 2025-08-28 06:57

/src/gdal/frmts/vrt/vrtderivedrasterband.cpp
Line
Count
Source (jump to first uncovered line)
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
0
#define GDAL_VRT_ENABLE_PYTHON_DEFAULT "TRUSTED_MODULES"
36
#endif
37
38
/* Flags for getting buffers */
39
0
#define PyBUF_WRITABLE 0x0001
40
0
#define PyBUF_FORMAT 0x0004
41
0
#define PyBUF_ND 0x0008
42
0
#define PyBUF_STRIDES (0x0010 | PyBUF_ND)
43
0
#define PyBUF_INDIRECT (0x0100 | PyBUF_STRIDES)
44
0
#define PyBUF_FULL (PyBUF_INDIRECT | PyBUF_WRITABLE | PyBUF_FORMAT)
45
46
/************************************************************************/
47
/*                        GDALCreateNumpyArray()                        */
48
/************************************************************************/
49
50
static PyObject *GDALCreateNumpyArray(PyObject *pCreateArray, void *pBuffer,
51
                                      GDALDataType eType, int nHeight,
52
                                      int nWidth)
53
0
{
54
0
    PyObject *poPyBuffer;
55
0
    const size_t nSize =
56
0
        static_cast<size_t>(nHeight) * nWidth * GDALGetDataTypeSizeBytes(eType);
57
0
    Py_buffer pybuffer;
58
0
    if (PyBuffer_FillInfo(&pybuffer, nullptr, static_cast<char *>(pBuffer),
59
0
                          nSize, 0, PyBUF_FULL) != 0)
60
0
    {
61
0
        return nullptr;
62
0
    }
63
0
    poPyBuffer = PyMemoryView_FromBuffer(&pybuffer);
64
0
    PyObject *pArgsCreateArray = PyTuple_New(4);
65
0
    PyTuple_SetItem(pArgsCreateArray, 0, poPyBuffer);
66
0
    const char *pszDataType = nullptr;
67
0
    switch (eType)
68
0
    {
69
0
        case GDT_Byte:
70
0
            pszDataType = "uint8";
71
0
            break;
72
0
        case GDT_Int8:
73
0
            pszDataType = "int8";
74
0
            break;
75
0
        case GDT_UInt16:
76
0
            pszDataType = "uint16";
77
0
            break;
78
0
        case GDT_Int16:
79
0
            pszDataType = "int16";
80
0
            break;
81
0
        case GDT_UInt32:
82
0
            pszDataType = "uint32";
83
0
            break;
84
0
        case GDT_Int32:
85
0
            pszDataType = "int32";
86
0
            break;
87
0
        case GDT_Int64:
88
0
            pszDataType = "int64";
89
0
            break;
90
0
        case GDT_UInt64:
91
0
            pszDataType = "uint64";
92
0
            break;
93
0
        case GDT_Float16:
94
0
            pszDataType = "float16";
95
0
            break;
96
0
        case GDT_Float32:
97
0
            pszDataType = "float32";
98
0
            break;
99
0
        case GDT_Float64:
100
0
            pszDataType = "float64";
101
0
            break;
102
0
        case GDT_CInt16:
103
0
        case GDT_CInt32:
104
0
            CPLAssert(FALSE);
105
0
            break;
106
0
        case GDT_CFloat16:
107
0
            CPLAssert(FALSE);
108
0
            break;
109
0
        case GDT_CFloat32:
110
0
            pszDataType = "complex64";
111
0
            break;
112
0
        case GDT_CFloat64:
113
0
            pszDataType = "complex128";
114
0
            break;
115
0
        case GDT_Unknown:
116
0
        case GDT_TypeCount:
117
0
            CPLAssert(FALSE);
118
0
            break;
119
0
    }
120
0
    PyTuple_SetItem(
121
0
        pArgsCreateArray, 1,
122
0
        PyBytes_FromStringAndSize(pszDataType, strlen(pszDataType)));
123
0
    PyTuple_SetItem(pArgsCreateArray, 2, PyLong_FromLong(nHeight));
124
0
    PyTuple_SetItem(pArgsCreateArray, 3, PyLong_FromLong(nWidth));
125
0
    PyObject *poNumpyArray =
126
0
        PyObject_Call(pCreateArray, pArgsCreateArray, nullptr);
127
0
    Py_DecRef(pArgsCreateArray);
128
0
    if (PyErr_Occurred())
129
0
        PyErr_Print();
130
0
    return poNumpyArray;
131
0
}
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()
162
0
        : m_nAllowedRAMUsage(CPLGetUsablePhysicalRAM() / 10 * 4)
163
0
    {
164
        // Use only up to 40% of RAM to acquire source bands and generate the
165
        // output buffer.
166
        // Only for tests now
167
0
        const char *pszMAX_RAM = "VRT_DERIVED_DATASET_ALLOWED_RAM_USAGE";
168
0
        if (const char *pszVal = CPLGetConfigOption(pszMAX_RAM, nullptr))
169
0
        {
170
0
            CPL_IGNORE_RET_VAL(
171
0
                CPLParseMemorySize(pszVal, &m_nAllowedRAMUsage, nullptr));
172
0
        }
173
0
    }
174
175
    ~VRTDerivedRasterBandPrivateData();
176
};
177
178
VRTDerivedRasterBandPrivateData::~VRTDerivedRasterBandPrivateData()
179
0
{
180
0
    if (m_poGDALCreateNumpyArray)
181
0
        Py_DecRef(m_poGDALCreateNumpyArray);
182
0
    if (m_poUserFunction)
183
0
        Py_DecRef(m_poUserFunction);
184
0
}
185
186
/************************************************************************/
187
/* ==================================================================== */
188
/*                          VRTDerivedRasterBand                        */
189
/* ==================================================================== */
190
/************************************************************************/
191
192
/************************************************************************/
193
/*                        VRTDerivedRasterBand()                        */
194
/************************************************************************/
195
196
VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn)
197
0
    : VRTSourcedRasterBand(poDSIn, nBandIn), m_poPrivate(nullptr),
198
0
      eSourceTransferType(GDT_Unknown)
199
0
{
200
0
    m_poPrivate = new VRTDerivedRasterBandPrivateData;
201
0
}
202
203
/************************************************************************/
204
/*                        VRTDerivedRasterBand()                        */
205
/************************************************************************/
206
207
VRTDerivedRasterBand::VRTDerivedRasterBand(GDALDataset *poDSIn, int nBandIn,
208
                                           GDALDataType eType, int nXSize,
209
                                           int nYSize, int nBlockXSizeIn,
210
                                           int nBlockYSizeIn)
211
0
    : VRTSourcedRasterBand(poDSIn, nBandIn, eType, nXSize, nYSize,
212
0
                           nBlockXSizeIn, nBlockYSizeIn),
213
0
      m_poPrivate(nullptr), eSourceTransferType(GDT_Unknown)
214
0
{
215
0
    m_poPrivate = new VRTDerivedRasterBandPrivateData;
216
0
}
217
218
/************************************************************************/
219
/*                       ~VRTDerivedRasterBand()                        */
220
/************************************************************************/
221
222
VRTDerivedRasterBand::~VRTDerivedRasterBand()
223
224
0
{
225
0
    delete m_poPrivate;
226
0
}
227
228
/************************************************************************/
229
/*                               Cleanup()                              */
230
/************************************************************************/
231
232
void VRTDerivedRasterBand::Cleanup()
233
0
{
234
0
}
235
236
/************************************************************************/
237
/*                      GetGlobalMapPixelFunction()                     */
238
/************************************************************************/
239
240
static std::map<std::string,
241
                std::pair<VRTDerivedRasterBand::PixelFunc, std::string>> &
242
GetGlobalMapPixelFunction()
243
0
{
244
0
    static std::map<std::string,
245
0
                    std::pair<VRTDerivedRasterBand::PixelFunc, std::string>>
246
0
        gosMapPixelFunction;
247
0
    return gosMapPixelFunction;
248
0
}
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(
273
    const char *pszName, GDALDerivedPixelFunc pfnNewFunction)
274
0
{
275
0
    if (pszName == nullptr || pszName[0] == '\0' || pfnNewFunction == nullptr)
276
0
    {
277
0
        return CE_None;
278
0
    }
279
280
0
    GetGlobalMapPixelFunction()[pszName] = {
281
0
        [pfnNewFunction](void **papoSources, int nSources, void *pData,
282
0
                         int nBufXSize, int nBufYSize, GDALDataType eSrcType,
283
0
                         GDALDataType eBufType, int nPixelSpace, int nLineSpace,
284
0
                         CSLConstList papszFunctionArgs)
285
0
        {
286
0
            (void)papszFunctionArgs;
287
0
            return pfnNewFunction(papoSources, nSources, pData, nBufXSize,
288
0
                                  nBufYSize, eSrcType, eBufType, nPixelSpace,
289
0
                                  nLineSpace);
290
0
        },
291
0
        ""};
292
293
0
    return CE_None;
294
0
}
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(
315
    const char *pszName, GDALDerivedPixelFuncWithArgs pfnNewFunction,
316
    const char *pszMetadata)
317
0
{
318
0
    if (!pszName || pszName[0] == '\0' || !pfnNewFunction)
319
0
    {
320
0
        return CE_None;
321
0
    }
322
323
0
    GetGlobalMapPixelFunction()[pszName] = {pfnNewFunction,
324
0
                                            pszMetadata ? pszMetadata : ""};
325
326
0
    return CE_None;
327
0
}
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
0
{
348
0
    return GDALAddDerivedBandPixelFunc(pszFuncNameIn, pfnNewFunction);
349
0
}
350
351
CPLErr VRTDerivedRasterBand::AddPixelFunction(
352
    const char *pszFuncNameIn, GDALDerivedPixelFuncWithArgs pfnNewFunction,
353
    const char *pszMetadata)
354
0
{
355
0
    return GDALAddDerivedBandPixelFuncWithArgs(pszFuncNameIn, pfnNewFunction,
356
0
                                               pszMetadata);
357
0
}
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)
377
0
{
378
0
    if (pszFuncNameIn == nullptr || pszFuncNameIn[0] == '\0')
379
0
    {
380
0
        return nullptr;
381
0
    }
382
383
0
    const auto &oMapPixelFunction = GetGlobalMapPixelFunction();
384
0
    const auto oIter = oMapPixelFunction.find(pszFuncNameIn);
385
386
0
    if (oIter == oMapPixelFunction.end())
387
0
        return nullptr;
388
389
0
    return &(oIter->second);
390
0
}
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()
401
0
{
402
0
    std::vector<std::string> res;
403
0
    for (const auto &iter : GetGlobalMapPixelFunction())
404
0
    {
405
0
        res.push_back(iter.first);
406
0
    }
407
0
    return res;
408
0
}
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)
422
0
{
423
0
    osFuncName = (pszFuncNameIn == nullptr) ? "" : pszFuncNameIn;
424
0
}
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,
438
                                                    const char *pszValue)
439
0
{
440
0
    m_poPrivate->m_oFunctionArgs.emplace_back(pszArg, pszValue);
441
0
}
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)
455
0
{
456
0
    m_poPrivate->m_osLanguage = pszLanguage;
457
0
}
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)
474
0
{
475
0
    m_poPrivate->m_bSkipNonContributingSources = bSkip;
476
0
    m_poPrivate->m_bSkipNonContributingSourcesSpecified = true;
477
0
}
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)
495
0
{
496
0
    eSourceTransferType = eDataTypeIn;
497
0
}
498
499
/************************************************************************/
500
/*                           InitializePython()                         */
501
/************************************************************************/
502
503
bool VRTDerivedRasterBand::InitializePython()
504
0
{
505
0
    if (m_poPrivate->m_bPythonInitializationDone)
506
0
        return m_poPrivate->m_bPythonInitializationSuccess;
507
508
0
    m_poPrivate->m_bPythonInitializationDone = true;
509
0
    m_poPrivate->m_bPythonInitializationSuccess = false;
510
511
0
    const size_t nIdxDot = osFuncName.rfind(".");
512
0
    CPLString osPythonModule;
513
0
    CPLString osPythonFunction;
514
0
    if (nIdxDot != std::string::npos)
515
0
    {
516
0
        osPythonModule = osFuncName.substr(0, nIdxDot);
517
0
        osPythonFunction = osFuncName.substr(nIdxDot + 1);
518
0
    }
519
0
    else
520
0
    {
521
0
        osPythonFunction = osFuncName;
522
0
    }
523
524
0
#ifndef GDAL_VRT_DISABLE_PYTHON
525
0
    const char *pszPythonEnabled =
526
0
        CPLGetConfigOption("GDAL_VRT_ENABLE_PYTHON", nullptr);
527
#else
528
    const char *pszPythonEnabled = "NO";
529
#endif
530
0
    const CPLString osPythonEnabled(
531
0
        pszPythonEnabled ? pszPythonEnabled : GDAL_VRT_ENABLE_PYTHON_DEFAULT);
532
533
0
    if (EQUAL(osPythonEnabled, "TRUSTED_MODULES"))
534
0
    {
535
0
        bool bIsTrustedModule = false;
536
0
        const CPLString osVRTTrustedModules(
537
0
            CPLGetConfigOption("GDAL_VRT_PYTHON_TRUSTED_MODULES", ""));
538
0
        if (!osPythonModule.empty())
539
0
        {
540
0
            char **papszTrustedModules =
541
0
                CSLTokenizeString2(osVRTTrustedModules, ",", 0);
542
0
            for (char **papszIter = papszTrustedModules;
543
0
                 !bIsTrustedModule && papszIter && *papszIter; ++papszIter)
544
0
            {
545
0
                const char *pszIterModule = *papszIter;
546
0
                size_t nIterModuleLen = strlen(pszIterModule);
547
0
                if (nIterModuleLen > 2 &&
548
0
                    strncmp(pszIterModule + nIterModuleLen - 2, ".*", 2) == 0)
549
0
                {
550
0
                    bIsTrustedModule =
551
0
                        (strncmp(osPythonModule, pszIterModule,
552
0
                                 nIterModuleLen - 2) == 0) &&
553
0
                        (osPythonModule.size() == nIterModuleLen - 2 ||
554
0
                         (osPythonModule.size() >= nIterModuleLen &&
555
0
                          osPythonModule[nIterModuleLen - 1] == '.'));
556
0
                }
557
0
                else if (nIterModuleLen >= 1 &&
558
0
                         pszIterModule[nIterModuleLen - 1] == '*')
559
0
                {
560
0
                    bIsTrustedModule = (strncmp(osPythonModule, pszIterModule,
561
0
                                                nIterModuleLen - 1) == 0);
562
0
                }
563
0
                else
564
0
                {
565
0
                    bIsTrustedModule =
566
0
                        (strcmp(osPythonModule, pszIterModule) == 0);
567
0
                }
568
0
            }
569
0
            CSLDestroy(papszTrustedModules);
570
0
        }
571
572
0
        if (!bIsTrustedModule)
573
0
        {
574
0
            if (osPythonModule.empty())
575
0
            {
576
0
                CPLError(
577
0
                    CE_Failure, CPLE_AppDefined,
578
0
                    "Python code needs to be executed, but it uses inline code "
579
0
                    "in the VRT whereas the current policy is to trust only "
580
0
                    "code from external trusted modules (defined in the "
581
0
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
582
0
                    "If you trust the code in %s, you can set the "
583
0
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES.",
584
0
                    GetDataset() ? GetDataset()->GetDescription()
585
0
                                 : "(unknown VRT)");
586
0
            }
587
0
            else if (osVRTTrustedModules.empty())
588
0
            {
589
0
                CPLError(
590
0
                    CE_Failure, CPLE_AppDefined,
591
0
                    "Python code needs to be executed, but it uses code "
592
0
                    "from module '%s', whereas the current policy is to "
593
0
                    "trust only code from modules defined in the "
594
0
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option, "
595
0
                    "which is currently unset. "
596
0
                    "If you trust the code in '%s', you can add module '%s' "
597
0
                    "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
598
0
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
599
0
                    osPythonModule.c_str(),
600
0
                    GetDataset() ? GetDataset()->GetDescription()
601
0
                                 : "(unknown VRT)",
602
0
                    osPythonModule.c_str());
603
0
            }
604
0
            else
605
0
            {
606
0
                CPLError(
607
0
                    CE_Failure, CPLE_AppDefined,
608
0
                    "Python code needs to be executed, but it uses code "
609
0
                    "from module '%s', whereas the current policy is to "
610
0
                    "trust only code from modules '%s' (defined in the "
611
0
                    "GDAL_VRT_PYTHON_TRUSTED_MODULES configuration option). "
612
0
                    "If you trust the code in '%s', you can add module '%s' "
613
0
                    "to GDAL_VRT_PYTHON_TRUSTED_MODULES (or set the "
614
0
                    "GDAL_VRT_ENABLE_PYTHON configuration option to YES).",
615
0
                    osPythonModule.c_str(), osVRTTrustedModules.c_str(),
616
0
                    GetDataset() ? GetDataset()->GetDescription()
617
0
                                 : "(unknown VRT)",
618
0
                    osPythonModule.c_str());
619
0
            }
620
0
            return false;
621
0
        }
622
0
    }
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
0
    else if (!EQUAL(osPythonEnabled, "YES") && !EQUAL(osPythonEnabled, "ON") &&
700
0
             !EQUAL(osPythonEnabled, "TRUE"))
701
0
    {
702
0
        if (pszPythonEnabled == nullptr)
703
0
        {
704
            // Note: this is dead code with our current default policy
705
            // GDAL_VRT_ENABLE_PYTHON == "TRUSTED_MODULES"
706
0
            CPLError(CE_Failure, CPLE_AppDefined,
707
0
                     "Python code needs to be executed, but this is "
708
0
                     "disabled by default. If you trust the code in %s, "
709
0
                     "you can set the GDAL_VRT_ENABLE_PYTHON configuration "
710
0
                     "option to YES.",
711
0
                     GetDataset() ? GetDataset()->GetDescription()
712
0
                                  : "(unknown VRT)");
713
0
        }
714
0
        else
715
0
        {
716
0
            CPLError(
717
0
                CE_Failure, CPLE_AppDefined,
718
0
                "Python code in %s needs to be executed, but this has been "
719
0
                "explicitly disabled.",
720
0
                GetDataset() ? GetDataset()->GetDescription()
721
0
                             : "(unknown VRT)");
722
0
        }
723
0
        return false;
724
0
    }
725
726
0
    if (!GDALPythonInitialize())
727
0
        return false;
728
729
    // Whether we should just use our own global mutex, in addition to Python
730
    // GIL locking.
731
0
    m_poPrivate->m_bExclusiveLock =
732
0
        CPLTestBool(CPLGetConfigOption("GDAL_VRT_PYTHON_EXCLUSIVE_LOCK", "NO"));
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
0
    const bool bUseExclusiveLock =
739
0
        m_poPrivate->m_bExclusiveLock ||
740
0
        m_poPrivate->m_osCode.find("@jit") != std::string::npos;
741
0
    GIL_Holder oHolder(bUseExclusiveLock);
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
0
    CPLString osModuleName(CPLSPrintf("gdal_vrt_module_%p", this));
750
0
    PyObject *poCompiledString = Py_CompileString(
751
0
        ("import numpy\n"
752
0
         "def GDALCreateNumpyArray(buffer, dtype, height, width):\n"
753
0
         "    return numpy.frombuffer(buffer, str(dtype.decode('ascii')))."
754
0
         "reshape([height, width])\n"
755
0
         "\n" +
756
0
         m_poPrivate->m_osCode)
757
0
            .c_str(),
758
0
        osModuleName, Py_file_input);
759
0
    if (poCompiledString == nullptr || PyErr_Occurred())
760
0
    {
761
0
        CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
762
0
                 GetPyExceptionString().c_str());
763
0
        return false;
764
0
    }
765
0
    PyObject *poModule =
766
0
        PyImport_ExecCodeModule(osModuleName, poCompiledString);
767
0
    Py_DecRef(poCompiledString);
768
769
0
    if (poModule == nullptr || PyErr_Occurred())
770
0
    {
771
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
772
0
                 GetPyExceptionString().c_str());
773
0
        return false;
774
0
    }
775
776
    // Fetch user computation function
777
0
    if (!osPythonModule.empty())
778
0
    {
779
0
        PyObject *poUserModule = PyImport_ImportModule(osPythonModule);
780
0
        if (poUserModule == nullptr || PyErr_Occurred())
781
0
        {
782
0
            CPLString osException = GetPyExceptionString();
783
0
            if (!osException.empty() && osException.back() == '\n')
784
0
            {
785
0
                osException.pop_back();
786
0
            }
787
0
            if (osException.find("ModuleNotFoundError") == 0)
788
0
            {
789
0
                osException += ". You may need to define PYTHONPATH";
790
0
            }
791
0
            CPLError(CE_Failure, CPLE_AppDefined, "%s", osException.c_str());
792
0
            Py_DecRef(poModule);
793
0
            return false;
794
0
        }
795
0
        m_poPrivate->m_poUserFunction =
796
0
            PyObject_GetAttrString(poUserModule, osPythonFunction);
797
0
        Py_DecRef(poUserModule);
798
0
    }
799
0
    else
800
0
    {
801
0
        m_poPrivate->m_poUserFunction =
802
0
            PyObject_GetAttrString(poModule, osPythonFunction);
803
0
    }
804
0
    if (m_poPrivate->m_poUserFunction == nullptr || PyErr_Occurred())
805
0
    {
806
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
807
0
                 GetPyExceptionString().c_str());
808
0
        Py_DecRef(poModule);
809
0
        return false;
810
0
    }
811
0
    if (!PyCallable_Check(m_poPrivate->m_poUserFunction))
812
0
    {
813
0
        CPLError(CE_Failure, CPLE_AppDefined, "Object '%s' is not callable",
814
0
                 osPythonFunction.c_str());
815
0
        Py_DecRef(poModule);
816
0
        return false;
817
0
    }
818
819
    // Fetch our GDALCreateNumpyArray python function
820
0
    m_poPrivate->m_poGDALCreateNumpyArray =
821
0
        PyObject_GetAttrString(poModule, "GDALCreateNumpyArray");
822
0
    if (m_poPrivate->m_poGDALCreateNumpyArray == nullptr || PyErr_Occurred())
823
0
    {
824
        // Shouldn't happen normally...
825
0
        CPLError(CE_Failure, CPLE_AppDefined, "%s",
826
0
                 GetPyExceptionString().c_str());
827
0
        Py_DecRef(poModule);
828
0
        return false;
829
0
    }
830
0
    Py_DecRef(poModule);
831
832
0
    m_poPrivate->m_bPythonInitializationSuccess = true;
833
0
    return true;
834
0
}
835
836
CPLErr VRTDerivedRasterBand::GetPixelFunctionArguments(
837
    const CPLString &osMetadata,
838
    const std::vector<int> &anMapBufferIdxToSourceIdx, int nXOff, int nYOff,
839
    std::vector<std::pair<CPLString, CPLString>> &oAdditionalArgs)
840
0
{
841
842
0
    auto poArgs = CPLXMLTreeCloser(CPLParseXMLString(osMetadata));
843
0
    if (poArgs != nullptr && poArgs->eType == CXT_Element &&
844
0
        !strcmp(poArgs->pszValue, "PixelFunctionArgumentsList"))
845
0
    {
846
0
        for (CPLXMLNode *psIter = poArgs->psChild; psIter != nullptr;
847
0
             psIter = psIter->psNext)
848
0
        {
849
0
            if (psIter->eType == CXT_Element &&
850
0
                !strcmp(psIter->pszValue, "Argument"))
851
0
            {
852
0
                CPLString osName, osType, osValue;
853
0
                auto pszName = CPLGetXMLValue(psIter, "name", nullptr);
854
0
                if (pszName != nullptr)
855
0
                    osName = pszName;
856
0
                auto pszType = CPLGetXMLValue(psIter, "type", nullptr);
857
0
                if (pszType != nullptr)
858
0
                    osType = pszType;
859
0
                auto pszValue = CPLGetXMLValue(psIter, "value", nullptr);
860
0
                if (pszValue != nullptr)
861
0
                    osValue = pszValue;
862
0
                if (osType == "constant" && osValue != "" && osName != "")
863
0
                    oAdditionalArgs.push_back(
864
0
                        std::pair<CPLString, CPLString>(osName, osValue));
865
0
                if (osType == "builtin")
866
0
                {
867
0
                    const CPLString &osArgName = osValue;
868
0
                    CPLString osVal;
869
0
                    double dfVal = 0;
870
871
0
                    int success(FALSE);
872
0
                    if (osArgName == "NoData")
873
0
                        dfVal = this->GetNoDataValue(&success);
874
0
                    else if (osArgName == "scale")
875
0
                        dfVal = this->GetScale(&success);
876
0
                    else if (osArgName == "offset")
877
0
                        dfVal = this->GetOffset(&success);
878
0
                    else if (osArgName == "xoff")
879
0
                    {
880
0
                        dfVal = static_cast<double>(nXOff);
881
0
                        success = true;
882
0
                    }
883
0
                    else if (osArgName == "yoff")
884
0
                    {
885
0
                        dfVal = static_cast<double>(nYOff);
886
0
                        success = true;
887
0
                    }
888
0
                    else if (osArgName == "geotransform")
889
0
                    {
890
0
                        GDALGeoTransform gt;
891
0
                        if (GetDataset()->GetGeoTransform(gt) != CE_None)
892
0
                        {
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
0
                            continue;
897
0
                        }
898
0
                        osVal = CPLSPrintf(
899
0
                            "%.17g,%.17g,%.17g,%.17g,%.17g,%.17g", gt[0], gt[1],
900
0
                            gt[2], gt[3], gt[4], gt[5]);
901
0
                        success = true;
902
0
                    }
903
0
                    else if (osArgName == "source_names")
904
0
                    {
905
0
                        for (size_t iBuffer = 0;
906
0
                             iBuffer < anMapBufferIdxToSourceIdx.size();
907
0
                             iBuffer++)
908
0
                        {
909
0
                            const int iSource =
910
0
                                anMapBufferIdxToSourceIdx[iBuffer];
911
0
                            const VRTSource *poSource =
912
0
                                m_papoSources[iSource].get();
913
914
0
                            if (iBuffer > 0)
915
0
                            {
916
0
                                osVal += "|";
917
0
                            }
918
919
0
                            const auto &osSourceName = poSource->GetName();
920
0
                            if (osSourceName.empty())
921
0
                            {
922
0
                                osVal += "B" + std::to_string(iBuffer + 1);
923
0
                            }
924
0
                            else
925
0
                            {
926
0
                                osVal += osSourceName;
927
0
                            }
928
0
                        }
929
930
0
                        success = true;
931
0
                    }
932
0
                    else
933
0
                    {
934
0
                        CPLError(
935
0
                            CE_Failure, CPLE_NotSupported,
936
0
                            "PixelFunction builtin argument %s not supported",
937
0
                            osArgName.c_str());
938
0
                        return CE_Failure;
939
0
                    }
940
0
                    if (!success)
941
0
                    {
942
0
                        if (CPLTestBool(
943
0
                                CPLGetXMLValue(psIter, "optional", "false")))
944
0
                            continue;
945
946
0
                        CPLError(CE_Failure, CPLE_AppDefined,
947
0
                                 "Raster has no %s", osValue.c_str());
948
0
                        return CE_Failure;
949
0
                    }
950
951
0
                    if (osVal.empty())
952
0
                    {
953
0
                        osVal = CPLSPrintf("%.17g", dfVal);
954
0
                    }
955
956
0
                    oAdditionalArgs.push_back(
957
0
                        std::pair<CPLString, CPLString>(osArgName, osVal));
958
0
                    CPLDebug("VRT",
959
0
                             "Added builtin pixel function argument %s = %s",
960
0
                             osArgName.c_str(), osVal.c_str());
961
0
                }
962
0
            }
963
0
        }
964
0
    }
965
966
0
    return CE_None;
967
0
}
968
969
/************************************************************************/
970
/*                             IRasterIO()                              */
971
/************************************************************************/
972
973
/**
974
 * Read/write a region of image data for this band.
975
 *
976
 * Each of the sources for this derived band will be read and passed to
977
 * the derived band pixel function.  The pixel function is responsible
978
 * for applying whatever algorithm is necessary to generate this band's
979
 * pixels from the sources.
980
 *
981
 * The sources will be read using the transfer type specified for sources
982
 * using SetSourceTransferType().  If no transfer type has been set for
983
 * this derived band, the band's data type will be used as the transfer type.
984
 *
985
 * @see gdalrasterband
986
 *
987
 * @param eRWFlag Either GF_Read to read a region of data, or GT_Write to
988
 * write a region of data.
989
 *
990
 * @param nXOff The pixel offset to the top left corner of the region
991
 * of the band to be accessed.  This would be zero to start from the left side.
992
 *
993
 * @param nYOff The line offset to the top left corner of the region
994
 * of the band to be accessed.  This would be zero to start from the top.
995
 *
996
 * @param nXSize The width of the region of the band to be accessed in pixels.
997
 *
998
 * @param nYSize The height of the region of the band to be accessed in lines.
999
 *
1000
 * @param pData The buffer into which the data should be read, or from which
1001
 * it should be written.  This buffer must contain at least nBufXSize *
1002
 * nBufYSize words of type eBufType.  It is organized in left to right,
1003
 * top to bottom pixel order.  Spacing is controlled by the nPixelSpace,
1004
 * and nLineSpace parameters.
1005
 *
1006
 * @param nBufXSize The width of the buffer image into which the desired
1007
 * region is to be read, or from which it is to be written.
1008
 *
1009
 * @param nBufYSize The height of the buffer image into which the desired
1010
 * region is to be read, or from which it is to be written.
1011
 *
1012
 * @param eBufType The type of the pixel values in the pData data buffer.  The
1013
 * pixel values will automatically be translated to/from the GDALRasterBand
1014
 * data type as needed.
1015
 *
1016
 * @param nPixelSpace The byte offset from the start of one pixel value in
1017
 * pData to the start of the next pixel value within a scanline.  If defaulted
1018
 * (0) the size of the datatype eBufType is used.
1019
 *
1020
 * @param nLineSpace The byte offset from the start of one scanline in
1021
 * pData to the start of the next.  If defaulted the size of the datatype
1022
 * eBufType * nBufXSize is used.
1023
 *
1024
 * @return CE_Failure if the access fails, otherwise CE_None.
1025
 */
1026
CPLErr VRTDerivedRasterBand::IRasterIO(
1027
    GDALRWFlag eRWFlag, int nXOff, int nYOff, int nXSize, int nYSize,
1028
    void *pData, int nBufXSize, int nBufYSize, GDALDataType eBufType,
1029
    GSpacing nPixelSpace, GSpacing nLineSpace, GDALRasterIOExtraArg *psExtraArg)
1030
0
{
1031
0
    if (eRWFlag == GF_Write)
1032
0
    {
1033
0
        CPLError(CE_Failure, CPLE_AppDefined,
1034
0
                 "Writing through VRTSourcedRasterBand is not supported.");
1035
0
        return CE_Failure;
1036
0
    }
1037
1038
    if constexpr (sizeof(GSpacing) > sizeof(int))
1039
0
    {
1040
0
        if (nLineSpace > INT_MAX)
1041
0
        {
1042
0
            if (nBufYSize == 1)
1043
0
            {
1044
0
                nLineSpace = 0;
1045
0
            }
1046
0
            else
1047
0
            {
1048
0
                CPLError(CE_Failure, CPLE_NotSupported,
1049
0
                         "VRTDerivedRasterBand::IRasterIO(): nLineSpace > "
1050
0
                         "INT_MAX not supported");
1051
0
                return CE_Failure;
1052
0
            }
1053
0
        }
1054
0
    }
1055
1056
0
    const int nBufTypeSize = GDALGetDataTypeSizeBytes(eBufType);
1057
0
    GDALDataType eSrcType = eSourceTransferType;
1058
0
    if (eSrcType == GDT_Unknown || eSrcType >= GDT_TypeCount)
1059
0
    {
1060
        // Check the largest data type for all sources
1061
0
        GDALDataType eAllSrcType = GDT_Unknown;
1062
0
        for (auto &poSource : m_papoSources)
1063
0
        {
1064
0
            if (poSource->GetType() == VRTSimpleSource::GetTypeStatic())
1065
0
            {
1066
0
                const auto poSS =
1067
0
                    static_cast<VRTSimpleSource *>(poSource.get());
1068
0
                auto l_poBand = poSS->GetRasterBand();
1069
0
                if (l_poBand)
1070
0
                {
1071
0
                    eAllSrcType = GDALDataTypeUnion(
1072
0
                        eAllSrcType, l_poBand->GetRasterDataType());
1073
0
                }
1074
0
                else
1075
0
                {
1076
0
                    eAllSrcType = GDT_Unknown;
1077
0
                    break;
1078
0
                }
1079
0
            }
1080
0
            else
1081
0
            {
1082
0
                eAllSrcType = GDT_Unknown;
1083
0
                break;
1084
0
            }
1085
0
        }
1086
1087
0
        if (eAllSrcType != GDT_Unknown)
1088
0
            eSrcType = eAllSrcType;
1089
0
        else
1090
0
            eSrcType = eBufType;
1091
0
    }
1092
0
    const int nSrcTypeSize = GDALGetDataTypeSizeBytes(eSrcType);
1093
1094
    // If acquiring the region of interest in a single time is going
1095
    // to consume too much RAM, split in halves, and that recursively
1096
    // until we get below m_nAllowedRAMUsage.
1097
0
    if (m_poPrivate->m_nAllowedRAMUsage > 0 && !m_papoSources.empty() &&
1098
0
        nSrcTypeSize > 0 && nBufXSize == nXSize && nBufYSize == nYSize &&
1099
0
        static_cast<GIntBig>(nBufXSize) * nBufYSize >
1100
0
            m_poPrivate->m_nAllowedRAMUsage /
1101
0
                (static_cast<int>(m_papoSources.size()) * nSrcTypeSize))
1102
0
    {
1103
0
        CPLErr eErr = SplitRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize,
1104
0
                                    pData, nBufXSize, nBufYSize, eBufType,
1105
0
                                    nPixelSpace, nLineSpace, psExtraArg);
1106
0
        if (eErr != CE_Warning)
1107
0
            return eErr;
1108
0
    }
1109
1110
    /* -------------------------------------------------------------------- */
1111
    /*      Do we have overviews that would be appropriate to satisfy       */
1112
    /*      this request?                                                   */
1113
    /* -------------------------------------------------------------------- */
1114
0
    if ((nBufXSize < nXSize || nBufYSize < nYSize) && GetOverviewCount() > 0)
1115
0
    {
1116
0
        if (OverviewRasterIO(eRWFlag, nXOff, nYOff, nXSize, nYSize, pData,
1117
0
                             nBufXSize, nBufYSize, eBufType, nPixelSpace,
1118
0
                             nLineSpace, psExtraArg) == CE_None)
1119
0
            return CE_None;
1120
0
    }
1121
1122
    /* ---- Get pixel function for band ---- */
1123
0
    const std::pair<PixelFunc, std::string> *poPixelFunc = nullptr;
1124
0
    std::vector<std::pair<CPLString, CPLString>> oAdditionalArgs;
1125
1126
0
    if (EQUAL(m_poPrivate->m_osLanguage, "C"))
1127
0
    {
1128
0
        poPixelFunc =
1129
0
            VRTDerivedRasterBand::GetPixelFunction(osFuncName.c_str());
1130
0
        if (poPixelFunc == nullptr)
1131
0
        {
1132
0
            CPLError(CE_Failure, CPLE_IllegalArg,
1133
0
                     "VRTDerivedRasterBand::IRasterIO:"
1134
0
                     "Derived band pixel function '%s' not registered.",
1135
0
                     osFuncName.c_str());
1136
0
            return CE_Failure;
1137
0
        }
1138
0
    }
1139
1140
    /* TODO: It would be nice to use a MallocBlock function for each
1141
       individual buffer that would recycle blocks of memory from a
1142
       cache by reassigning blocks that are nearly the same size.
1143
       A corresponding FreeBlock might only truly free if the total size
1144
       of freed blocks gets to be too great of a percentage of the size
1145
       of the allocated blocks. */
1146
1147
    // Get buffers for each source.
1148
0
    const int nBufferRadius = m_poPrivate->m_nBufferRadius;
1149
0
    if (nBufferRadius > (INT_MAX - nBufXSize) / 2 ||
1150
0
        nBufferRadius > (INT_MAX - nBufYSize) / 2)
1151
0
    {
1152
0
        CPLError(CE_Failure, CPLE_AppDefined,
1153
0
                 "Integer overflow: "
1154
0
                 "nBufferRadius > (INT_MAX - nBufXSize) / 2 || "
1155
0
                 "nBufferRadius > (INT_MAX - nBufYSize) / 2)");
1156
0
        return CE_Failure;
1157
0
    }
1158
0
    const int nExtBufXSize = nBufXSize + 2 * nBufferRadius;
1159
0
    const int nExtBufYSize = nBufYSize + 2 * nBufferRadius;
1160
0
    int nBufferCount = 0;
1161
1162
0
    std::vector<std::unique_ptr<void, VSIFreeReleaser>> apBuffers(
1163
0
        m_papoSources.size());
1164
0
    std::vector<int> anMapBufferIdxToSourceIdx(m_papoSources.size());
1165
0
    bool bSkipOutputBufferInitialization = !m_papoSources.empty();
1166
0
    for (int iSource = 0; iSource < static_cast<int>(m_papoSources.size());
1167
0
         iSource++)
1168
0
    {
1169
0
        if (m_poPrivate->m_bSkipNonContributingSources &&
1170
0
            m_papoSources[iSource]->IsSimpleSource())
1171
0
        {
1172
0
            bool bError = false;
1173
0
            double dfReqXOff, dfReqYOff, dfReqXSize, dfReqYSize;
1174
0
            int nReqXOff, nReqYOff, nReqXSize, nReqYSize;
1175
0
            int nOutXOff, nOutYOff, nOutXSize, nOutYSize;
1176
0
            auto poSource =
1177
0
                static_cast<VRTSimpleSource *>(m_papoSources[iSource].get());
1178
0
            if (!poSource->GetSrcDstWindow(
1179
0
                    nXOff, nYOff, nXSize, nYSize, nBufXSize, nBufYSize,
1180
0
                    &dfReqXOff, &dfReqYOff, &dfReqXSize, &dfReqYSize, &nReqXOff,
1181
0
                    &nReqYOff, &nReqXSize, &nReqYSize, &nOutXOff, &nOutYOff,
1182
0
                    &nOutXSize, &nOutYSize, bError))
1183
0
            {
1184
0
                if (bError)
1185
0
                {
1186
0
                    return CE_Failure;
1187
0
                }
1188
1189
                // Skip non contributing source
1190
0
                bSkipOutputBufferInitialization = false;
1191
0
                continue;
1192
0
            }
1193
0
        }
1194
1195
0
        anMapBufferIdxToSourceIdx[nBufferCount] = iSource;
1196
0
        apBuffers[nBufferCount].reset(
1197
0
            VSI_MALLOC3_VERBOSE(nSrcTypeSize, nExtBufXSize, nExtBufYSize));
1198
0
        if (apBuffers[nBufferCount] == nullptr)
1199
0
        {
1200
0
            return CE_Failure;
1201
0
        }
1202
1203
0
        bool bBufferInit = true;
1204
0
        if (m_papoSources[iSource]->IsSimpleSource())
1205
0
        {
1206
0
            const auto poSS =
1207
0
                static_cast<VRTSimpleSource *>(m_papoSources[iSource].get());
1208
0
            auto l_poBand = poSS->GetRasterBand();
1209
0
            if (l_poBand != nullptr && poSS->m_dfSrcXOff == 0.0 &&
1210
0
                poSS->m_dfSrcYOff == 0.0 &&
1211
0
                poSS->m_dfSrcXOff + poSS->m_dfSrcXSize ==
1212
0
                    l_poBand->GetXSize() &&
1213
0
                poSS->m_dfSrcYOff + poSS->m_dfSrcYSize ==
1214
0
                    l_poBand->GetYSize() &&
1215
0
                poSS->m_dfDstXOff == 0.0 && poSS->m_dfDstYOff == 0.0 &&
1216
0
                poSS->m_dfDstXOff + poSS->m_dfDstXSize == nRasterXSize &&
1217
0
                poSS->m_dfDstYOff + poSS->m_dfDstYSize == nRasterYSize)
1218
0
            {
1219
0
                if (m_papoSources[iSource]->GetType() ==
1220
0
                    VRTSimpleSource::GetTypeStatic())
1221
0
                    bBufferInit = false;
1222
0
            }
1223
0
            else
1224
0
            {
1225
0
                bSkipOutputBufferInitialization = false;
1226
0
            }
1227
0
        }
1228
0
        else
1229
0
        {
1230
0
            bSkipOutputBufferInitialization = false;
1231
0
        }
1232
0
        if (bBufferInit)
1233
0
        {
1234
            /* ------------------------------------------------------------ */
1235
            /* #4045: Initialize the newly allocated buffers before handing */
1236
            /* them off to the sources. These buffers are packed, so we     */
1237
            /* don't need any special line-by-line handling when a nonzero  */
1238
            /* nodata value is set.                                         */
1239
            /* ------------------------------------------------------------ */
1240
0
            if (!m_bNoDataValueSet || m_dfNoDataValue == 0)
1241
0
            {
1242
0
                memset(apBuffers[nBufferCount].get(), 0,
1243
0
                       static_cast<size_t>(nSrcTypeSize) * nExtBufXSize *
1244
0
                           nExtBufYSize);
1245
0
            }
1246
0
            else
1247
0
            {
1248
0
                GDALCopyWords64(
1249
0
                    &m_dfNoDataValue, GDT_Float64, 0,
1250
0
                    static_cast<GByte *>(apBuffers[nBufferCount].get()),
1251
0
                    eSrcType, nSrcTypeSize,
1252
0
                    static_cast<GPtrDiff_t>(nExtBufXSize) * nExtBufYSize);
1253
0
            }
1254
0
        }
1255
1256
0
        ++nBufferCount;
1257
0
    }
1258
1259
    /* -------------------------------------------------------------------- */
1260
    /*      Initialize the buffer to some background value. Use the         */
1261
    /*      nodata value if available.                                      */
1262
    /* -------------------------------------------------------------------- */
1263
0
    if (bSkipOutputBufferInitialization)
1264
0
    {
1265
        // Do nothing
1266
0
    }
1267
0
    else if (nPixelSpace == nBufTypeSize &&
1268
0
             (!m_bNoDataValueSet || m_dfNoDataValue == 0))
1269
0
    {
1270
0
        memset(pData, 0,
1271
0
               static_cast<size_t>(nBufXSize) * nBufYSize * nBufTypeSize);
1272
0
    }
1273
0
    else if (m_bNoDataValueSet)
1274
0
    {
1275
0
        double dfWriteValue = m_dfNoDataValue;
1276
1277
0
        for (int iLine = 0; iLine < nBufYSize; iLine++)
1278
0
        {
1279
0
            GDALCopyWords64(&dfWriteValue, GDT_Float64, 0,
1280
0
                            static_cast<GByte *>(pData) + nLineSpace * iLine,
1281
0
                            eBufType, static_cast<int>(nPixelSpace), nBufXSize);
1282
0
        }
1283
0
    }
1284
1285
    // No contributing sources and SkipNonContributingSources mode ?
1286
    // Do not call the pixel function and just return the 0/nodata initialized
1287
    // output buffer.
1288
0
    if (nBufferCount == 0 && m_poPrivate->m_bSkipNonContributingSources)
1289
0
    {
1290
0
        return CE_None;
1291
0
    }
1292
1293
0
    GDALRasterIOExtraArg sExtraArg;
1294
0
    GDALCopyRasterIOExtraArg(&sExtraArg, psExtraArg);
1295
1296
0
    int nXShiftInBuffer = 0;
1297
0
    int nYShiftInBuffer = 0;
1298
0
    int nExtBufXSizeReq = nExtBufXSize;
1299
0
    int nExtBufYSizeReq = nExtBufYSize;
1300
1301
0
    int nXOffExt = nXOff;
1302
0
    int nYOffExt = nYOff;
1303
0
    int nXSizeExt = nXSize;
1304
0
    int nYSizeExt = nYSize;
1305
1306
0
    if (nBufferRadius)
1307
0
    {
1308
0
        double dfXRatio = static_cast<double>(nXSize) / nBufXSize;
1309
0
        double dfYRatio = static_cast<double>(nYSize) / nBufYSize;
1310
1311
0
        if (!sExtraArg.bFloatingPointWindowValidity)
1312
0
        {
1313
0
            sExtraArg.dfXOff = nXOff;
1314
0
            sExtraArg.dfYOff = nYOff;
1315
0
            sExtraArg.dfXSize = nXSize;
1316
0
            sExtraArg.dfYSize = nYSize;
1317
0
        }
1318
1319
0
        sExtraArg.dfXOff -= dfXRatio * nBufferRadius;
1320
0
        sExtraArg.dfYOff -= dfYRatio * nBufferRadius;
1321
0
        sExtraArg.dfXSize += 2 * dfXRatio * nBufferRadius;
1322
0
        sExtraArg.dfYSize += 2 * dfYRatio * nBufferRadius;
1323
0
        if (sExtraArg.dfXOff < 0)
1324
0
        {
1325
0
            nXShiftInBuffer = -static_cast<int>(sExtraArg.dfXOff / dfXRatio);
1326
0
            nExtBufXSizeReq -= nXShiftInBuffer;
1327
0
            sExtraArg.dfXSize += sExtraArg.dfXOff;
1328
0
            sExtraArg.dfXOff = 0;
1329
0
        }
1330
0
        if (sExtraArg.dfYOff < 0)
1331
0
        {
1332
0
            nYShiftInBuffer = -static_cast<int>(sExtraArg.dfYOff / dfYRatio);
1333
0
            nExtBufYSizeReq -= nYShiftInBuffer;
1334
0
            sExtraArg.dfYSize += sExtraArg.dfYOff;
1335
0
            sExtraArg.dfYOff = 0;
1336
0
        }
1337
0
        if (sExtraArg.dfXOff + sExtraArg.dfXSize > nRasterXSize)
1338
0
        {
1339
0
            nExtBufXSizeReq -= static_cast<int>(
1340
0
                (sExtraArg.dfXOff + sExtraArg.dfXSize - nRasterXSize) /
1341
0
                dfXRatio);
1342
0
            sExtraArg.dfXSize = nRasterXSize - sExtraArg.dfXOff;
1343
0
        }
1344
0
        if (sExtraArg.dfYOff + sExtraArg.dfYSize > nRasterYSize)
1345
0
        {
1346
0
            nExtBufYSizeReq -= static_cast<int>(
1347
0
                (sExtraArg.dfYOff + sExtraArg.dfYSize - nRasterYSize) /
1348
0
                dfYRatio);
1349
0
            sExtraArg.dfYSize = nRasterYSize - sExtraArg.dfYOff;
1350
0
        }
1351
1352
0
        nXOffExt = static_cast<int>(sExtraArg.dfXOff);
1353
0
        nYOffExt = static_cast<int>(sExtraArg.dfYOff);
1354
0
        nXSizeExt = std::min(static_cast<int>(sExtraArg.dfXSize + 0.5),
1355
0
                             nRasterXSize - nXOffExt);
1356
0
        nYSizeExt = std::min(static_cast<int>(sExtraArg.dfYSize + 0.5),
1357
0
                             nRasterYSize - nYOffExt);
1358
0
    }
1359
1360
    // Load values for sources into packed buffers.
1361
0
    CPLErr eErr = CE_None;
1362
0
    VRTSource::WorkingState oWorkingState;
1363
0
    for (int iBuffer = 0; iBuffer < nBufferCount && eErr == CE_None; iBuffer++)
1364
0
    {
1365
0
        const int iSource = anMapBufferIdxToSourceIdx[iBuffer];
1366
0
        GByte *pabyBuffer = static_cast<GByte *>(apBuffers[iBuffer].get());
1367
0
        eErr = static_cast<VRTSource *>(m_papoSources[iSource].get())
1368
0
                   ->RasterIO(
1369
0
                       eSrcType, nXOffExt, nYOffExt, nXSizeExt, nYSizeExt,
1370
0
                       pabyBuffer + (static_cast<size_t>(nYShiftInBuffer) *
1371
0
                                         nExtBufXSize +
1372
0
                                     nXShiftInBuffer) *
1373
0
                                        nSrcTypeSize,
1374
0
                       nExtBufXSizeReq, nExtBufYSizeReq, eSrcType, nSrcTypeSize,
1375
0
                       static_cast<GSpacing>(nSrcTypeSize) * nExtBufXSize,
1376
0
                       &sExtraArg, oWorkingState);
1377
1378
        // Extend first lines
1379
0
        for (int iY = 0; iY < nYShiftInBuffer; iY++)
1380
0
        {
1381
0
            memcpy(pabyBuffer +
1382
0
                       static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
1383
0
                   pabyBuffer + static_cast<size_t>(nYShiftInBuffer) *
1384
0
                                    nExtBufXSize * nSrcTypeSize,
1385
0
                   static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
1386
0
        }
1387
        // Extend last lines
1388
0
        for (int iY = nYShiftInBuffer + nExtBufYSizeReq; iY < nExtBufYSize;
1389
0
             iY++)
1390
0
        {
1391
0
            memcpy(pabyBuffer +
1392
0
                       static_cast<size_t>(iY) * nExtBufXSize * nSrcTypeSize,
1393
0
                   pabyBuffer + static_cast<size_t>(nYShiftInBuffer +
1394
0
                                                    nExtBufYSizeReq - 1) *
1395
0
                                    nExtBufXSize * nSrcTypeSize,
1396
0
                   static_cast<size_t>(nExtBufXSize) * nSrcTypeSize);
1397
0
        }
1398
        // Extend first cols
1399
0
        if (nXShiftInBuffer)
1400
0
        {
1401
0
            for (int iY = 0; iY < nExtBufYSize; iY++)
1402
0
            {
1403
0
                for (int iX = 0; iX < nXShiftInBuffer; iX++)
1404
0
                {
1405
0
                    memcpy(pabyBuffer +
1406
0
                               static_cast<size_t>(iY * nExtBufXSize + iX) *
1407
0
                                   nSrcTypeSize,
1408
0
                           pabyBuffer +
1409
0
                               (static_cast<size_t>(iY) * nExtBufXSize +
1410
0
                                nXShiftInBuffer) *
1411
0
                                   nSrcTypeSize,
1412
0
                           nSrcTypeSize);
1413
0
                }
1414
0
            }
1415
0
        }
1416
        // Extent last cols
1417
0
        if (nXShiftInBuffer + nExtBufXSizeReq < nExtBufXSize)
1418
0
        {
1419
0
            for (int iY = 0; iY < nExtBufYSize; iY++)
1420
0
            {
1421
0
                for (int iX = nXShiftInBuffer + nExtBufXSizeReq;
1422
0
                     iX < nExtBufXSize; iX++)
1423
0
                {
1424
0
                    memcpy(pabyBuffer +
1425
0
                               (static_cast<size_t>(iY) * nExtBufXSize + iX) *
1426
0
                                   nSrcTypeSize,
1427
0
                           pabyBuffer +
1428
0
                               (static_cast<size_t>(iY) * nExtBufXSize +
1429
0
                                nXShiftInBuffer + nExtBufXSizeReq - 1) *
1430
0
                                   nSrcTypeSize,
1431
0
                           nSrcTypeSize);
1432
0
                }
1433
0
            }
1434
0
        }
1435
0
    }
1436
1437
    // Collect any pixel function arguments
1438
0
    if (poPixelFunc != nullptr && !poPixelFunc->second.empty())
1439
0
    {
1440
0
        if (GetPixelFunctionArguments(poPixelFunc->second,
1441
0
                                      anMapBufferIdxToSourceIdx, nXOff, nYOff,
1442
0
                                      oAdditionalArgs) != CE_None)
1443
0
        {
1444
0
            eErr = CE_Failure;
1445
0
        }
1446
0
    }
1447
1448
    // Apply pixel function.
1449
0
    if (eErr == CE_None && EQUAL(m_poPrivate->m_osLanguage, "Python"))
1450
0
    {
1451
        // numpy doesn't have native cint16/cint32/cfloat16
1452
0
        if (eSrcType == GDT_CInt16 || eSrcType == GDT_CInt32 ||
1453
0
            eSrcType == GDT_CFloat16)
1454
0
        {
1455
0
            CPLError(CE_Failure, CPLE_AppDefined,
1456
0
                     "CInt16/CInt32/CFloat16 data type not supported for "
1457
0
                     "SourceTransferType");
1458
0
            return CE_Failure;
1459
0
        }
1460
0
        if (eDataType == GDT_CInt16 || eDataType == GDT_CInt32 ||
1461
0
            eDataType == GDT_CFloat16)
1462
0
        {
1463
0
            CPLError(
1464
0
                CE_Failure, CPLE_AppDefined,
1465
0
                "CInt16/CInt32/CFloat16 data type not supported for data type");
1466
0
            return CE_Failure;
1467
0
        }
1468
1469
0
        if (!InitializePython())
1470
0
            return CE_Failure;
1471
1472
0
        std::unique_ptr<GByte, VSIFreeReleaser> pabyTmpBuffer;
1473
        // Do we need a temporary buffer or can we use directly the output
1474
        // buffer ?
1475
0
        if (nBufferRadius != 0 || eDataType != eBufType ||
1476
0
            nPixelSpace != nBufTypeSize ||
1477
0
            nLineSpace != static_cast<GSpacing>(nBufTypeSize) * nBufXSize)
1478
0
        {
1479
0
            pabyTmpBuffer.reset(static_cast<GByte *>(VSI_CALLOC_VERBOSE(
1480
0
                static_cast<size_t>(nExtBufXSize) * nExtBufYSize,
1481
0
                GDALGetDataTypeSizeBytes(eDataType))));
1482
0
            if (!pabyTmpBuffer)
1483
0
                return CE_Failure;
1484
0
        }
1485
1486
0
        {
1487
0
            const bool bUseExclusiveLock =
1488
0
                m_poPrivate->m_bExclusiveLock ||
1489
0
                (m_poPrivate->m_bFirstTime &&
1490
0
                 m_poPrivate->m_osCode.find("@jit") != std::string::npos);
1491
0
            m_poPrivate->m_bFirstTime = false;
1492
0
            GIL_Holder oHolder(bUseExclusiveLock);
1493
1494
            // Prepare target numpy array
1495
0
            PyObject *poPyDstArray = GDALCreateNumpyArray(
1496
0
                m_poPrivate->m_poGDALCreateNumpyArray,
1497
0
                pabyTmpBuffer ? pabyTmpBuffer.get() : pData, eDataType,
1498
0
                nExtBufYSize, nExtBufXSize);
1499
0
            if (!poPyDstArray)
1500
0
            {
1501
0
                return CE_Failure;
1502
0
            }
1503
1504
            // Wrap source buffers as input numpy arrays
1505
0
            PyObject *pyArgInputArray = PyTuple_New(nBufferCount);
1506
0
            for (int i = 0; i < nBufferCount; i++)
1507
0
            {
1508
0
                GByte *pabyBuffer = static_cast<GByte *>(apBuffers[i].get());
1509
0
                PyObject *poPySrcArray = GDALCreateNumpyArray(
1510
0
                    m_poPrivate->m_poGDALCreateNumpyArray, pabyBuffer, eSrcType,
1511
0
                    nExtBufYSize, nExtBufXSize);
1512
0
                CPLAssert(poPySrcArray);
1513
0
                PyTuple_SetItem(pyArgInputArray, i, poPySrcArray);
1514
0
            }
1515
1516
            // Create arguments
1517
0
            PyObject *pyArgs = PyTuple_New(10);
1518
0
            PyTuple_SetItem(pyArgs, 0, pyArgInputArray);
1519
0
            PyTuple_SetItem(pyArgs, 1, poPyDstArray);
1520
0
            PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(nXOff));
1521
0
            PyTuple_SetItem(pyArgs, 3, PyLong_FromLong(nYOff));
1522
0
            PyTuple_SetItem(pyArgs, 4, PyLong_FromLong(nXSize));
1523
0
            PyTuple_SetItem(pyArgs, 5, PyLong_FromLong(nYSize));
1524
0
            PyTuple_SetItem(pyArgs, 6, PyLong_FromLong(nRasterXSize));
1525
0
            PyTuple_SetItem(pyArgs, 7, PyLong_FromLong(nRasterYSize));
1526
0
            PyTuple_SetItem(pyArgs, 8, PyLong_FromLong(nBufferRadius));
1527
1528
0
            GDALGeoTransform gt;
1529
0
            if (GetDataset())
1530
0
                GetDataset()->GetGeoTransform(gt);
1531
0
            PyObject *pyGT = PyTuple_New(6);
1532
0
            for (int i = 0; i < 6; i++)
1533
0
                PyTuple_SetItem(pyGT, i, PyFloat_FromDouble(gt[i]));
1534
0
            PyTuple_SetItem(pyArgs, 9, pyGT);
1535
1536
            // Prepare kwargs
1537
0
            PyObject *pyKwargs = PyDict_New();
1538
0
            for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
1539
0
            {
1540
0
                const char *pszKey =
1541
0
                    m_poPrivate->m_oFunctionArgs[i].first.c_str();
1542
0
                const char *pszValue =
1543
0
                    m_poPrivate->m_oFunctionArgs[i].second.c_str();
1544
0
                PyDict_SetItemString(
1545
0
                    pyKwargs, pszKey,
1546
0
                    PyBytes_FromStringAndSize(pszValue, strlen(pszValue)));
1547
0
            }
1548
1549
            // Call user function
1550
0
            PyObject *pRetValue =
1551
0
                PyObject_Call(m_poPrivate->m_poUserFunction, pyArgs, pyKwargs);
1552
1553
0
            Py_DecRef(pyArgs);
1554
0
            Py_DecRef(pyKwargs);
1555
1556
0
            if (ErrOccurredEmitCPLError())
1557
0
            {
1558
0
                eErr = CE_Failure;
1559
0
            }
1560
0
            if (pRetValue)
1561
0
                Py_DecRef(pRetValue);
1562
0
        }  // End of GIL section
1563
1564
0
        if (pabyTmpBuffer)
1565
0
        {
1566
            // Copy numpy destination array to user buffer
1567
0
            for (int iY = 0; iY < nBufYSize; iY++)
1568
0
            {
1569
0
                size_t nSrcOffset =
1570
0
                    (static_cast<size_t>(iY + nBufferRadius) * nExtBufXSize +
1571
0
                     nBufferRadius) *
1572
0
                    GDALGetDataTypeSizeBytes(eDataType);
1573
0
                GDALCopyWords64(pabyTmpBuffer.get() + nSrcOffset, eDataType,
1574
0
                                GDALGetDataTypeSizeBytes(eDataType),
1575
0
                                static_cast<GByte *>(pData) + iY * nLineSpace,
1576
0
                                eBufType, static_cast<int>(nPixelSpace),
1577
0
                                nBufXSize);
1578
0
            }
1579
0
        }
1580
0
    }
1581
0
    else if (eErr == CE_None && poPixelFunc != nullptr)
1582
0
    {
1583
0
        CPLStringList aosArgs;
1584
1585
0
        oAdditionalArgs.insert(oAdditionalArgs.end(),
1586
0
                               m_poPrivate->m_oFunctionArgs.begin(),
1587
0
                               m_poPrivate->m_oFunctionArgs.end());
1588
0
        for (const auto &oArg : oAdditionalArgs)
1589
0
        {
1590
0
            const char *pszKey = oArg.first.c_str();
1591
0
            const char *pszValue = oArg.second.c_str();
1592
0
            aosArgs.SetNameValue(pszKey, pszValue);
1593
0
        }
1594
1595
0
        static_assert(sizeof(apBuffers[0]) == sizeof(void *));
1596
0
        eErr = (poPixelFunc->first)(
1597
            // We cast vector<unique_ptr<void>>.data() as void**. This is OK
1598
            // given above static_assert
1599
0
            reinterpret_cast<void **>(apBuffers.data()), nBufferCount, pData,
1600
0
            nBufXSize, nBufYSize, eSrcType, eBufType,
1601
0
            static_cast<int>(nPixelSpace), static_cast<int>(nLineSpace),
1602
0
            aosArgs.List());
1603
0
    }
1604
1605
0
    return eErr;
1606
0
}
1607
1608
/************************************************************************/
1609
/*                         IGetDataCoverageStatus()                     */
1610
/************************************************************************/
1611
1612
int VRTDerivedRasterBand::IGetDataCoverageStatus(
1613
    int /* nXOff */, int /* nYOff */, int /* nXSize */, int /* nYSize */,
1614
    int /* nMaskFlagStop */, double *pdfDataPct)
1615
0
{
1616
0
    if (pdfDataPct != nullptr)
1617
0
        *pdfDataPct = -1.0;
1618
0
    return GDAL_DATA_COVERAGE_STATUS_UNIMPLEMENTED |
1619
0
           GDAL_DATA_COVERAGE_STATUS_DATA;
1620
0
}
1621
1622
/************************************************************************/
1623
/*                              XMLInit()                               */
1624
/************************************************************************/
1625
1626
CPLErr VRTDerivedRasterBand::XMLInit(const CPLXMLNode *psTree,
1627
                                     const char *pszVRTPath,
1628
                                     VRTMapSharedResources &oMapSharedSources)
1629
1630
0
{
1631
0
    const CPLErr eErr =
1632
0
        VRTSourcedRasterBand::XMLInit(psTree, pszVRTPath, oMapSharedSources);
1633
0
    if (eErr != CE_None)
1634
0
        return eErr;
1635
1636
    // Read derived pixel function type.
1637
0
    SetPixelFunctionName(CPLGetXMLValue(psTree, "PixelFunctionType", nullptr));
1638
0
    if (osFuncName.empty())
1639
0
    {
1640
0
        CPLError(CE_Failure, CPLE_AppDefined, "PixelFunctionType missing");
1641
0
        return CE_Failure;
1642
0
    }
1643
1644
0
    m_poPrivate->m_osLanguage =
1645
0
        CPLGetXMLValue(psTree, "PixelFunctionLanguage", "C");
1646
0
    if (!EQUAL(m_poPrivate->m_osLanguage, "C") &&
1647
0
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1648
0
    {
1649
0
        CPLError(CE_Failure, CPLE_NotSupported,
1650
0
                 "Unsupported PixelFunctionLanguage");
1651
0
        return CE_Failure;
1652
0
    }
1653
1654
0
    m_poPrivate->m_osCode = CPLGetXMLValue(psTree, "PixelFunctionCode", "");
1655
0
    if (!m_poPrivate->m_osCode.empty() &&
1656
0
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1657
0
    {
1658
0
        CPLError(CE_Failure, CPLE_NotSupported,
1659
0
                 "PixelFunctionCode can only be used with Python");
1660
0
        return CE_Failure;
1661
0
    }
1662
1663
0
    m_poPrivate->m_nBufferRadius =
1664
0
        atoi(CPLGetXMLValue(psTree, "BufferRadius", "0"));
1665
0
    if (m_poPrivate->m_nBufferRadius < 0 || m_poPrivate->m_nBufferRadius > 1024)
1666
0
    {
1667
0
        CPLError(CE_Failure, CPLE_AppDefined, "Invalid value for BufferRadius");
1668
0
        return CE_Failure;
1669
0
    }
1670
0
    if (m_poPrivate->m_nBufferRadius != 0 &&
1671
0
        !EQUAL(m_poPrivate->m_osLanguage, "Python"))
1672
0
    {
1673
0
        CPLError(CE_Failure, CPLE_NotSupported,
1674
0
                 "BufferRadius can only be used with Python");
1675
0
        return CE_Failure;
1676
0
    }
1677
1678
0
    const CPLXMLNode *const psArgs =
1679
0
        CPLGetXMLNode(psTree, "PixelFunctionArguments");
1680
0
    if (psArgs != nullptr)
1681
0
    {
1682
0
        for (const CPLXMLNode *psIter = psArgs->psChild; psIter;
1683
0
             psIter = psIter->psNext)
1684
0
        {
1685
0
            if (psIter->eType == CXT_Attribute)
1686
0
            {
1687
0
                AddPixelFunctionArgument(psIter->pszValue,
1688
0
                                         psIter->psChild->pszValue);
1689
0
            }
1690
0
        }
1691
0
    }
1692
1693
    // Read optional source transfer data type.
1694
0
    const char *pszTypeName =
1695
0
        CPLGetXMLValue(psTree, "SourceTransferType", nullptr);
1696
0
    if (pszTypeName != nullptr)
1697
0
    {
1698
0
        eSourceTransferType = GDALGetDataTypeByName(pszTypeName);
1699
0
    }
1700
1701
    // Whether to skip non contributing sources
1702
0
    const char *pszSkipNonContributingSources =
1703
0
        CPLGetXMLValue(psTree, "SkipNonContributingSources", nullptr);
1704
0
    if (pszSkipNonContributingSources)
1705
0
    {
1706
0
        SetSkipNonContributingSources(
1707
0
            CPLTestBool(pszSkipNonContributingSources));
1708
0
    }
1709
1710
0
    return CE_None;
1711
0
}
1712
1713
/************************************************************************/
1714
/*                           SerializeToXML()                           */
1715
/************************************************************************/
1716
1717
CPLXMLNode *VRTDerivedRasterBand::SerializeToXML(const char *pszVRTPath,
1718
                                                 bool &bHasWarnedAboutRAMUsage,
1719
                                                 size_t &nAccRAMUsage)
1720
0
{
1721
0
    CPLXMLNode *psTree = VRTSourcedRasterBand::SerializeToXML(
1722
0
        pszVRTPath, bHasWarnedAboutRAMUsage, nAccRAMUsage);
1723
1724
    /* -------------------------------------------------------------------- */
1725
    /*      Set subclass.                                                   */
1726
    /* -------------------------------------------------------------------- */
1727
0
    CPLCreateXMLNode(CPLCreateXMLNode(psTree, CXT_Attribute, "subClass"),
1728
0
                     CXT_Text, "VRTDerivedRasterBand");
1729
1730
    /* ---- Encode DerivedBand-specific fields ---- */
1731
0
    if (!EQUAL(m_poPrivate->m_osLanguage, "C"))
1732
0
    {
1733
0
        CPLSetXMLValue(psTree, "PixelFunctionLanguage",
1734
0
                       m_poPrivate->m_osLanguage);
1735
0
    }
1736
0
    if (!osFuncName.empty())
1737
0
        CPLSetXMLValue(psTree, "PixelFunctionType", osFuncName.c_str());
1738
0
    if (!m_poPrivate->m_oFunctionArgs.empty())
1739
0
    {
1740
0
        CPLXMLNode *psArgs =
1741
0
            CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionArguments");
1742
0
        for (size_t i = 0; i < m_poPrivate->m_oFunctionArgs.size(); ++i)
1743
0
        {
1744
0
            const char *pszKey = m_poPrivate->m_oFunctionArgs[i].first.c_str();
1745
0
            const char *pszValue =
1746
0
                m_poPrivate->m_oFunctionArgs[i].second.c_str();
1747
0
            CPLCreateXMLNode(CPLCreateXMLNode(psArgs, CXT_Attribute, pszKey),
1748
0
                             CXT_Text, pszValue);
1749
0
        }
1750
0
    }
1751
0
    if (!m_poPrivate->m_osCode.empty())
1752
0
    {
1753
0
        if (m_poPrivate->m_osCode.find("<![CDATA[") == std::string::npos)
1754
0
        {
1755
0
            CPLCreateXMLNode(
1756
0
                CPLCreateXMLNode(psTree, CXT_Element, "PixelFunctionCode"),
1757
0
                CXT_Literal,
1758
0
                ("<![CDATA[" + m_poPrivate->m_osCode + "]]>").c_str());
1759
0
        }
1760
0
        else
1761
0
        {
1762
0
            CPLSetXMLValue(psTree, "PixelFunctionCode", m_poPrivate->m_osCode);
1763
0
        }
1764
0
    }
1765
0
    if (m_poPrivate->m_nBufferRadius != 0)
1766
0
        CPLSetXMLValue(psTree, "BufferRadius",
1767
0
                       CPLSPrintf("%d", m_poPrivate->m_nBufferRadius));
1768
0
    if (this->eSourceTransferType != GDT_Unknown)
1769
0
        CPLSetXMLValue(psTree, "SourceTransferType",
1770
0
                       GDALGetDataTypeName(eSourceTransferType));
1771
1772
0
    if (m_poPrivate->m_bSkipNonContributingSourcesSpecified)
1773
0
    {
1774
0
        CPLSetXMLValue(psTree, "SkipNonContributingSources",
1775
0
                       m_poPrivate->m_bSkipNonContributingSources ? "true"
1776
0
                                                                  : "false");
1777
0
    }
1778
1779
0
    return psTree;
1780
0
}
1781
1782
/************************************************************************/
1783
/*                             GetMinimum()                             */
1784
/************************************************************************/
1785
1786
double VRTDerivedRasterBand::GetMinimum(int *pbSuccess)
1787
0
{
1788
0
    return GDALRasterBand::GetMinimum(pbSuccess);
1789
0
}
1790
1791
/************************************************************************/
1792
/*                             GetMaximum()                             */
1793
/************************************************************************/
1794
1795
double VRTDerivedRasterBand::GetMaximum(int *pbSuccess)
1796
0
{
1797
0
    return GDALRasterBand::GetMaximum(pbSuccess);
1798
0
}
1799
1800
/************************************************************************/
1801
/*                       ComputeRasterMinMax()                          */
1802
/************************************************************************/
1803
1804
CPLErr VRTDerivedRasterBand::ComputeRasterMinMax(int bApproxOK,
1805
                                                 double *adfMinMax)
1806
0
{
1807
0
    return GDALRasterBand::ComputeRasterMinMax(bApproxOK, adfMinMax);
1808
0
}
1809
1810
/************************************************************************/
1811
/*                         ComputeStatistics()                          */
1812
/************************************************************************/
1813
1814
CPLErr VRTDerivedRasterBand::ComputeStatistics(int bApproxOK, double *pdfMin,
1815
                                               double *pdfMax, double *pdfMean,
1816
                                               double *pdfStdDev,
1817
                                               GDALProgressFunc pfnProgress,
1818
                                               void *pProgressData)
1819
1820
0
{
1821
0
    return GDALRasterBand::ComputeStatistics(bApproxOK, pdfMin, pdfMax, pdfMean,
1822
0
                                             pdfStdDev, pfnProgress,
1823
0
                                             pProgressData);
1824
0
}
1825
1826
/************************************************************************/
1827
/*                            GetHistogram()                            */
1828
/************************************************************************/
1829
1830
CPLErr VRTDerivedRasterBand::GetHistogram(double dfMin, double dfMax,
1831
                                          int nBuckets, GUIntBig *panHistogram,
1832
                                          int bIncludeOutOfRange, int bApproxOK,
1833
                                          GDALProgressFunc pfnProgress,
1834
                                          void *pProgressData)
1835
1836
0
{
1837
0
    return VRTRasterBand::GetHistogram(dfMin, dfMax, nBuckets, panHistogram,
1838
0
                                       bIncludeOutOfRange, bApproxOK,
1839
0
                                       pfnProgress, pProgressData);
1840
0
}
1841
1842
/*! @endcond */