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

Generated by: LCOV version 1.14