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

Generated by: LCOV version 1.14