LCOV - code coverage report
Current view: top level - frmts/vrt - vrtderivedrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 630 675 93.3 %
Date: 2025-05-31 00:00:17 Functions: 30 32 93.8 %

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

Generated by: LCOV version 1.14