LCOV - code coverage report
Current view: top level - frmts/vrt - vrtderivedrasterband.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 591 635 93.1 %
Date: 2025-03-29 15:49:56 Functions: 28 30 93.3 %

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

Generated by: LCOV version 1.14