LCOV - code coverage report
Current view: top level - gcore - gdalpythondriverloader.cpp (source / functions) Hit Total Coverage
Test: gdal_filtered.info Lines: 623 919 67.8 %
Date: 2025-11-23 04:58:22 Functions: 39 47 83.0 %

          Line data    Source code
       1             : /******************************************************************************
       2             :  *
       3             :  * Project:  GDAL Core
       4             :  * Purpose:  Python plugin loader
       5             :  * Author:   Even Rouault, <even dot rouault at spatialys dot com>
       6             :  *
       7             :  ******************************************************************************
       8             :  * Copyright (c) 2017-2019, Even Rouault, <even dot rouault at spatialys dot
       9             :  *com>
      10             :  *
      11             :  * SPDX-License-Identifier: MIT
      12             :  ****************************************************************************/
      13             : 
      14             : #include "cpl_conv.h"
      15             : #include "cpl_minixml.h"
      16             : #include "cpl_multiproc.h"
      17             : #include "cpl_string.h"
      18             : #include "gdal_priv.h"
      19             : #include "ogrsf_frmts.h"
      20             : #include "gdalpython.h"
      21             : 
      22             : #include <algorithm>
      23             : #include <memory>
      24             : #include <mutex>
      25             : 
      26             : using namespace GDALPy;
      27             : 
      28             : #ifdef GDAL_NO_AUTOLOAD
      29             : void GDALDriverManager::AutoLoadPythonDrivers()
      30             : {
      31             : }
      32             : 
      33             : void GDALDriverManager::CleanupPythonDrivers()
      34             : {
      35             : }
      36             : 
      37             : #else
      38             : 
      39             : static PyObject *layer_featureCount(PyObject *m, PyObject *args,
      40             :                                     PyObject *kwargs);
      41             : 
      42             : static PyObject *Py_None = nullptr;
      43             : 
      44             : static PyObject *gpoGDALPythonDriverModule = nullptr;
      45             : 
      46             : /************************************************************************/
      47             : /*                         IncRefAndReturn()                            */
      48             : /************************************************************************/
      49             : 
      50           9 : static PyObject *IncRefAndReturn(PyObject *obj)
      51             : {
      52           9 :     Py_IncRef(obj);
      53           9 :     return obj;
      54             : }
      55             : 
      56             : /************************************************************************/
      57             : /*                            CallPython()                              */
      58             : /************************************************************************/
      59             : 
      60           1 : static PyObject *CallPython(PyObject *function)
      61             : {
      62           1 :     PyObject *pyArgs = PyTuple_New(0);
      63           1 :     PyObject *pRet = PyObject_Call(function, pyArgs, nullptr);
      64           1 :     Py_DecRef(pyArgs);
      65           1 :     return pRet;
      66             : }
      67             : 
      68             : /************************************************************************/
      69             : /*                            CallPython()                              */
      70             : /************************************************************************/
      71             : 
      72           3 : static PyObject *CallPython(PyObject *function, int nVal)
      73             : {
      74           3 :     PyObject *pyArgs = PyTuple_New(1);
      75           3 :     PyTuple_SetItem(pyArgs, 0, PyLong_FromLong(nVal));
      76           3 :     PyObject *pRet = PyObject_Call(function, pyArgs, nullptr);
      77           3 :     Py_DecRef(pyArgs);
      78           3 :     return pRet;
      79             : }
      80             : 
      81             : /************************************************************************/
      82             : /*                InitializePythonAndLoadGDALPythonDriverModule() */
      83             : /************************************************************************/
      84             : 
      85           3 : static bool InitializePythonAndLoadGDALPythonDriverModule()
      86             : {
      87           3 :     if (!GDALPythonInitialize())
      88           0 :         return false;
      89             : 
      90             :     static std::mutex gMutex;
      91             :     static bool gbAlreadyInitialized = false;
      92           6 :     std::lock_guard<std::mutex> guard(gMutex);
      93             : 
      94           3 :     if (gbAlreadyInitialized)
      95           2 :         return true;
      96           1 :     gbAlreadyInitialized = true;
      97             : 
      98           1 :     GIL_Holder oHolder(false);
      99             : 
     100           1 :     PyObject *poCompiledString = Py_CompileString(
     101             :         "import json\n"
     102             :         "import inspect\n"
     103             :         "import sys\n"
     104             :         "class BaseLayer:\n"
     105             :         "   RandomRead='RandomRead'\n"
     106             :         "   FastSpatialFilter='FastSpatialFilter'\n"
     107             :         "   FastFeatureCount='FastFeatureCount'\n"
     108             :         "   FastGetExtent='FastGetExtent'\n"
     109             :         "   StringsAsUTF8='StringsAsUTF8'\n"
     110             :         "\n"
     111             :         "   def __init__(self):\n"
     112             :         "       pass\n"
     113             :         "\n"
     114             :         "   def feature_count(self, force):\n"
     115             :         "       assert isinstance(self, BaseLayer), 'self not instance of "
     116             :         "BaseLayer'\n"
     117             :         "       return _layer_featureCount(self, force)\n"
     118             :         "\n"
     119             :         "class BaseDataset:\n"
     120             :         "   def __init__(self):\n"
     121             :         "       pass\n"
     122             :         "\n"
     123             :         "class BaseDriver:\n"
     124             :         "   def __init__(self):\n"
     125             :         "       pass\n"
     126             :         "\n"
     127             :         "def _gdal_returnNone():\n"
     128             :         "  return None"
     129             :         "\n"
     130             :         "def _gdal_json_serialize(d):\n"
     131             :         "  return json.dumps(d)\n"
     132             :         "\n"
     133             :         "def _instantiate_plugin(plugin_module):\n"
     134             :         "   candidate = None\n"
     135             :         "   for key in dir(plugin_module):\n"
     136             :         "       elt = getattr(plugin_module, key)\n"
     137             :         "       if inspect.isclass(elt) and sys.modules[elt.__module__] == "
     138             :         "plugin_module and issubclass(elt, BaseDriver):\n"
     139             :         "           if candidate:\n"
     140             :         "               raise Exception(\"several classes in \" + "
     141             :         "plugin_module.__name__ + \" deriving from "
     142             :         "gdal_python_driver.BaseDriver\")\n"
     143             :         "           candidate = elt\n"
     144             :         "   if candidate:\n"
     145             :         "       return candidate()\n"
     146             :         "   raise Exception(\"cannot find class in \" + plugin_module.__name__ "
     147             :         "+ \" deriving from gdal_python_driver.BaseDriver\")\n",
     148             :         "gdal_python_driver", Py_file_input);
     149           1 :     gpoGDALPythonDriverModule =
     150           1 :         PyImport_ExecCodeModule("gdal_python_driver", poCompiledString);
     151           1 :     Py_DecRef(poCompiledString);
     152             : 
     153             :     static const PyMethodDef layer_featureCount_def = {
     154             :         "_layer_featureCount",
     155             :         layer_featureCount,
     156             :         METH_VARARGS | METH_KEYWORDS,
     157             :         nullptr,
     158             :     };
     159             :     PyObject *layer_featureCount_func =
     160           1 :         PyCFunction_New(&layer_featureCount_def, nullptr);
     161           1 :     PyModule_AddObject(gpoGDALPythonDriverModule, layer_featureCount_def.name,
     162             :                        layer_featureCount_func);
     163             : 
     164             :     // Initialize Py_None
     165             :     PyObject *returnNone =
     166           1 :         PyObject_GetAttrString(gpoGDALPythonDriverModule, "_gdal_returnNone");
     167           1 :     Py_None = CallPython(returnNone);
     168           1 :     Py_DecRef(returnNone);
     169             : 
     170           1 :     return true;
     171             : }
     172             : 
     173             : /************************************************************************/
     174             : /*                           GetIntRes()                                */
     175             : /************************************************************************/
     176             : 
     177           0 : static int GetIntRes(PyObject *poObj, const char *pszFunctionName)
     178             : {
     179           0 :     PyObject *poMethod = PyObject_GetAttrString(poObj, pszFunctionName);
     180           0 :     if (poMethod == nullptr || PyErr_Occurred())
     181             :     {
     182           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
     183           0 :                  GetPyExceptionString().c_str());
     184           0 :         return 0;
     185             :     }
     186             : 
     187           0 :     PyObject *poMethodRes = CallPython(poMethod);
     188           0 :     if (ErrOccurredEmitCPLError())
     189             :     {
     190           0 :         Py_DecRef(poMethod);
     191           0 :         return 0;
     192             :     }
     193           0 :     Py_DecRef(poMethod);
     194             : 
     195           0 :     int nRes = static_cast<int>(PyLong_AsLong(poMethodRes));
     196           0 :     if (ErrOccurredEmitCPLError())
     197             :     {
     198           0 :         Py_DecRef(poMethodRes);
     199           0 :         return 0;
     200             :     }
     201             : 
     202           0 :     Py_DecRef(poMethodRes);
     203           0 :     return nRes;
     204             : }
     205             : 
     206             : /************************************************************************/
     207             : /*                           GetDict()                                  */
     208             : /************************************************************************/
     209             : 
     210           0 : static char **GetDict(PyObject *poDict)
     211             : {
     212             :     PyObject *key, *value;
     213           0 :     size_t pos = 0;
     214             : 
     215           0 :     char **papszRes = nullptr;
     216           0 :     while (PyDict_Next(poDict, &pos, &key, &value))
     217             :     {
     218           0 :         if (ErrOccurredEmitCPLError())
     219             :         {
     220           0 :             break;
     221             :         }
     222           0 :         CPLString osKey = GetString(key);
     223           0 :         if (ErrOccurredEmitCPLError())
     224             :         {
     225           0 :             break;
     226             :         }
     227           0 :         CPLString osValue = GetString(value);
     228           0 :         if (ErrOccurredEmitCPLError())
     229             :         {
     230           0 :             break;
     231             :         }
     232           0 :         papszRes = CSLSetNameValue(papszRes, osKey, osValue);
     233             :     }
     234           0 :     return papszRes;
     235             : }
     236             : 
     237             : /************************************************************************/
     238             : /*                          GetStringRes()                              */
     239             : /************************************************************************/
     240             : 
     241           0 : static CPLString GetStringRes(PyObject *poObj, const char *pszFunctionName,
     242             :                               bool bOptionalMethod = false)
     243             : {
     244           0 :     PyObject *poMethod = PyObject_GetAttrString(poObj, pszFunctionName);
     245           0 :     if (poMethod == nullptr || PyErr_Occurred())
     246             :     {
     247           0 :         if (bOptionalMethod)
     248             :         {
     249           0 :             PyErr_Clear();
     250             :         }
     251             :         else
     252             :         {
     253           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
     254           0 :                      GetPyExceptionString().c_str());
     255             :         }
     256           0 :         return CPLString();
     257             :     }
     258             : 
     259           0 :     PyObject *poMethodRes = CallPython(poMethod);
     260             : 
     261           0 :     if (ErrOccurredEmitCPLError())
     262             :     {
     263           0 :         Py_DecRef(poMethod);
     264           0 :         return CPLString();
     265             :     }
     266           0 :     Py_DecRef(poMethod);
     267             : 
     268           0 :     CPLString osRes = GetString(poMethodRes);
     269           0 :     if (ErrOccurredEmitCPLError())
     270             :     {
     271           0 :         Py_DecRef(poMethodRes);
     272           0 :         return CPLString();
     273             :     }
     274             : 
     275           0 :     Py_DecRef(poMethodRes);
     276           0 :     return osRes;
     277             : }
     278             : 
     279             : /************************************************************************/
     280             : /*                          PythonPluginLayer                           */
     281             : /************************************************************************/
     282             : 
     283             : class PythonPluginLayer final : public OGRLayer
     284             : {
     285             :     mutable PyObject *m_poLayer = nullptr;
     286             :     mutable OGRFeatureDefn *m_poFeatureDefn = nullptr;
     287             :     mutable CPLString m_osName{};
     288             :     mutable CPLString m_osFIDColumn{};
     289             :     mutable bool m_bHasFIDColumn = false;
     290             :     std::map<CPLString, CPLStringList> m_oMapMD{};
     291             :     PyObject *m_pyFeatureByIdMethod = nullptr;
     292             :     bool m_bIteratorHonourSpatialFilter = false;
     293             :     bool m_bIteratorHonourAttributeFilter = false;
     294             :     bool m_bFeatureCountHonourSpatialFilter = false;
     295             :     bool m_bFeatureCountHonourAttributeFilter = false;
     296             :     PyObject *m_pyIterator = nullptr;
     297             :     bool m_bStopIteration = false;
     298             : 
     299             :     void RefreshHonourFlags();
     300             :     void StoreSpatialFilter();
     301             : 
     302             :     void GetFields() const;
     303             :     void GetGeomFields() const;
     304             :     OGRFeature *TranslateToOGRFeature(PyObject *poObj);
     305             : 
     306             :     PythonPluginLayer(const PythonPluginLayer &) = delete;
     307             :     PythonPluginLayer &operator=(const PythonPluginLayer &) = delete;
     308             : 
     309             :   public:
     310             :     explicit PythonPluginLayer(PyObject *poLayer);
     311             :     ~PythonPluginLayer() override;
     312             : 
     313             :     const char *GetName() const override;
     314             :     void ResetReading() override;
     315             :     OGRFeature *GetNextFeature() override;
     316             :     OGRFeature *GetFeature(GIntBig nFID) override;
     317             :     int TestCapability(const char *) const override;
     318             :     const OGRFeatureDefn *GetLayerDefn() const override;
     319             : 
     320             :     GIntBig GetFeatureCount(int bForce) override;
     321             :     const char *GetFIDColumn() const override;
     322             :     OGRErr SetAttributeFilter(const char *) override;
     323             : 
     324             :     OGRErr ISetSpatialFilter(int iGeomField, const OGRGeometry *) override;
     325             : 
     326             :     OGRErr IGetExtent(int iGeomField, OGREnvelope *psExtent,
     327             :                       bool bForce) override;
     328             : 
     329             :     char **GetMetadata(const char *pszDomain = "") override;
     330             : };
     331             : 
     332             : /************************************************************************/
     333             : /*                          PythonPluginLayer()                         */
     334             : /************************************************************************/
     335             : 
     336           3 : PythonPluginLayer::PythonPluginLayer(PyObject *poLayer)
     337           3 :     : m_poLayer(poLayer), m_poFeatureDefn(nullptr)
     338             : {
     339           3 :     SetDescription(PythonPluginLayer::GetName());
     340           3 :     const char *pszPtr = CPLSPrintf("%p", this);
     341           3 :     PyObject *ptr = PyUnicode_FromString(pszPtr);
     342           3 :     PyObject_SetAttrString(m_poLayer, "_gdal_pointer", ptr);
     343           3 :     Py_DecRef(ptr);
     344           3 :     PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", Py_None);
     345           3 :     PyObject_SetAttrString(m_poLayer, "spatial_filter", Py_None);
     346           3 :     PyObject_SetAttrString(m_poLayer, "attribute_filter", Py_None);
     347           3 :     auto poFalse = PyBool_FromLong(false);
     348           3 :     if (!PyObject_HasAttrString(m_poLayer, "iterator_honour_attribute_filter"))
     349             :     {
     350           3 :         PyObject_SetAttrString(m_poLayer, "iterator_honour_attribute_filter",
     351             :                                poFalse);
     352             :     }
     353           3 :     if (!PyObject_HasAttrString(m_poLayer, "iterator_honour_spatial_filter"))
     354             :     {
     355           3 :         PyObject_SetAttrString(m_poLayer, "iterator_honour_spatial_filter",
     356             :                                poFalse);
     357             :     }
     358           3 :     if (!PyObject_HasAttrString(m_poLayer,
     359             :                                 "feature_count_honour_attribute_filter"))
     360             :     {
     361           3 :         PyObject_SetAttrString(
     362             :             m_poLayer, "feature_count_honour_attribute_filter", poFalse);
     363             :     }
     364           3 :     if (!PyObject_HasAttrString(m_poLayer,
     365             :                                 "feature_count_honour_spatial_filter"))
     366             :     {
     367           3 :         PyObject_SetAttrString(m_poLayer, "feature_count_honour_spatial_filter",
     368             :                                poFalse);
     369             :     }
     370           3 :     Py_DecRef(poFalse);
     371           3 :     RefreshHonourFlags();
     372             : 
     373           3 :     if (PyObject_HasAttrString(m_poLayer, "feature_by_id"))
     374             :     {
     375           0 :         m_pyFeatureByIdMethod =
     376           0 :             PyObject_GetAttrString(m_poLayer, "feature_by_id");
     377             :     }
     378           3 : }
     379             : 
     380             : /************************************************************************/
     381             : /*                          ~PythonPluginLayer()                        */
     382             : /************************************************************************/
     383             : 
     384           6 : PythonPluginLayer::~PythonPluginLayer()
     385             : {
     386           6 :     GIL_Holder oHolder(false);
     387           3 :     if (m_poFeatureDefn)
     388           3 :         m_poFeatureDefn->Release();
     389           3 :     Py_DecRef(m_pyFeatureByIdMethod);
     390           3 :     Py_DecRef(m_poLayer);
     391           3 :     Py_DecRef(m_pyIterator);
     392           6 : }
     393             : 
     394             : /************************************************************************/
     395             : /*                        RefreshHonourFlags()               */
     396             : /************************************************************************/
     397             : 
     398           3 : void PythonPluginLayer::RefreshHonourFlags()
     399             : {
     400           3 :     if (PyObject_HasAttrString(m_poLayer, "iterator_honour_attribute_filter"))
     401             :     {
     402           3 :         auto poObj = PyObject_GetAttrString(m_poLayer,
     403             :                                             "iterator_honour_attribute_filter");
     404           3 :         m_bIteratorHonourAttributeFilter = PyLong_AsLong(poObj) != 0;
     405           3 :         Py_DecRef(poObj);
     406             :     }
     407           3 :     if (PyObject_HasAttrString(m_poLayer, "iterator_honour_spatial_filter"))
     408             :     {
     409             :         auto poObj =
     410           3 :             PyObject_GetAttrString(m_poLayer, "iterator_honour_spatial_filter");
     411           3 :         m_bIteratorHonourSpatialFilter = PyLong_AsLong(poObj) != 0;
     412           3 :         Py_DecRef(poObj);
     413             :     }
     414           3 :     if (PyObject_HasAttrString(m_poLayer,
     415           3 :                                "feature_count_honour_attribute_filter"))
     416             :     {
     417           3 :         auto poObj = PyObject_GetAttrString(
     418             :             m_poLayer, "feature_count_honour_attribute_filter");
     419           3 :         m_bFeatureCountHonourAttributeFilter = PyLong_AsLong(poObj) != 0;
     420           3 :         Py_DecRef(poObj);
     421             :     }
     422           3 :     if (PyObject_HasAttrString(m_poLayer,
     423           3 :                                "feature_count_honour_spatial_filter"))
     424             :     {
     425           3 :         auto poObj = PyObject_GetAttrString(
     426             :             m_poLayer, "feature_count_honour_spatial_filter");
     427           3 :         m_bFeatureCountHonourSpatialFilter = PyLong_AsLong(poObj) != 0;
     428           3 :         Py_DecRef(poObj);
     429             :     }
     430           3 : }
     431             : 
     432             : /************************************************************************/
     433             : /*                          SetAttributeFilter()                        */
     434             : /************************************************************************/
     435             : 
     436          12 : OGRErr PythonPluginLayer::SetAttributeFilter(const char *pszFilter)
     437             : {
     438          24 :     GIL_Holder oHolder(false);
     439             :     PyObject *str =
     440          12 :         pszFilter ? PyUnicode_FromString(pszFilter) : IncRefAndReturn(Py_None);
     441          12 :     PyObject_SetAttrString(m_poLayer, "attribute_filter", str);
     442          12 :     Py_DecRef(str);
     443             : 
     444          12 :     if (PyObject_HasAttrString(m_poLayer, "attribute_filter_changed"))
     445             :     {
     446             :         auto poObj =
     447           0 :             PyObject_GetAttrString(m_poLayer, "attribute_filter_changed");
     448           0 :         Py_DecRef(CallPython(poObj));
     449           0 :         Py_DecRef(poObj);
     450             :     }
     451             : 
     452          24 :     return OGRLayer::SetAttributeFilter(pszFilter);
     453             : }
     454             : 
     455             : /************************************************************************/
     456             : /*                          StoreSpatialFilter()                        */
     457             : /************************************************************************/
     458             : 
     459          12 : void PythonPluginLayer::StoreSpatialFilter()
     460             : {
     461          24 :     GIL_Holder oHolder(false);
     462          12 :     if (m_poFilterGeom && !m_poFilterGeom->IsEmpty())
     463             :     {
     464           3 :         PyObject *list = PyList_New(4);
     465           3 :         PyList_SetItem(list, 0, PyFloat_FromDouble(m_sFilterEnvelope.MinX));
     466           3 :         PyList_SetItem(list, 1, PyFloat_FromDouble(m_sFilterEnvelope.MinY));
     467           3 :         PyList_SetItem(list, 2, PyFloat_FromDouble(m_sFilterEnvelope.MaxX));
     468           3 :         PyList_SetItem(list, 3, PyFloat_FromDouble(m_sFilterEnvelope.MaxY));
     469           3 :         PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", list);
     470           3 :         Py_DecRef(list);
     471             : 
     472           3 :         char *pszWKT = nullptr;
     473           3 :         m_poFilterGeom->exportToWkt(&pszWKT);
     474           3 :         PyObject *str = PyUnicode_FromString(pszWKT);
     475           3 :         PyObject_SetAttrString(m_poLayer, "spatial_filter", str);
     476           3 :         Py_DecRef(str);
     477           3 :         CPLFree(pszWKT);
     478             :     }
     479             :     else
     480             :     {
     481           9 :         PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", Py_None);
     482           9 :         PyObject_SetAttrString(m_poLayer, "spatial_filter", Py_None);
     483             :     }
     484             : 
     485          12 :     if (PyObject_HasAttrString(m_poLayer, "spatial_filter_changed"))
     486             :     {
     487             :         auto poObj =
     488           0 :             PyObject_GetAttrString(m_poLayer, "spatial_filter_changed");
     489           0 :         Py_DecRef(CallPython(poObj));
     490           0 :         Py_DecRef(poObj);
     491             :     }
     492          12 : }
     493             : 
     494             : /************************************************************************/
     495             : /*                         ISetSpatialFilter()                          */
     496             : /************************************************************************/
     497             : 
     498          12 : OGRErr PythonPluginLayer::ISetSpatialFilter(int iGeomField,
     499             :                                             const OGRGeometry *poGeom)
     500             : {
     501          12 :     const OGRErr eErr = OGRLayer::ISetSpatialFilter(iGeomField, poGeom);
     502          12 :     if (eErr == OGRERR_NONE)
     503          12 :         StoreSpatialFilter();
     504          12 :     return eErr;
     505             : }
     506             : 
     507             : /************************************************************************/
     508             : /*                           GetName()                                  */
     509             : /************************************************************************/
     510             : 
     511           9 : const char *PythonPluginLayer::GetName() const
     512             : {
     513           9 :     if (m_osName.empty())
     514             :     {
     515           3 :         GIL_Holder oHolder(false);
     516             : 
     517           3 :         PyObject *poObj = PyObject_GetAttrString(m_poLayer, "name");
     518           3 :         if (ErrOccurredEmitCPLError())
     519           0 :             return m_osName;
     520           3 :         if (PyCallable_Check(poObj))
     521             :         {
     522           0 :             m_osName = GetStringRes(m_poLayer, "name");
     523             :         }
     524             :         else
     525             :         {
     526           3 :             m_osName = GetString(poObj);
     527           3 :             CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     528             :         }
     529           3 :         Py_DecRef(poObj);
     530             :     }
     531           9 :     return m_osName;
     532             : }
     533             : 
     534             : /************************************************************************/
     535             : /*                       TestCapability()                               */
     536             : /************************************************************************/
     537             : 
     538          12 : int PythonPluginLayer::TestCapability(const char *pszCap) const
     539             : {
     540          24 :     GIL_Holder oHolder(false);
     541          12 :     if (PyObject_HasAttrString(m_poLayer, "test_capability"))
     542             :     {
     543          12 :         PyObject *poObj = PyObject_GetAttrString(m_poLayer, "test_capability");
     544          12 :         if (ErrOccurredEmitCPLError())
     545           0 :             return 0;
     546          12 :         PyObject *pyArgs = PyTuple_New(1);
     547          12 :         PyTuple_SetItem(pyArgs, 0, PyUnicode_FromString(pszCap));
     548          12 :         PyObject *pRet = PyObject_Call(poObj, pyArgs, nullptr);
     549          12 :         Py_DecRef(pyArgs);
     550          12 :         Py_DecRef(poObj);
     551          12 :         if (ErrOccurredEmitCPLError())
     552             :         {
     553           0 :             Py_DecRef(pRet);
     554           0 :             return 0;
     555             :         }
     556          12 :         int nRes = static_cast<int>(PyLong_AsLong(pRet));
     557          12 :         Py_DecRef(pRet);
     558          12 :         if (ErrOccurredEmitCPLError())
     559             :         {
     560           0 :             return 0;
     561             :         }
     562          12 :         return nRes;
     563             :     }
     564           0 :     return 0;
     565             : }
     566             : 
     567             : /************************************************************************/
     568             : /*                         GetFIDColumn()                               */
     569             : /************************************************************************/
     570             : 
     571           6 : const char *PythonPluginLayer::GetFIDColumn() const
     572             : {
     573           6 :     if (!m_bHasFIDColumn)
     574             :     {
     575           3 :         m_bHasFIDColumn = true;
     576           6 :         GIL_Holder oHolder(false);
     577           3 :         PyObject *poObj = PyObject_GetAttrString(m_poLayer, "fid_name");
     578           3 :         if (PyErr_Occurred())
     579             :         {
     580           0 :             PyErr_Clear();
     581             :         }
     582             :         else
     583             :         {
     584           3 :             if (PyCallable_Check(poObj))
     585             :             {
     586           0 :                 m_osFIDColumn = GetStringRes(m_poLayer, "fid_name", true);
     587             :             }
     588             :             else
     589             :             {
     590           3 :                 m_osFIDColumn = GetString(poObj);
     591           3 :                 CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     592             :             }
     593           3 :             Py_DecRef(poObj);
     594             :         }
     595             :     }
     596           6 :     return m_osFIDColumn;
     597             : }
     598             : 
     599             : /************************************************************************/
     600             : /*                        layer_featureCount()                           */
     601             : /************************************************************************/
     602             : 
     603           0 : static PyObject *layer_featureCount(PyObject * /*m*/, PyObject *args,
     604             :                                     PyObject * /*kwargs*/)
     605             : {
     606           0 :     PyObject *poPyLayer = nullptr;
     607           0 :     int bForce = 0;
     608           0 :     if (PyArg_ParseTuple(args, "O|i", &poPyLayer, &bForce))
     609             :     {
     610             :         PyObject *poPointer =
     611           0 :             PyObject_GetAttrString(poPyLayer, "_gdal_pointer");
     612           0 :         if (poPointer)
     613             :         {
     614           0 :             CPLString osPtr = GetString(poPointer);
     615           0 :             Py_DecRef(poPointer);
     616           0 :             void *pPtr = nullptr;
     617           0 :             sscanf(osPtr, "%p", &pPtr);
     618           0 :             PythonPluginLayer *poLayer = static_cast<PythonPluginLayer *>(pPtr);
     619           0 :             return PyLong_FromLongLong(
     620           0 :                 poLayer->OGRLayer::GetFeatureCount(bForce));
     621             :         }
     622             :     }
     623           0 :     Py_IncRef(Py_None);
     624           0 :     return Py_None;
     625             : }
     626             : 
     627             : /************************************************************************/
     628             : /*                         GetFeatureCount()                            */
     629             : /************************************************************************/
     630             : 
     631           9 : GIntBig PythonPluginLayer::GetFeatureCount(int bForce)
     632             : {
     633          18 :     GIL_Holder oHolder(false);
     634             : 
     635           9 :     if (PyObject_HasAttrString(m_poLayer, "feature_count") &&
     636          15 :         (m_bFeatureCountHonourAttributeFilter || m_poAttrQuery == nullptr) &&
     637           6 :         (m_bFeatureCountHonourSpatialFilter || m_poFilterGeom == nullptr))
     638             :     {
     639           3 :         auto poMethod = PyObject_GetAttrString(m_poLayer, "feature_count");
     640           3 :         PyObject *poRet = CallPython(poMethod, bForce);
     641           3 :         if (ErrOccurredEmitCPLError())
     642             :         {
     643           0 :             Py_DecRef(poRet);
     644           0 :             return OGRLayer::GetFeatureCount(bForce);
     645             :         }
     646             : 
     647           3 :         GIntBig nRet = PyLong_AsLongLong(poRet);
     648           3 :         if (ErrOccurredEmitCPLError())
     649             :         {
     650           0 :             Py_DecRef(poRet);
     651           0 :             return OGRLayer::GetFeatureCount(bForce);
     652             :         }
     653             : 
     654           3 :         Py_DecRef(poRet);
     655           3 :         return nRet;
     656             :     }
     657           6 :     return OGRLayer::GetFeatureCount(bForce);
     658             : }
     659             : 
     660             : /************************************************************************/
     661             : /*                          IGetExtent()                                */
     662             : /************************************************************************/
     663             : 
     664           0 : OGRErr PythonPluginLayer::IGetExtent(int iGeomField, OGREnvelope *psExtent,
     665             :                                      bool bForce)
     666             : {
     667           0 :     GIL_Holder oHolder(false);
     668           0 :     if (PyObject_HasAttrString(m_poLayer, "extent"))
     669             :     {
     670           0 :         PyObject *poMethod = PyObject_GetAttrString(m_poLayer, "extent");
     671           0 :         if (poMethod != nullptr)
     672             :         {
     673           0 :             PyObject *poRet = CallPython(poMethod, bForce);
     674             : 
     675           0 :             if (ErrOccurredEmitCPLError())
     676             :             {
     677           0 :                 Py_DecRef(poRet);
     678           0 :                 return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     679             :             }
     680             : 
     681           0 :             if (poRet == Py_None)
     682             :             {
     683           0 :                 Py_DecRef(poRet);
     684           0 :                 return OGRERR_FAILURE;
     685             :             }
     686             : 
     687           0 :             if (PySequence_Size(poRet) == 4)
     688             :             {
     689           0 :                 PyObject *poMinX = PySequence_GetItem(poRet, 0);
     690           0 :                 PyObject *poMinY = PySequence_GetItem(poRet, 1);
     691           0 :                 PyObject *poMaxX = PySequence_GetItem(poRet, 2);
     692           0 :                 PyObject *poMaxY = PySequence_GetItem(poRet, 3);
     693           0 :                 double dfMinX = PyFloat_AsDouble(poMinX);
     694           0 :                 double dfMinY = PyFloat_AsDouble(poMinY);
     695           0 :                 double dfMaxX = PyFloat_AsDouble(poMaxX);
     696           0 :                 double dfMaxY = PyFloat_AsDouble(poMaxY);
     697           0 :                 if (ErrOccurredEmitCPLError())
     698             :                 {
     699           0 :                     Py_DecRef(poRet);
     700           0 :                     return OGRLayer::GetExtent(psExtent, bForce);
     701             :                 }
     702           0 :                 Py_DecRef(poRet);
     703           0 :                 psExtent->MinX = dfMinX;
     704           0 :                 psExtent->MinY = dfMinY;
     705           0 :                 psExtent->MaxX = dfMaxX;
     706           0 :                 psExtent->MaxY = dfMaxY;
     707           0 :                 return OGRERR_NONE;
     708             :             }
     709             :             else
     710             :             {
     711           0 :                 CPLError(CE_Failure, CPLE_AppDefined,
     712             :                          "List should have 4 values");
     713             :             }
     714             : 
     715           0 :             Py_DecRef(poRet);
     716             :         }
     717             :     }
     718           0 :     return OGRLayer::IGetExtent(iGeomField, psExtent, bForce);
     719             : }
     720             : 
     721             : /************************************************************************/
     722             : /*                      TranslateToOGRFeature()                         */
     723             : /************************************************************************/
     724             : 
     725          78 : OGRFeature *PythonPluginLayer::TranslateToOGRFeature(PyObject *poObj)
     726             : {
     727          78 :     if (poObj == Py_None)
     728           0 :         return nullptr;
     729             : 
     730          78 :     OGRFeature *poFeature = new OGRFeature(GetLayerDefn());
     731             : 
     732          78 :     PyObject *myBool = PyBool_FromLong(1);
     733          78 :     PyObject *myBoolType = PyObject_Type(myBool);
     734          78 :     PyObject *myInt = PyLong_FromLong(1);
     735          78 :     PyObject *myIntType = PyObject_Type(myInt);
     736          78 :     PyObject *myLong = PyLong_FromLongLong(1);
     737          78 :     PyObject *myLongType = PyObject_Type(myLong);
     738          78 :     PyObject *myFloat = PyFloat_FromDouble(1.0);
     739          78 :     PyObject *myFloatType = PyObject_Type(myFloat);
     740          78 :     PyObject *myStr = PyUnicode_FromString("");
     741          78 :     PyObject *myStrType = PyObject_Type(myStr);
     742             : 
     743          78 :     auto poFields = PyDict_GetItemString(poObj, "fields");
     744          78 :     auto poGeometryFields = PyDict_GetItemString(poObj, "geometry_fields");
     745          78 :     auto poId = PyDict_GetItemString(poObj, "id");
     746          78 :     auto poStyleString = PyDict_GetItemString(poObj, "style");
     747          78 :     PyErr_Clear();
     748             : 
     749          78 :     if (poId && PyObject_IsInstance(poId, myLongType))
     750             :     {
     751          78 :         poFeature->SetFID(static_cast<GIntBig>(PyLong_AsLongLong(poId)));
     752             :     }
     753           0 :     else if (poId && PyObject_IsInstance(poId, myIntType))
     754             :     {
     755           0 :         poFeature->SetFID(static_cast<GIntBig>(PyLong_AsLong(poId)));
     756             :     }
     757             : 
     758          78 :     if (poStyleString && poStyleString != Py_None)
     759             :     {
     760          96 :         CPLString osValue = GetString(poStyleString);
     761          48 :         if (!ErrOccurredEmitCPLError())
     762             :         {
     763          48 :             poFeature->SetStyleString(osValue);
     764             :         }
     765             :     }
     766             : 
     767          78 :     if (poGeometryFields && poGeometryFields != Py_None)
     768             :     {
     769          78 :         PyObject *key = nullptr;
     770          78 :         PyObject *value = nullptr;
     771          78 :         size_t pos = 0;
     772         156 :         while (PyDict_Next(poGeometryFields, &pos, &key, &value))
     773             :         {
     774          78 :             CPLString osKey = GetString(key);
     775          78 :             if (ErrOccurredEmitCPLError())
     776             :             {
     777           0 :                 break;
     778             :             }
     779          78 :             if (value != Py_None)
     780             :             {
     781          78 :                 const int idx = m_poFeatureDefn->GetGeomFieldIndex(osKey);
     782          78 :                 if (idx >= 0)
     783             :                 {
     784          78 :                     OGRGeometry *poGeom = nullptr;
     785          78 :                     if (PyObject_IsInstance(value, myStrType))
     786             :                     {
     787             :                         // WKT
     788          26 :                         CPLString osValue = GetString(value);
     789          26 :                         if (ErrOccurredEmitCPLError())
     790             :                         {
     791           0 :                             break;
     792             :                         }
     793          26 :                         OGRGeometryFactory::createFromWkt(osValue.c_str(),
     794             :                                                           nullptr, &poGeom);
     795             :                     }
     796             :                     else
     797             :                     {
     798             :                         // WKB (from bytes, bytearray, memoryview)
     799          52 :                         PyObject *poBytes = PyBytes_FromObject(value);
     800          52 :                         if (ErrOccurredEmitCPLError())
     801             :                         {
     802           0 :                             break;
     803             :                         }
     804          52 :                         char *buffer = nullptr;
     805          52 :                         size_t length = 0;
     806          52 :                         PyBytes_AsStringAndSize(poBytes, &buffer, &length);
     807          52 :                         if (ErrOccurredEmitCPLError())
     808             :                         {
     809           0 :                             break;
     810             :                         }
     811             : 
     812          52 :                         OGRGeometryFactory::createFromWkb(
     813             :                             buffer, nullptr, &poGeom, length, wkbVariantIso);
     814             :                     }
     815             : 
     816          78 :                     if (poGeom)
     817             :                     {
     818             :                         const auto poGeomFieldDefn =
     819          78 :                             m_poFeatureDefn->GetGeomFieldDefn(idx);
     820          78 :                         if (poGeomFieldDefn)
     821          78 :                             poGeom->assignSpatialReference(
     822          78 :                                 poGeomFieldDefn->GetSpatialRef());
     823             :                     }
     824          78 :                     poFeature->SetGeomFieldDirectly(idx, poGeom);
     825             :                 }
     826             :             }
     827             :         }
     828             :     }
     829             : 
     830          78 :     PyObject *key = nullptr;
     831          78 :     PyObject *value = nullptr;
     832          78 :     size_t pos = 0;
     833        2028 :     while (poFields && poFields != Py_None &&
     834        1014 :            PyDict_Next(poFields, &pos, &key, &value))
     835             :     {
     836         936 :         CPLString osKey = GetString(key);
     837         936 :         if (ErrOccurredEmitCPLError())
     838             :         {
     839           0 :             break;
     840             :         }
     841             : 
     842         936 :         if (value == Py_None)
     843             :         {
     844          78 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     845          78 :             if (idx >= 0)
     846             :             {
     847          78 :                 poFeature->SetFieldNull(idx);
     848             :             }
     849             :         }
     850         858 :         else if (PyObject_IsInstance(value, myLongType))
     851             :         {
     852         312 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     853         312 :             if (idx >= 0)
     854             :             {
     855         312 :                 poFeature->SetField(
     856             :                     idx, static_cast<GIntBig>(PyLong_AsLongLong(value)));
     857             :             }
     858             :         }
     859        1092 :         else if (PyObject_IsInstance(value, myBoolType) ||
     860         546 :                  PyObject_IsInstance(value, myIntType))
     861             :         {
     862           0 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     863           0 :             if (idx >= 0)
     864             :             {
     865           0 :                 poFeature->SetField(idx,
     866           0 :                                     static_cast<GIntBig>(PyLong_AsLong(value)));
     867             :             }
     868             :         }
     869         546 :         else if (PyObject_IsInstance(value, myFloatType))
     870             :         {
     871         156 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     872         156 :             if (idx >= 0)
     873             :             {
     874         156 :                 poFeature->SetField(idx, PyFloat_AsDouble(value));
     875             :             }
     876             :         }
     877             :         else
     878             :         {
     879         390 :             int idx = m_poFeatureDefn->GetFieldIndex(osKey);
     880         780 :             if (idx >= 0 &&
     881         390 :                 m_poFeatureDefn->GetFieldDefn(idx)->GetType() == OFTBinary)
     882             :             {
     883          78 :                 Py_ssize_t nSize = PyBytes_Size(value);
     884          78 :                 const char *pszBytes = PyBytes_AsString(value);
     885          78 :                 poFeature->SetField(
     886             :                     idx, static_cast<int>(nSize),
     887             :                     const_cast<GByte *>(
     888             :                         reinterpret_cast<const GByte *>(pszBytes)));
     889          78 :                 continue;
     890             :             }
     891             : 
     892         312 :             CPLString osValue = GetString(value);
     893         312 :             if (ErrOccurredEmitCPLError())
     894             :             {
     895           0 :                 break;
     896             :             }
     897         312 :             if (idx >= 0)
     898             :             {
     899         312 :                 poFeature->SetField(idx, osValue);
     900             :             }
     901             :         }
     902             :     }
     903             : 
     904          78 :     Py_DecRef(myBoolType);
     905          78 :     Py_DecRef(myBool);
     906          78 :     Py_DecRef(myIntType);
     907          78 :     Py_DecRef(myInt);
     908          78 :     Py_DecRef(myLongType);
     909          78 :     Py_DecRef(myLong);
     910          78 :     Py_DecRef(myFloatType);
     911          78 :     Py_DecRef(myFloat);
     912          78 :     Py_DecRef(myStr);
     913          78 :     Py_DecRef(myStrType);
     914             : 
     915          78 :     return poFeature;
     916             : }
     917             : 
     918             : /************************************************************************/
     919             : /*                            GetFeature()                              */
     920             : /************************************************************************/
     921             : 
     922           3 : OGRFeature *PythonPluginLayer::GetFeature(GIntBig nFID)
     923             : {
     924           6 :     GIL_Holder oHolder(false);
     925             : 
     926           3 :     if (m_pyFeatureByIdMethod)
     927             :     {
     928           0 :         PyObject *pyArgs = PyTuple_New(1);
     929           0 :         PyTuple_SetItem(pyArgs, 0, PyLong_FromLongLong(nFID));
     930           0 :         PyObject *pRet = PyObject_Call(m_pyFeatureByIdMethod, pyArgs, nullptr);
     931           0 :         Py_DecRef(pyArgs);
     932           0 :         if (ErrOccurredEmitCPLError())
     933             :         {
     934           0 :             Py_DecRef(pRet);
     935           0 :             return nullptr;
     936             :         }
     937           0 :         auto poFeature = TranslateToOGRFeature(pRet);
     938           0 :         Py_DecRef(pRet);
     939           0 :         if (ErrOccurredEmitCPLError())
     940             :         {
     941           0 :             return nullptr;
     942             :         }
     943           0 :         return poFeature;
     944             :     }
     945           3 :     return OGRLayer::GetFeature(nFID);
     946             : }
     947             : 
     948             : /************************************************************************/
     949             : /*                           ResetReading()                             */
     950             : /************************************************************************/
     951             : 
     952          36 : void PythonPluginLayer::ResetReading()
     953             : {
     954          36 :     m_bStopIteration = false;
     955             : 
     956          36 :     GIL_Holder oHolder(false);
     957             : 
     958          36 :     Py_DecRef(m_pyIterator);
     959          36 :     m_pyIterator = PyObject_GetIter(m_poLayer);
     960          36 :     CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     961          36 : }
     962             : 
     963             : /************************************************************************/
     964             : /*                          GetNextFeature()                            */
     965             : /************************************************************************/
     966             : 
     967          33 : OGRFeature *PythonPluginLayer::GetNextFeature()
     968             : {
     969          66 :     GIL_Holder oHolder(false);
     970             : 
     971          33 :     if (m_bStopIteration)
     972           0 :         return nullptr;
     973             : 
     974          33 :     if (m_pyIterator == nullptr)
     975             :     {
     976           0 :         ResetReading();
     977           0 :         if (m_pyIterator == nullptr)
     978             :         {
     979           0 :             return nullptr;
     980             :         }
     981             :     }
     982             : 
     983             :     while (true)
     984             :     {
     985          93 :         PyObject *poRet = PyIter_Next(m_pyIterator);
     986          93 :         if (poRet == nullptr)
     987             :         {
     988          15 :             m_bStopIteration = true;
     989          15 :             CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
     990          15 :             return nullptr;
     991             :         }
     992             : 
     993          78 :         auto poFeature = TranslateToOGRFeature(poRet);
     994          78 :         Py_DecRef(poRet);
     995          78 :         if (poFeature == nullptr)
     996             :         {
     997           0 :             return nullptr;
     998             :         }
     999             : 
    1000          78 :         if ((m_bIteratorHonourSpatialFilter || m_poFilterGeom == nullptr ||
    1001         156 :              FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
    1002          48 :             (m_bIteratorHonourAttributeFilter || m_poAttrQuery == nullptr ||
    1003          30 :              m_poAttrQuery->Evaluate(poFeature)))
    1004             :         {
    1005          18 :             return poFeature;
    1006             :         }
    1007             : 
    1008          60 :         delete poFeature;
    1009          60 :     }
    1010             : }
    1011             : 
    1012             : /************************************************************************/
    1013             : /*                         GetLayerDefn()                               */
    1014             : /************************************************************************/
    1015             : 
    1016          93 : const OGRFeatureDefn *PythonPluginLayer::GetLayerDefn() const
    1017             : {
    1018          93 :     if (m_poFeatureDefn)
    1019          90 :         return m_poFeatureDefn;
    1020             : 
    1021           3 :     GIL_Holder oHolder(false);
    1022           3 :     m_poFeatureDefn = new OGRFeatureDefn(GetName());
    1023           3 :     m_poFeatureDefn->Reference();
    1024           3 :     m_poFeatureDefn->SetGeomType(wkbNone);
    1025             : 
    1026           3 :     GetFields();
    1027           3 :     GetGeomFields();
    1028           3 :     return m_poFeatureDefn;
    1029             : }
    1030             : 
    1031             : /************************************************************************/
    1032             : /*                           GetFields()                                */
    1033             : /************************************************************************/
    1034             : 
    1035           3 : void PythonPluginLayer::GetFields() const
    1036             : {
    1037           3 :     PyObject *poFields = PyObject_GetAttrString(m_poLayer, "fields");
    1038           3 :     if (ErrOccurredEmitCPLError())
    1039           0 :         return;
    1040           3 :     if (PyCallable_Check(poFields))
    1041             :     {
    1042           0 :         PyObject *poFieldsRes = CallPython(poFields);
    1043           0 :         if (ErrOccurredEmitCPLError())
    1044             :         {
    1045           0 :             Py_DecRef(poFields);
    1046             : 
    1047           0 :             return;
    1048             :         }
    1049           0 :         Py_DecRef(poFields);
    1050           0 :         poFields = poFieldsRes;
    1051             :     }
    1052             : 
    1053           3 :     size_t nSize = PySequence_Size(poFields);
    1054           3 :     if (ErrOccurredEmitCPLError())
    1055             :     {
    1056           0 :         Py_DecRef(poFields);
    1057             : 
    1058           0 :         return;
    1059             :     }
    1060          42 :     for (size_t i = 0; i < nSize; i++)
    1061             :     {
    1062          39 :         PyObject *poItem = PySequence_GetItem(poFields, i);
    1063          39 :         if (poItem == nullptr || PyErr_Occurred())
    1064             :         {
    1065           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1066           0 :                      GetPyExceptionString().c_str());
    1067           0 :             Py_DecRef(poFields);
    1068             : 
    1069           0 :             return;
    1070             :         }
    1071             : 
    1072             :         PyObject *key, *value;
    1073          39 :         size_t pos = 0;
    1074          39 :         CPLString osFieldName;
    1075          39 :         OGRFieldType eType = OFTString;
    1076          39 :         OGRFieldSubType eSubType = OFSTNone;
    1077         117 :         while (PyDict_Next(poItem, &pos, &key, &value))
    1078             :         {
    1079          78 :             if (ErrOccurredEmitCPLError())
    1080             :             {
    1081           0 :                 Py_DecRef(poFields);
    1082             : 
    1083           0 :                 return;
    1084             :             }
    1085          78 :             CPLString osKey = GetString(key);
    1086          78 :             if (ErrOccurredEmitCPLError())
    1087             :             {
    1088           0 :                 Py_DecRef(poFields);
    1089             : 
    1090           0 :                 return;
    1091             :             }
    1092          78 :             if (strcmp(osKey, "name") == 0)
    1093             :             {
    1094          39 :                 osFieldName = GetString(value);
    1095          39 :                 if (ErrOccurredEmitCPLError())
    1096             :                 {
    1097           0 :                     Py_DecRef(poFields);
    1098             : 
    1099           0 :                     return;
    1100             :                 }
    1101             :             }
    1102          39 :             else if (strcmp(osKey, "type") == 0)
    1103             :             {
    1104          39 :                 PyObject *myInt = PyLong_FromLong(1);
    1105          39 :                 PyObject *myIntType = PyObject_Type(myInt);
    1106          39 :                 if (PyObject_IsInstance(value, myIntType))
    1107             :                 {
    1108           0 :                     int nType = static_cast<int>(PyLong_AsLong(value));
    1109           0 :                     if (nType < 0 || nType > OFTMaxType)
    1110             :                     {
    1111           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %d",
    1112             :                                  nType);
    1113             :                     }
    1114             :                     else
    1115             :                     {
    1116           0 :                         eType = static_cast<OGRFieldType>(nType);
    1117           0 :                         if (ErrOccurredEmitCPLError())
    1118             :                         {
    1119           0 :                             Py_DecRef(poFields);
    1120             : 
    1121           0 :                             return;
    1122             :                         }
    1123             :                     }
    1124             :                 }
    1125             :                 else
    1126             :                 {
    1127          39 :                     CPLString osValue = GetString(value);
    1128          39 :                     if (ErrOccurredEmitCPLError())
    1129             :                     {
    1130           0 :                         Py_DecRef(poFields);
    1131             : 
    1132           0 :                         return;
    1133             :                     }
    1134          39 :                     if (EQUAL(osValue, "String"))
    1135           9 :                         eType = OFTString;
    1136          30 :                     else if (EQUAL(osValue, "Integer") ||
    1137          57 :                              EQUAL(osValue, "Integer32") ||
    1138          27 :                              EQUAL(osValue, "Int32"))
    1139           3 :                         eType = OFTInteger;
    1140          27 :                     else if (EQUAL(osValue, "Boolean"))
    1141             :                     {
    1142           3 :                         eType = OFTInteger;
    1143           3 :                         eSubType = OFSTBoolean;
    1144             :                     }
    1145          45 :                     else if (EQUAL(osValue, "Integer16") ||
    1146          21 :                              EQUAL(osValue, "Int16"))
    1147             :                     {
    1148           3 :                         eType = OFTInteger;
    1149           3 :                         eSubType = OFSTInt16;
    1150             :                     }
    1151          39 :                     else if (EQUAL(osValue, "Integer64") ||
    1152          18 :                              EQUAL(osValue, "Int64"))
    1153           3 :                         eType = OFTInteger64;
    1154          18 :                     else if (EQUAL(osValue, "Real"))
    1155           3 :                         eType = OFTReal;
    1156          27 :                     else if (EQUAL(osValue, "Float") ||
    1157          12 :                              EQUAL(osValue, "Float32"))
    1158             :                     {
    1159           3 :                         eType = OFTReal;
    1160           3 :                         eSubType = OFSTFloat32;
    1161             :                     }
    1162          12 :                     else if (EQUAL(osValue, "Binary"))
    1163           3 :                         eType = OFTBinary;
    1164           9 :                     else if (EQUAL(osValue, "DateTime"))
    1165           3 :                         eType = OFTDateTime;
    1166           6 :                     else if (EQUAL(osValue, "Date"))
    1167           3 :                         eType = OFTDate;
    1168           3 :                     else if (EQUAL(osValue, "Time"))
    1169           3 :                         eType = OFTTime;
    1170             :                     else
    1171             :                     {
    1172           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %s",
    1173             :                                  osValue.c_str());
    1174             :                     }
    1175             :                 }
    1176          39 :                 Py_DecRef(myInt);
    1177          39 :                 Py_DecRef(myIntType);
    1178             :             }
    1179             :             else
    1180             :             {
    1181           0 :                 CPLDebug("GDAL", "Unknown field property: %s", osKey.c_str());
    1182             :             }
    1183             :         }
    1184             : 
    1185          39 :         if (!osFieldName.empty())
    1186             :         {
    1187          78 :             OGRFieldDefn oFieldDefn(osFieldName, eType);
    1188          39 :             oFieldDefn.SetSubType(eSubType);
    1189          39 :             m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
    1190             :         }
    1191             :     }
    1192             : 
    1193           3 :     Py_DecRef(poFields);
    1194             : }
    1195             : 
    1196             : /************************************************************************/
    1197             : /*                         GetGeomFields()                              */
    1198             : /************************************************************************/
    1199             : 
    1200           3 : void PythonPluginLayer::GetGeomFields() const
    1201             : {
    1202           3 :     PyObject *poFields = PyObject_GetAttrString(m_poLayer, "geometry_fields");
    1203           3 :     if (ErrOccurredEmitCPLError())
    1204           0 :         return;
    1205           3 :     if (PyCallable_Check(poFields))
    1206             :     {
    1207           0 :         PyObject *poFieldsRes = CallPython(poFields);
    1208           0 :         if (ErrOccurredEmitCPLError())
    1209             :         {
    1210           0 :             Py_DecRef(poFields);
    1211             : 
    1212           0 :             return;
    1213             :         }
    1214           0 :         Py_DecRef(poFields);
    1215           0 :         poFields = poFieldsRes;
    1216             :     }
    1217             : 
    1218           3 :     size_t nSize = PySequence_Size(poFields);
    1219           3 :     if (ErrOccurredEmitCPLError())
    1220             :     {
    1221           0 :         Py_DecRef(poFields);
    1222             : 
    1223           0 :         return;
    1224             :     }
    1225           6 :     for (size_t i = 0; i < nSize; i++)
    1226             :     {
    1227           3 :         PyObject *poItem = PySequence_GetItem(poFields, i);
    1228           3 :         if (poItem == nullptr || PyErr_Occurred())
    1229             :         {
    1230           0 :             CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1231           0 :                      GetPyExceptionString().c_str());
    1232           0 :             Py_DecRef(poFields);
    1233             : 
    1234           0 :             return;
    1235             :         }
    1236             : 
    1237             :         PyObject *key, *value;
    1238           3 :         size_t pos = 0;
    1239           3 :         CPLString osFieldName, osSRS;
    1240           3 :         OGRwkbGeometryType eType = wkbUnknown;
    1241          12 :         while (PyDict_Next(poItem, &pos, &key, &value))
    1242             :         {
    1243           9 :             if (ErrOccurredEmitCPLError())
    1244             :             {
    1245           0 :                 Py_DecRef(poFields);
    1246             : 
    1247           0 :                 return;
    1248             :             }
    1249           9 :             CPLString osKey = GetString(key);
    1250           9 :             if (ErrOccurredEmitCPLError())
    1251             :             {
    1252           0 :                 Py_DecRef(poFields);
    1253             : 
    1254           0 :                 return;
    1255             :             }
    1256           9 :             if (strcmp(osKey, "name") == 0)
    1257             :             {
    1258           3 :                 osFieldName = GetString(value);
    1259           3 :                 if (ErrOccurredEmitCPLError())
    1260             :                 {
    1261           0 :                     Py_DecRef(poFields);
    1262             : 
    1263           0 :                     return;
    1264             :                 }
    1265             :             }
    1266           6 :             else if (strcmp(osKey, "type") == 0)
    1267             :             {
    1268           3 :                 PyObject *myInt = PyLong_FromLong(1);
    1269           3 :                 PyObject *myIntType = PyObject_Type(myInt);
    1270           3 :                 if (PyObject_IsInstance(value, myIntType))
    1271             :                 {
    1272           0 :                     eType =
    1273           0 :                         static_cast<OGRwkbGeometryType>(PyLong_AsLong(value));
    1274           0 :                     if (ErrOccurredEmitCPLError())
    1275             :                     {
    1276           0 :                         Py_DecRef(poFields);
    1277             : 
    1278           0 :                         return;
    1279             :                     }
    1280             :                 }
    1281             :                 else
    1282             :                 {
    1283           3 :                     CPLString osValue = GetString(value);
    1284           3 :                     if (ErrOccurredEmitCPLError())
    1285             :                     {
    1286           0 :                         Py_DecRef(poFields);
    1287             : 
    1288           0 :                         return;
    1289             :                     }
    1290           3 :                     eType = OGRFromOGCGeomType(osValue);
    1291           3 :                     if (eType == wkbUnknown && !EQUAL(osValue, "Geometry"))
    1292             :                     {
    1293           0 :                         CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %s",
    1294             :                                  osValue.c_str());
    1295             :                     }
    1296             :                 }
    1297           3 :                 Py_DecRef(myInt);
    1298           3 :                 Py_DecRef(myIntType);
    1299             :             }
    1300           3 :             else if (strcmp(osKey, "srs") == 0)
    1301             :             {
    1302           3 :                 if (value != Py_None)
    1303             :                 {
    1304           3 :                     osSRS = GetString(value);
    1305           3 :                     if (ErrOccurredEmitCPLError())
    1306             :                     {
    1307           0 :                         Py_DecRef(poFields);
    1308             : 
    1309           0 :                         return;
    1310             :                     }
    1311             :                 }
    1312             :             }
    1313             :             else
    1314             :             {
    1315           0 :                 CPLDebug("GDAL", "Unknown geometry field property: %s",
    1316             :                          osKey.c_str());
    1317             :             }
    1318             :         }
    1319             : 
    1320           6 :         OGRGeomFieldDefn oFieldDefn(osFieldName, eType);
    1321           3 :         if (!osSRS.empty())
    1322             :         {
    1323           3 :             OGRSpatialReference *poSRS = new OGRSpatialReference();
    1324           3 :             poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
    1325           3 :             poSRS->SetFromUserInput(
    1326             :                 osSRS, OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS);
    1327           3 :             oFieldDefn.SetSpatialRef(poSRS);
    1328           3 :             poSRS->Release();
    1329             :         }
    1330           3 :         m_poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
    1331             :     }
    1332             : 
    1333           3 :     Py_DecRef(poFields);
    1334             : }
    1335             : 
    1336             : /************************************************************************/
    1337             : /*                          GetMetadata()                               */
    1338             : /************************************************************************/
    1339             : 
    1340           0 : static char **GetMetadata(PyObject *obj, const char *pszDomain)
    1341             : {
    1342           0 :     if (!PyObject_HasAttrString(obj, "metadata"))
    1343           0 :         return nullptr;
    1344           0 :     PyObject *poMetadata = PyObject_GetAttrString(obj, "metadata");
    1345           0 :     CPLAssert(poMetadata);
    1346             :     PyObject *poMethodRes;
    1347           0 :     if (PyCallable_Check(poMetadata))
    1348             :     {
    1349           0 :         PyObject *pyArgs = PyTuple_New(1);
    1350           0 :         PyTuple_SetItem(pyArgs, 0,
    1351           0 :                         pszDomain && pszDomain[0]
    1352           0 :                             ? PyUnicode_FromString(pszDomain)
    1353           0 :                             : IncRefAndReturn(Py_None));
    1354           0 :         poMethodRes = PyObject_Call(poMetadata, pyArgs, nullptr);
    1355           0 :         Py_DecRef(pyArgs);
    1356           0 :         Py_DecRef(poMetadata);
    1357             : 
    1358           0 :         if (ErrOccurredEmitCPLError())
    1359             :         {
    1360           0 :             return nullptr;
    1361             :         }
    1362             :     }
    1363             :     else
    1364             :     {
    1365           0 :         poMethodRes = poMetadata;
    1366             :     }
    1367             : 
    1368           0 :     if (poMethodRes == Py_None)
    1369             :     {
    1370           0 :         Py_DecRef(poMethodRes);
    1371           0 :         return nullptr;
    1372             :     }
    1373           0 :     char **papszMD = GetDict(poMethodRes);
    1374           0 :     Py_DecRef(poMethodRes);
    1375           0 :     return papszMD;
    1376             : }
    1377             : 
    1378             : /************************************************************************/
    1379             : /*                          GetMetadata()                               */
    1380             : /************************************************************************/
    1381             : 
    1382           0 : char **PythonPluginLayer::GetMetadata(const char *pszDomain)
    1383             : {
    1384           0 :     GIL_Holder oHolder(false);
    1385           0 :     if (pszDomain == nullptr)
    1386           0 :         pszDomain = "";
    1387           0 :     m_oMapMD[pszDomain] = CPLStringList(::GetMetadata(m_poLayer, pszDomain));
    1388           0 :     return m_oMapMD[pszDomain].List();
    1389             : }
    1390             : 
    1391             : /************************************************************************/
    1392             : /*                         PythonPluginDataset                          */
    1393             : /************************************************************************/
    1394             : 
    1395             : class PythonPluginDataset final : public GDALDataset
    1396             : {
    1397             :     PyObject *m_poDataset = nullptr;
    1398             :     mutable std::map<int, std::unique_ptr<OGRLayer>> m_oMapLayer{};
    1399             :     std::map<CPLString, CPLStringList> m_oMapMD{};
    1400             :     bool m_bHasLayersMember = false;
    1401             : 
    1402             :     PythonPluginDataset(const PythonPluginDataset &) = delete;
    1403             :     PythonPluginDataset &operator=(const PythonPluginDataset &) = delete;
    1404             : 
    1405             :   public:
    1406             :     PythonPluginDataset(GDALOpenInfo *poOpenInfo, PyObject *poDataset);
    1407             :     ~PythonPluginDataset() override;
    1408             : 
    1409             :     int GetLayerCount() const override;
    1410             :     OGRLayer *GetLayer(int) const override;
    1411             :     char **GetMetadata(const char *pszDomain = "") override;
    1412             : };
    1413             : 
    1414             : /************************************************************************/
    1415             : /*                         PythonPluginDataset()                        */
    1416             : /************************************************************************/
    1417             : 
    1418           3 : PythonPluginDataset::PythonPluginDataset(GDALOpenInfo *poOpenInfo,
    1419           3 :                                          PyObject *poDataset)
    1420           3 :     : m_poDataset(poDataset)
    1421             : {
    1422           3 :     SetDescription(poOpenInfo->pszFilename);
    1423             : 
    1424           6 :     GIL_Holder oHolder(false);
    1425             : 
    1426           3 :     const auto poLayers = PyObject_GetAttrString(m_poDataset, "layers");
    1427           3 :     PyErr_Clear();
    1428           3 :     if (poLayers)
    1429             :     {
    1430           3 :         if (PySequence_Check(poLayers))
    1431             :         {
    1432           3 :             m_bHasLayersMember = true;
    1433           3 :             const int nSize = static_cast<int>(PySequence_Size(poLayers));
    1434           6 :             for (int i = 0; i < nSize; i++)
    1435             :             {
    1436           3 :                 const auto poLayer = PySequence_GetItem(poLayers, i);
    1437           3 :                 Py_IncRef(poLayer);
    1438           6 :                 m_oMapLayer[i] = std::unique_ptr<PythonPluginLayer>(
    1439           6 :                     new PythonPluginLayer(poLayer));
    1440             :             }
    1441             :         }
    1442           3 :         Py_DecRef(poLayers);
    1443             :     }
    1444           3 : }
    1445             : 
    1446             : /************************************************************************/
    1447             : /*                        ~PythonPluginDataset()                        */
    1448             : /************************************************************************/
    1449             : 
    1450           6 : PythonPluginDataset::~PythonPluginDataset()
    1451             : {
    1452           6 :     GIL_Holder oHolder(false);
    1453             : 
    1454           3 :     if (m_poDataset && PyObject_HasAttrString(m_poDataset, "close"))
    1455             :     {
    1456           3 :         PyObject *poClose = PyObject_GetAttrString(m_poDataset, "close");
    1457           3 :         PyObject *pyArgs = PyTuple_New(0);
    1458           3 :         Py_DecRef(PyObject_Call(poClose, pyArgs, nullptr));
    1459           3 :         Py_DecRef(pyArgs);
    1460           3 :         Py_DecRef(poClose);
    1461             : 
    1462           3 :         CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
    1463             :     }
    1464           3 :     Py_DecRef(m_poDataset);
    1465           6 : }
    1466             : 
    1467             : /************************************************************************/
    1468             : /*                          GetLayerCount()                             */
    1469             : /************************************************************************/
    1470             : 
    1471           3 : int PythonPluginDataset::GetLayerCount() const
    1472             : {
    1473           3 :     if (m_bHasLayersMember)
    1474           3 :         return static_cast<int>(m_oMapLayer.size());
    1475             : 
    1476           0 :     GIL_Holder oHolder(false);
    1477           0 :     return GetIntRes(m_poDataset, "layer_count");
    1478             : }
    1479             : 
    1480             : /************************************************************************/
    1481             : /*                            GetLayer()                                */
    1482             : /************************************************************************/
    1483             : 
    1484           9 : OGRLayer *PythonPluginDataset::GetLayer(int idx) const
    1485             : {
    1486           9 :     if (idx < 0)
    1487           3 :         return nullptr;
    1488             : 
    1489           6 :     auto oIter = m_oMapLayer.find(idx);
    1490           6 :     if (oIter != m_oMapLayer.end())
    1491           3 :         return m_oMapLayer[idx].get();
    1492             : 
    1493           3 :     if (m_bHasLayersMember)
    1494           3 :         return nullptr;
    1495             : 
    1496           0 :     GIL_Holder oHolder(false);
    1497             : 
    1498           0 :     PyObject *poMethod = PyObject_GetAttrString(m_poDataset, "layer");
    1499           0 :     if (poMethod == nullptr || PyErr_Occurred())
    1500             :     {
    1501           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1502           0 :                  GetPyExceptionString().c_str());
    1503           0 :         return nullptr;
    1504             :     }
    1505             : 
    1506           0 :     PyObject *poMethodRes = CallPython(poMethod, idx);
    1507           0 :     if (ErrOccurredEmitCPLError())
    1508             :     {
    1509           0 :         Py_DecRef(poMethod);
    1510           0 :         return nullptr;
    1511             :     }
    1512           0 :     Py_DecRef(poMethod);
    1513             : 
    1514           0 :     if (poMethodRes == Py_None)
    1515             :     {
    1516           0 :         m_oMapLayer[idx] = nullptr;
    1517           0 :         Py_DecRef(poMethodRes);
    1518           0 :         return nullptr;
    1519             :     }
    1520             :     return m_oMapLayer
    1521           0 :         .insert(std::make_pair(idx, std::unique_ptr<PythonPluginLayer>(
    1522           0 :                                         new PythonPluginLayer(poMethodRes))))
    1523           0 :         .first->second.get();
    1524             : }
    1525             : 
    1526             : /************************************************************************/
    1527             : /*                          GetMetadata()                               */
    1528             : /************************************************************************/
    1529             : 
    1530           0 : char **PythonPluginDataset::GetMetadata(const char *pszDomain)
    1531             : {
    1532           0 :     GIL_Holder oHolder(false);
    1533           0 :     if (pszDomain == nullptr)
    1534           0 :         pszDomain = "";
    1535           0 :     m_oMapMD[pszDomain] = CPLStringList(::GetMetadata(m_poDataset, pszDomain));
    1536           0 :     return m_oMapMD[pszDomain].List();
    1537             : }
    1538             : 
    1539             : /************************************************************************/
    1540             : /*                          PythonPluginDriver                          */
    1541             : /************************************************************************/
    1542             : 
    1543             : class PythonPluginDriver final : public GDALDriver
    1544             : {
    1545             :     CPLMutex *m_hMutex = nullptr;
    1546             :     CPLString m_osFilename;
    1547             :     PyObject *m_poPlugin = nullptr;
    1548             : 
    1549             :     PythonPluginDriver(const PythonPluginDriver &) = delete;
    1550             :     PythonPluginDriver &operator=(const PythonPluginDriver &) = delete;
    1551             : 
    1552             :     bool LoadPlugin();
    1553             : 
    1554             :     int Identify(GDALOpenInfo *);
    1555             :     static int IdentifyEx(GDALDriver *, GDALOpenInfo *);
    1556             : 
    1557             :     GDALDataset *Open(GDALOpenInfo *);
    1558             :     static GDALDataset *OpenEx(GDALDriver *, GDALOpenInfo *);
    1559             : 
    1560             :   public:
    1561             :     PythonPluginDriver(const char *pszFilename, const char *pszPluginName,
    1562             :                        char **papszMD);
    1563             :     ~PythonPluginDriver() override;
    1564             : };
    1565             : 
    1566             : /************************************************************************/
    1567             : /*                            LoadPlugin()                              */
    1568             : /************************************************************************/
    1569             : 
    1570           3 : bool PythonPluginDriver::LoadPlugin()
    1571             : {
    1572           6 :     CPLMutexHolder oMutexHolder(&m_hMutex);
    1573           3 :     if (m_poPlugin)
    1574           0 :         return true;
    1575           3 :     if (!InitializePythonAndLoadGDALPythonDriverModule())
    1576           0 :         return false;
    1577           6 :     GIL_Holder oHolder(false);
    1578             : 
    1579           6 :     CPLString osStr;
    1580           3 :     VSILFILE *fp = VSIFOpenL(m_osFilename, "rb");
    1581           3 :     VSIFSeekL(fp, 0, SEEK_END);
    1582           3 :     auto nSize = VSIFTellL(fp);
    1583           3 :     if (nSize > 10 * 1024 * 1024)
    1584             :     {
    1585           0 :         VSIFCloseL(fp);
    1586           0 :         return false;
    1587             :     }
    1588           3 :     VSIFSeekL(fp, 0, SEEK_SET);
    1589           3 :     osStr.resize(static_cast<size_t>(nSize));
    1590           3 :     VSIFReadL(&osStr[0], 1, static_cast<size_t>(nSize), fp);
    1591           3 :     VSIFCloseL(fp);
    1592             :     PyObject *poCompiledString =
    1593           3 :         Py_CompileString(osStr, m_osFilename, Py_file_input);
    1594           3 :     if (poCompiledString == nullptr || PyErr_Occurred())
    1595             :     {
    1596           0 :         CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
    1597           0 :                  GetPyExceptionString().c_str());
    1598           0 :         return false;
    1599             :     }
    1600           6 :     const CPLString osPluginModuleName(CPLGetBasenameSafe(m_osFilename));
    1601             :     PyObject *poModule =
    1602           3 :         PyImport_ExecCodeModule(osPluginModuleName, poCompiledString);
    1603           3 :     Py_DecRef(poCompiledString);
    1604             : 
    1605           3 :     if (poModule == nullptr || PyErr_Occurred())
    1606             :     {
    1607           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1608           0 :                  GetPyExceptionString().c_str());
    1609           0 :         return false;
    1610             :     }
    1611             : 
    1612           3 :     PyObject *poInstantiate = PyObject_GetAttrString(gpoGDALPythonDriverModule,
    1613             :                                                      "_instantiate_plugin");
    1614           3 :     CPLAssert(poInstantiate);
    1615             : 
    1616           3 :     PyObject *pyArgs = PyTuple_New(1);
    1617           3 :     PyTuple_SetItem(pyArgs, 0, poModule);
    1618           3 :     PyObject *poPlugin = PyObject_Call(poInstantiate, pyArgs, nullptr);
    1619           3 :     Py_DecRef(pyArgs);
    1620           3 :     Py_DecRef(poInstantiate);
    1621             : 
    1622           3 :     if (ErrOccurredEmitCPLError())
    1623             :     {
    1624           1 :         return false;
    1625             :     }
    1626             :     else
    1627             :     {
    1628           2 :         m_poPlugin = poPlugin;
    1629           2 :         return true;
    1630             :     }
    1631             : }
    1632             : 
    1633             : /************************************************************************/
    1634             : /*                       BuildIdentifyOpenArgs()                        */
    1635             : /************************************************************************/
    1636             : 
    1637          11 : static void BuildIdentifyOpenArgs(GDALOpenInfo *poOpenInfo, PyObject *&pyArgs,
    1638             :                                   PyObject *&pyKwargs)
    1639             : {
    1640          11 :     pyArgs = PyTuple_New(3);
    1641          11 :     PyTuple_SetItem(pyArgs, 0, PyUnicode_FromString(poOpenInfo->pszFilename));
    1642          11 :     PyTuple_SetItem(pyArgs, 1,
    1643          11 :                     PyBytes_FromStringAndSize(poOpenInfo->pabyHeader,
    1644          11 :                                               poOpenInfo->nHeaderBytes));
    1645          11 :     PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(poOpenInfo->nOpenFlags));
    1646          11 :     pyKwargs = PyDict_New();
    1647          11 :     PyObject *pyOpenOptions = PyDict_New();
    1648          11 :     PyDict_SetItemString(pyKwargs, "open_options", pyOpenOptions);
    1649          11 :     if (poOpenInfo->papszOpenOptions)
    1650             :     {
    1651          12 :         for (char **papszIter = poOpenInfo->papszOpenOptions; *papszIter;
    1652             :              ++papszIter)
    1653             :         {
    1654           6 :             char *pszKey = nullptr;
    1655           6 :             const char *pszValue = CPLParseNameValue(*papszIter, &pszKey);
    1656           6 :             if (pszKey && pszValue)
    1657             :             {
    1658           6 :                 auto pyValue = PyUnicode_FromString(pszValue);
    1659           6 :                 PyDict_SetItemString(pyOpenOptions, pszKey, pyValue);
    1660           6 :                 Py_DecRef(pyValue);
    1661             :             }
    1662           6 :             CPLFree(pszKey);
    1663             :         }
    1664             :     }
    1665          11 :     Py_DecRef(pyOpenOptions);
    1666          11 : }
    1667             : 
    1668             : /************************************************************************/
    1669             : /*                            Identify()                                */
    1670             : /************************************************************************/
    1671             : 
    1672          10 : int PythonPluginDriver::Identify(GDALOpenInfo *poOpenInfo)
    1673             : {
    1674          10 :     if (m_poPlugin == nullptr)
    1675             :     {
    1676           3 :         if (!LoadPlugin())
    1677           1 :             return FALSE;
    1678             :     }
    1679             : 
    1680          18 :     GIL_Holder oHolder(false);
    1681             : 
    1682           9 :     PyObject *poMethod = PyObject_GetAttrString(m_poPlugin, "identify");
    1683           9 :     if (poMethod == nullptr || PyErr_Occurred())
    1684             :     {
    1685           1 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1686           2 :                  GetPyExceptionString().c_str());
    1687           1 :         return 0;
    1688             :     }
    1689             : 
    1690           8 :     PyObject *pyArgs = nullptr;
    1691           8 :     PyObject *pyKwargs = nullptr;
    1692           8 :     BuildIdentifyOpenArgs(poOpenInfo, pyArgs, pyKwargs);
    1693           8 :     PyObject *poMethodRes = PyObject_Call(poMethod, pyArgs, pyKwargs);
    1694           8 :     Py_DecRef(pyArgs);
    1695           8 :     Py_DecRef(pyKwargs);
    1696             : 
    1697           8 :     if (ErrOccurredEmitCPLError())
    1698             :     {
    1699           0 :         Py_DecRef(poMethod);
    1700           0 :         return 0;
    1701             :     }
    1702           8 :     Py_DecRef(poMethod);
    1703             : 
    1704           8 :     int nRes = static_cast<int>(PyLong_AsLong(poMethodRes));
    1705           8 :     if (ErrOccurredEmitCPLError())
    1706             :     {
    1707           0 :         Py_DecRef(poMethodRes);
    1708           0 :         return 0;
    1709             :     }
    1710             : 
    1711           8 :     Py_DecRef(poMethodRes);
    1712           8 :     return nRes;
    1713             : }
    1714             : 
    1715             : /************************************************************************/
    1716             : /*                            IdentifyEx()                              */
    1717             : /************************************************************************/
    1718             : 
    1719          10 : int PythonPluginDriver::IdentifyEx(GDALDriver *poDrv, GDALOpenInfo *poOpenInfo)
    1720             : {
    1721          10 :     return reinterpret_cast<PythonPluginDriver *>(poDrv)->Identify(poOpenInfo);
    1722             : }
    1723             : 
    1724             : /************************************************************************/
    1725             : /*                               Open()                                 */
    1726             : /************************************************************************/
    1727             : 
    1728           3 : GDALDataset *PythonPluginDriver::Open(GDALOpenInfo *poOpenInfo)
    1729             : {
    1730           3 :     if (m_poPlugin == nullptr)
    1731             :     {
    1732           0 :         if (!LoadPlugin())
    1733           0 :             return nullptr;
    1734             :     }
    1735             : 
    1736           6 :     GIL_Holder oHolder(false);
    1737             : 
    1738           3 :     PyObject *poMethod = PyObject_GetAttrString(m_poPlugin, "open");
    1739           3 :     if (poMethod == nullptr || PyErr_Occurred())
    1740             :     {
    1741           0 :         CPLError(CE_Failure, CPLE_AppDefined, "%s",
    1742           0 :                  GetPyExceptionString().c_str());
    1743           0 :         return nullptr;
    1744             :     }
    1745             : 
    1746           3 :     PyObject *pyArgs = nullptr;
    1747           3 :     PyObject *pyKwargs = nullptr;
    1748           3 :     BuildIdentifyOpenArgs(poOpenInfo, pyArgs, pyKwargs);
    1749           3 :     PyObject *poMethodRes = PyObject_Call(poMethod, pyArgs, pyKwargs);
    1750           3 :     Py_DecRef(pyArgs);
    1751           3 :     Py_DecRef(pyKwargs);
    1752             : 
    1753           3 :     if (ErrOccurredEmitCPLError())
    1754             :     {
    1755           0 :         Py_DecRef(poMethod);
    1756           0 :         return nullptr;
    1757             :     }
    1758           3 :     Py_DecRef(poMethod);
    1759             : 
    1760           3 :     if (poMethodRes == Py_None)
    1761             :     {
    1762           0 :         Py_DecRef(poMethodRes);
    1763           0 :         return nullptr;
    1764             :     }
    1765           3 :     return new PythonPluginDataset(poOpenInfo, poMethodRes);
    1766             : }
    1767             : 
    1768             : /************************************************************************/
    1769             : /*                              OpenEx()                                */
    1770             : /************************************************************************/
    1771             : 
    1772           3 : GDALDataset *PythonPluginDriver::OpenEx(GDALDriver *poDrv,
    1773             :                                         GDALOpenInfo *poOpenInfo)
    1774             : {
    1775           3 :     return reinterpret_cast<PythonPluginDriver *>(poDrv)->Open(poOpenInfo);
    1776             : }
    1777             : 
    1778             : /************************************************************************/
    1779             : /*                        PythonPluginDriver()                          */
    1780             : /************************************************************************/
    1781             : 
    1782           3 : PythonPluginDriver::PythonPluginDriver(const char *pszFilename,
    1783             :                                        const char *pszPluginName,
    1784           3 :                                        char **papszMD)
    1785           3 :     : m_hMutex(nullptr), m_osFilename(pszFilename), m_poPlugin(nullptr)
    1786             : {
    1787           3 :     SetDescription(pszPluginName);
    1788           3 :     SetMetadata(papszMD);
    1789           3 :     pfnIdentifyEx = IdentifyEx;
    1790           3 :     pfnOpenWithDriverArg = OpenEx;
    1791           3 : }
    1792             : 
    1793             : /************************************************************************/
    1794             : /*                       ~PythonPluginDriver()                          */
    1795             : /************************************************************************/
    1796             : 
    1797           6 : PythonPluginDriver::~PythonPluginDriver()
    1798             : {
    1799           3 :     if (m_hMutex)
    1800           3 :         CPLDestroyMutex(m_hMutex);
    1801             : 
    1802           3 :     if (m_poPlugin)
    1803             :     {
    1804           4 :         GIL_Holder oHolder(false);
    1805           2 :         Py_DecRef(m_poPlugin);
    1806             :     }
    1807           6 : }
    1808             : 
    1809             : /************************************************************************/
    1810             : /*                         LoadPythonDriver()                           */
    1811             : /************************************************************************/
    1812             : 
    1813           5 : static void LoadPythonDriver(const char *pszFilename)
    1814             : {
    1815           5 :     char **papszLines = CSLLoad2(pszFilename, 1000, 1000, nullptr);
    1816           5 :     if (papszLines == nullptr)
    1817             :     {
    1818           0 :         return;
    1819             :     }
    1820          10 :     CPLString osPluginName;
    1821           5 :     char **papszMD = nullptr;
    1822           5 :     bool bAPIOK = false;
    1823           5 :     constexpr int CURRENT_API_VERSION = 1;
    1824         306 :     for (int i = 0; papszLines[i] != nullptr; i++)
    1825             :     {
    1826         301 :         const char *pszLine = papszLines[i];
    1827         301 :         if (!STARTS_WITH_CI(pszLine, "# gdal: DRIVER_"))
    1828         284 :             continue;
    1829          17 :         pszLine += strlen("# gdal: DRIVER_");
    1830             : 
    1831          17 :         const char *pszEqual = strchr(pszLine, '=');
    1832          17 :         if (pszEqual == nullptr)
    1833           0 :             continue;
    1834             : 
    1835          34 :         CPLString osKey(pszLine);
    1836          17 :         osKey.resize(pszEqual - pszLine);
    1837          17 :         osKey.Trim();
    1838             : 
    1839          34 :         CPLString osValue(pszEqual + 1);
    1840          17 :         osValue.Trim();
    1841             : 
    1842          17 :         char chQuote = 0;
    1843          17 :         if (!osValue.empty() && (osValue[0] == '"' || osValue[0] == '\''))
    1844             :         {
    1845          13 :             chQuote = osValue[0];
    1846          13 :             osValue = osValue.substr(1);
    1847             :         }
    1848          17 :         if (!osValue.empty() && osValue[osValue.size() - 1] == chQuote)
    1849          13 :             osValue.resize(osValue.size() - 1);
    1850          17 :         if (EQUAL(osKey, "NAME"))
    1851             :         {
    1852           4 :             osPluginName = std::move(osValue);
    1853             :         }
    1854          13 :         else if (EQUAL(osKey, "SUPPORTED_API_VERSION"))
    1855             :         {
    1856             :             const CPLStringList aosTokens(
    1857           8 :                 CSLTokenizeString2(osValue, "[, ]", 0));
    1858           5 :             for (int j = 0; j < aosTokens.size(); ++j)
    1859             :             {
    1860           4 :                 if (atoi(aosTokens[j]) == CURRENT_API_VERSION)
    1861             :                 {
    1862           3 :                     bAPIOK = true;
    1863           3 :                     break;
    1864             :                 }
    1865             :             }
    1866             :         }
    1867             :         else
    1868             :         {
    1869           9 :             papszMD = CSLSetNameValue(papszMD, osKey.c_str(), osValue);
    1870             :         }
    1871             :     }
    1872           5 :     papszMD = CSLSetNameValue(papszMD, "DRIVER_LANGUAGE", "PYTHON");
    1873           5 :     CSLDestroy(papszLines);
    1874             : 
    1875           5 :     if (osPluginName.empty())
    1876             :     {
    1877           1 :         CPLError(CE_Warning, CPLE_AppDefined,
    1878             :                  "Missing global # gdal: DRIVER_NAME declaration in %s",
    1879             :                  pszFilename);
    1880             :     }
    1881           4 :     else if (!bAPIOK)
    1882             :     {
    1883           1 :         CPLDebug(
    1884             :             "GDAL",
    1885             :             "Plugin %s does not declare # gdal: DRIVER_SUPPORTED_API_VERSION "
    1886             :             "or not at version %d",
    1887             :             osPluginName.c_str(), CURRENT_API_VERSION);
    1888             :     }
    1889           3 :     else if (GDALGetDriverByName(osPluginName) == nullptr)
    1890             :     {
    1891             :         GDALDriver *poDriver =
    1892           3 :             new PythonPluginDriver(pszFilename, osPluginName, papszMD);
    1893           3 :         GetGDALDriverManager()->RegisterDriver(poDriver);
    1894             :     }
    1895           5 :     CSLDestroy(papszMD);
    1896             : }
    1897             : 
    1898             : /************************************************************************/
    1899             : /*                        AutoLoadPythonDrivers()                       */
    1900             : /************************************************************************/
    1901             : 
    1902             : /**
    1903             :  * \brief Auto-load GDAL drivers from Python scripts.
    1904             :  *
    1905             :  * This function will automatically load drivers from Python scripts.
    1906             :  * It searches them first from the directory pointed by the
    1907             :  * GDAL_PYTHON_DRIVER_PATH configuration option. If not defined, it will
    1908             :  * use GDAL_DRIVER_PATH. If not defined, it will use the path for
    1909             :  * drivers hardcoded at build time.
    1910             :  * Scripts must begin with gdal_ or ogr_ and end up with .py
    1911             :  *
    1912             :  * @since GDAL 3.1
    1913             :  */
    1914             : 
    1915        2055 : void GDALDriverManager::AutoLoadPythonDrivers()
    1916             : {
    1917             :     const char *pszPythonDriverPath =
    1918        2055 :         CPLGetConfigOption("GDAL_PYTHON_DRIVER_PATH", nullptr);
    1919        2055 :     if (pszPythonDriverPath == nullptr)
    1920             :     {
    1921        2050 :         pszPythonDriverPath = CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr);
    1922             :     }
    1923        2055 :     char **papszSearchPaths = GetSearchPaths(pszPythonDriverPath);
    1924             : 
    1925             :     /* -------------------------------------------------------------------- */
    1926             :     /*      Format the ABI version specific subdirectory to look in.        */
    1927             :     /* -------------------------------------------------------------------- */
    1928        4110 :     CPLString osABIVersion;
    1929             : 
    1930        2055 :     osABIVersion.Printf("%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
    1931             : 
    1932             :     /* -------------------------------------------------------------------- */
    1933             :     /*      Scan each directory                                             */
    1934             :     /* -------------------------------------------------------------------- */
    1935        4110 :     std::vector<CPLString> aosPythonFiles;
    1936        2055 :     const int nSearchPaths = CSLCount(papszSearchPaths);
    1937        4110 :     for (int iDir = 0; iDir < nSearchPaths; ++iDir)
    1938             :     {
    1939             :         std::string osABISpecificDir =
    1940        4110 :             CPLFormFilenameSafe(papszSearchPaths[iDir], osABIVersion, nullptr);
    1941             : 
    1942             :         VSIStatBufL sStatBuf;
    1943        2055 :         if (VSIStatL(osABISpecificDir.c_str(), &sStatBuf) != 0)
    1944        2055 :             osABISpecificDir = papszSearchPaths[iDir];
    1945             : 
    1946        2055 :         char **papszFiles = CPLReadDir(osABISpecificDir.c_str());
    1947       82024 :         for (int i = 0; papszFiles && papszFiles[i]; i++)
    1948             :         {
    1949      198907 :             if ((STARTS_WITH_CI(papszFiles[i], "gdal_") ||
    1950      151724 :                  STARTS_WITH_CI(papszFiles[i], "ogr_")) &&
    1951      151724 :                 EQUAL(CPLGetExtensionSafe(papszFiles[i]).c_str(), "py"))
    1952             :             {
    1953           5 :                 aosPythonFiles.push_back(CPLFormFilenameSafe(
    1954           5 :                     osABISpecificDir.c_str(), papszFiles[i], nullptr));
    1955             :             }
    1956             :         }
    1957        2055 :         CSLDestroy(papszFiles);
    1958             :     }
    1959        2055 :     CSLDestroy(papszSearchPaths);
    1960             : 
    1961        2060 :     for (const auto &osPythonFile : aosPythonFiles)
    1962             :     {
    1963           5 :         LoadPythonDriver(osPythonFile);
    1964             :     }
    1965        2055 : }
    1966             : 
    1967             : /************************************************************************/
    1968             : /*                        CleanupPythonDrivers()                        */
    1969             : /************************************************************************/
    1970             : 
    1971        1123 : void GDALDriverManager::CleanupPythonDrivers()
    1972             : {
    1973        1123 :     if (gpoGDALPythonDriverModule)
    1974             :     {
    1975             :         // On Windows, with pytest, GDALDestroy() can call this after having
    1976             :         // stopped Python, so do not attempt any Python related action.
    1977           0 :         if (Py_IsInitialized())
    1978             :         {
    1979           0 :             GIL_Holder oHolder(false);
    1980           0 :             Py_DecRef(Py_None);
    1981           0 :             Py_DecRef(gpoGDALPythonDriverModule);
    1982             :         }
    1983           0 :         Py_None = nullptr;
    1984           0 :         gpoGDALPythonDriverModule = nullptr;
    1985             :     }
    1986        1123 : }
    1987             : 
    1988             : #endif

Generated by: LCOV version 1.14