2009 lines
64 KiB
C++
2009 lines
64 KiB
C++
/******************************************************************************
|
|
*
|
|
* Project: GDAL Core
|
|
* Purpose: Python plugin loader
|
|
* Author: Even Rouault, <even dot rouault at spatialys dot com>
|
|
*
|
|
******************************************************************************
|
|
* Copyright (c) 2017-2019, Even Rouault, <even dot rouault at spatialys dot
|
|
*com>
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
****************************************************************************/
|
|
|
|
#include "cpl_conv.h"
|
|
#include "cpl_string.h"
|
|
#include "gdal_priv.h"
|
|
#include "ogrsf_frmts.h"
|
|
#include "gdalpython.h"
|
|
|
|
#include <algorithm>
|
|
#include <memory>
|
|
#include <mutex>
|
|
|
|
using namespace GDALPy;
|
|
|
|
#ifdef GDAL_NO_AUTOLOAD
|
|
void GDALDriverManager::AutoLoadPythonDrivers()
|
|
{
|
|
}
|
|
|
|
void GDALDriverManager::CleanupPythonDrivers()
|
|
{
|
|
}
|
|
|
|
#else
|
|
|
|
static PyObject *layer_featureCount(PyObject *m, PyObject *args,
|
|
PyObject *kwargs);
|
|
|
|
static const PyMethodDef gdal_python_driver_methods[] = {
|
|
{"layer_featureCount", layer_featureCount, METH_VARARGS | METH_KEYWORDS,
|
|
nullptr},
|
|
{nullptr, nullptr, 0, nullptr}};
|
|
|
|
static PyObject *Py_None = nullptr;
|
|
|
|
static PyObject *gpoGDALPythonDriverModule = nullptr;
|
|
|
|
/************************************************************************/
|
|
/* IncRefAndReturn() */
|
|
/************************************************************************/
|
|
|
|
static PyObject *IncRefAndReturn(PyObject *obj)
|
|
{
|
|
Py_IncRef(obj);
|
|
return obj;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CallPython() */
|
|
/************************************************************************/
|
|
|
|
static PyObject *CallPython(PyObject *function)
|
|
{
|
|
PyObject *pyArgs = PyTuple_New(0);
|
|
PyObject *pRet = PyObject_Call(function, pyArgs, nullptr);
|
|
Py_DecRef(pyArgs);
|
|
return pRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CallPython() */
|
|
/************************************************************************/
|
|
|
|
static PyObject *CallPython(PyObject *function, int nVal)
|
|
{
|
|
PyObject *pyArgs = PyTuple_New(1);
|
|
PyTuple_SetItem(pyArgs, 0, PyLong_FromLong(nVal));
|
|
PyObject *pRet = PyObject_Call(function, pyArgs, nullptr);
|
|
Py_DecRef(pyArgs);
|
|
return pRet;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* InitializePythonAndLoadGDALPythonDriverModule() */
|
|
/************************************************************************/
|
|
|
|
static bool InitializePythonAndLoadGDALPythonDriverModule()
|
|
{
|
|
if (!GDALPythonInitialize())
|
|
return false;
|
|
|
|
static std::mutex gMutex;
|
|
static bool gbAlreadyInitialized = false;
|
|
std::lock_guard<std::mutex> guard(gMutex);
|
|
|
|
if (gbAlreadyInitialized)
|
|
return true;
|
|
gbAlreadyInitialized = true;
|
|
|
|
GIL_Holder oHolder(false);
|
|
|
|
static PyModuleDef gdal_python_driver_moduledef = {
|
|
PyModuleDef_HEAD_INIT,
|
|
"_gdal_python_driver",
|
|
nullptr,
|
|
static_cast<Py_ssize_t>(-1), // sizeof(struct module_state),
|
|
gdal_python_driver_methods,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr,
|
|
nullptr};
|
|
|
|
PyObject *module =
|
|
PyModule_Create2(&gdal_python_driver_moduledef, PYTHON_API_VERSION);
|
|
// Add module to importable modules
|
|
PyObject *sys = PyImport_ImportModule("sys");
|
|
PyObject *sys_modules = PyObject_GetAttrString(sys, "modules");
|
|
PyDict_SetItemString(sys_modules, "_gdal_python_driver", module);
|
|
Py_DecRef(sys_modules);
|
|
Py_DecRef(sys);
|
|
Py_DecRef(module);
|
|
|
|
PyObject *poCompiledString = Py_CompileString(
|
|
"import _gdal_python_driver\n"
|
|
"import json\n"
|
|
"import inspect\n"
|
|
"import sys\n"
|
|
"class BaseLayer:\n"
|
|
" RandomRead='RandomRead'\n"
|
|
" FastSpatialFilter='FastSpatialFilter'\n"
|
|
" FastFeatureCount='FastFeatureCount'\n"
|
|
" FastGetExtent='FastGetExtent'\n"
|
|
" StringsAsUTF8='StringsAsUTF8'\n"
|
|
"\n"
|
|
" def __init__(self):\n"
|
|
" pass\n"
|
|
"\n"
|
|
" def feature_count(self, force):\n"
|
|
" assert isinstance(self, BaseLayer), 'self not instance of "
|
|
"BaseLayer'\n"
|
|
" return _gdal_python_driver.layer_featureCount(self, force)\n"
|
|
"\n"
|
|
"class BaseDataset:\n"
|
|
" def __init__(self):\n"
|
|
" pass\n"
|
|
"\n"
|
|
"class BaseDriver:\n"
|
|
" def __init__(self):\n"
|
|
" pass\n"
|
|
"\n"
|
|
"def _gdal_returnNone():\n"
|
|
" return None"
|
|
"\n"
|
|
"def _gdal_json_serialize(d):\n"
|
|
" return json.dumps(d)\n"
|
|
"\n"
|
|
"def _instantiate_plugin(plugin_module):\n"
|
|
" candidate = None\n"
|
|
" for key in dir(plugin_module):\n"
|
|
" elt = getattr(plugin_module, key)\n"
|
|
" if inspect.isclass(elt) and sys.modules[elt.__module__] == "
|
|
"plugin_module and issubclass(elt, BaseDriver):\n"
|
|
" if candidate:\n"
|
|
" raise Exception(\"several classes in \" + "
|
|
"plugin_module.__name__ + \" deriving from "
|
|
"gdal_python_driver.BaseDriver\")\n"
|
|
" candidate = elt\n"
|
|
" if candidate:\n"
|
|
" return candidate()\n"
|
|
" raise Exception(\"cannot find class in \" + plugin_module.__name__ "
|
|
"+ \" deriving from gdal_python_driver.BaseDriver\")\n",
|
|
"gdal_python_driver", Py_file_input);
|
|
gpoGDALPythonDriverModule =
|
|
PyImport_ExecCodeModule("gdal_python_driver", poCompiledString);
|
|
Py_DecRef(poCompiledString);
|
|
|
|
// Initialize Py_None
|
|
PyObject *returnNone =
|
|
PyObject_GetAttrString(gpoGDALPythonDriverModule, "_gdal_returnNone");
|
|
Py_None = CallPython(returnNone);
|
|
Py_DecRef(returnNone);
|
|
|
|
return true;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetIntRes() */
|
|
/************************************************************************/
|
|
|
|
static int GetIntRes(PyObject *poObj, const char *pszFunctionName)
|
|
{
|
|
PyObject *poMethod = PyObject_GetAttrString(poObj, pszFunctionName);
|
|
if (poMethod == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
return 0;
|
|
}
|
|
|
|
PyObject *poMethodRes = CallPython(poMethod);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethod);
|
|
return 0;
|
|
}
|
|
Py_DecRef(poMethod);
|
|
|
|
int nRes = static_cast<int>(PyLong_AsLong(poMethodRes));
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethodRes);
|
|
return 0;
|
|
}
|
|
|
|
Py_DecRef(poMethodRes);
|
|
return nRes;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetDict() */
|
|
/************************************************************************/
|
|
|
|
static char **GetDict(PyObject *poDict)
|
|
{
|
|
PyObject *key, *value;
|
|
size_t pos = 0;
|
|
|
|
char **papszRes = nullptr;
|
|
while (PyDict_Next(poDict, &pos, &key, &value))
|
|
{
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
CPLString osKey = GetString(key);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
CPLString osValue = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
papszRes = CSLSetNameValue(papszRes, osKey, osValue);
|
|
}
|
|
return papszRes;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetStringRes() */
|
|
/************************************************************************/
|
|
|
|
static CPLString GetStringRes(PyObject *poObj, const char *pszFunctionName,
|
|
bool bOptionalMethod = false)
|
|
{
|
|
PyObject *poMethod = PyObject_GetAttrString(poObj, pszFunctionName);
|
|
if (poMethod == nullptr || PyErr_Occurred())
|
|
{
|
|
if (bOptionalMethod)
|
|
{
|
|
PyErr_Clear();
|
|
}
|
|
else
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
}
|
|
return CPLString();
|
|
}
|
|
|
|
PyObject *poMethodRes = CallPython(poMethod);
|
|
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethod);
|
|
return CPLString();
|
|
}
|
|
Py_DecRef(poMethod);
|
|
|
|
CPLString osRes = GetString(poMethodRes);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethodRes);
|
|
return CPLString();
|
|
}
|
|
|
|
Py_DecRef(poMethodRes);
|
|
return osRes;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* PythonPluginLayer */
|
|
/************************************************************************/
|
|
|
|
class PythonPluginLayer final : public OGRLayer
|
|
{
|
|
PyObject *m_poLayer = nullptr;
|
|
OGRFeatureDefn *m_poFeatureDefn = nullptr;
|
|
CPLString m_osName{};
|
|
CPLString m_osFIDColumn{};
|
|
bool m_bHasFIDColumn = false;
|
|
std::map<CPLString, CPLStringList> m_oMapMD{};
|
|
PyObject *m_pyFeatureByIdMethod = nullptr;
|
|
bool m_bIteratorHonourSpatialFilter = false;
|
|
bool m_bIteratorHonourAttributeFilter = false;
|
|
bool m_bFeatureCountHonourSpatialFilter = false;
|
|
bool m_bFeatureCountHonourAttributeFilter = false;
|
|
PyObject *m_pyIterator = nullptr;
|
|
bool m_bStopIteration = false;
|
|
|
|
void RefreshHonourFlags();
|
|
void StoreSpatialFilter();
|
|
|
|
void GetFields();
|
|
void GetGeomFields();
|
|
OGRFeature *TranslateToOGRFeature(PyObject *poObj);
|
|
|
|
PythonPluginLayer(const PythonPluginLayer &) = delete;
|
|
PythonPluginLayer &operator=(const PythonPluginLayer &) = delete;
|
|
|
|
public:
|
|
explicit PythonPluginLayer(PyObject *poLayer);
|
|
~PythonPluginLayer();
|
|
|
|
const char *GetName() override;
|
|
void ResetReading() override;
|
|
OGRFeature *GetNextFeature() override;
|
|
OGRFeature *GetFeature(GIntBig nFID) override;
|
|
int TestCapability(const char *) override;
|
|
OGRFeatureDefn *GetLayerDefn() override;
|
|
|
|
GIntBig GetFeatureCount(int bForce) override;
|
|
const char *GetFIDColumn() override;
|
|
OGRErr SetAttributeFilter(const char *) override;
|
|
|
|
void SetSpatialFilter(OGRGeometry *) override;
|
|
void SetSpatialFilter(int iGeomField, OGRGeometry *) override;
|
|
|
|
OGRErr GetExtent(OGREnvelope *psExtent, int bForce) override;
|
|
|
|
OGRErr GetExtent(int iGeomField, OGREnvelope *psExtent, int bForce) override
|
|
{
|
|
return OGRLayer::GetExtent(iGeomField, psExtent, bForce);
|
|
}
|
|
|
|
char **GetMetadata(const char *pszDomain = "") override;
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* PythonPluginLayer() */
|
|
/************************************************************************/
|
|
|
|
PythonPluginLayer::PythonPluginLayer(PyObject *poLayer)
|
|
: m_poLayer(poLayer), m_poFeatureDefn(nullptr)
|
|
{
|
|
SetDescription(PythonPluginLayer::GetName());
|
|
const char *pszPtr = CPLSPrintf("%p", this);
|
|
PyObject *ptr = PyUnicode_FromString(pszPtr);
|
|
PyObject_SetAttrString(m_poLayer, "_gdal_pointer", ptr);
|
|
Py_DecRef(ptr);
|
|
PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", Py_None);
|
|
PyObject_SetAttrString(m_poLayer, "spatial_filter", Py_None);
|
|
PyObject_SetAttrString(m_poLayer, "attribute_filter", Py_None);
|
|
auto poFalse = PyBool_FromLong(false);
|
|
if (!PyObject_HasAttrString(m_poLayer, "iterator_honour_attribute_filter"))
|
|
{
|
|
PyObject_SetAttrString(m_poLayer, "iterator_honour_attribute_filter",
|
|
poFalse);
|
|
}
|
|
if (!PyObject_HasAttrString(m_poLayer, "iterator_honour_spatial_filter"))
|
|
{
|
|
PyObject_SetAttrString(m_poLayer, "iterator_honour_spatial_filter",
|
|
poFalse);
|
|
}
|
|
if (!PyObject_HasAttrString(m_poLayer,
|
|
"feature_count_honour_attribute_filter"))
|
|
{
|
|
PyObject_SetAttrString(
|
|
m_poLayer, "feature_count_honour_attribute_filter", poFalse);
|
|
}
|
|
if (!PyObject_HasAttrString(m_poLayer,
|
|
"feature_count_honour_spatial_filter"))
|
|
{
|
|
PyObject_SetAttrString(m_poLayer, "feature_count_honour_spatial_filter",
|
|
poFalse);
|
|
}
|
|
Py_DecRef(poFalse);
|
|
RefreshHonourFlags();
|
|
|
|
if (PyObject_HasAttrString(m_poLayer, "feature_by_id"))
|
|
{
|
|
m_pyFeatureByIdMethod =
|
|
PyObject_GetAttrString(m_poLayer, "feature_by_id");
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~PythonPluginLayer() */
|
|
/************************************************************************/
|
|
|
|
PythonPluginLayer::~PythonPluginLayer()
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
if (m_poFeatureDefn)
|
|
m_poFeatureDefn->Release();
|
|
Py_DecRef(m_pyFeatureByIdMethod);
|
|
Py_DecRef(m_poLayer);
|
|
Py_DecRef(m_pyIterator);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* RefreshHonourFlags() */
|
|
/************************************************************************/
|
|
|
|
void PythonPluginLayer::RefreshHonourFlags()
|
|
{
|
|
if (PyObject_HasAttrString(m_poLayer, "iterator_honour_attribute_filter"))
|
|
{
|
|
auto poObj = PyObject_GetAttrString(m_poLayer,
|
|
"iterator_honour_attribute_filter");
|
|
m_bIteratorHonourAttributeFilter = PyLong_AsLong(poObj) != 0;
|
|
Py_DecRef(poObj);
|
|
}
|
|
if (PyObject_HasAttrString(m_poLayer, "iterator_honour_spatial_filter"))
|
|
{
|
|
auto poObj =
|
|
PyObject_GetAttrString(m_poLayer, "iterator_honour_spatial_filter");
|
|
m_bIteratorHonourSpatialFilter = PyLong_AsLong(poObj) != 0;
|
|
Py_DecRef(poObj);
|
|
}
|
|
if (PyObject_HasAttrString(m_poLayer,
|
|
"feature_count_honour_attribute_filter"))
|
|
{
|
|
auto poObj = PyObject_GetAttrString(
|
|
m_poLayer, "feature_count_honour_attribute_filter");
|
|
m_bFeatureCountHonourAttributeFilter = PyLong_AsLong(poObj) != 0;
|
|
Py_DecRef(poObj);
|
|
}
|
|
if (PyObject_HasAttrString(m_poLayer,
|
|
"feature_count_honour_spatial_filter"))
|
|
{
|
|
auto poObj = PyObject_GetAttrString(
|
|
m_poLayer, "feature_count_honour_spatial_filter");
|
|
m_bFeatureCountHonourSpatialFilter = PyLong_AsLong(poObj) != 0;
|
|
Py_DecRef(poObj);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetAttributeFilter() */
|
|
/************************************************************************/
|
|
|
|
OGRErr PythonPluginLayer::SetAttributeFilter(const char *pszFilter)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
PyObject *str =
|
|
pszFilter ? PyUnicode_FromString(pszFilter) : IncRefAndReturn(Py_None);
|
|
PyObject_SetAttrString(m_poLayer, "attribute_filter", str);
|
|
Py_DecRef(str);
|
|
|
|
if (PyObject_HasAttrString(m_poLayer, "attribute_filter_changed"))
|
|
{
|
|
auto poObj =
|
|
PyObject_GetAttrString(m_poLayer, "attribute_filter_changed");
|
|
Py_DecRef(CallPython(poObj));
|
|
Py_DecRef(poObj);
|
|
}
|
|
|
|
return OGRLayer::SetAttributeFilter(pszFilter);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* StoreSpatialFilter() */
|
|
/************************************************************************/
|
|
|
|
void PythonPluginLayer::StoreSpatialFilter()
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
if (m_poFilterGeom && !m_poFilterGeom->IsEmpty())
|
|
{
|
|
PyObject *list = PyList_New(4);
|
|
PyList_SetItem(list, 0, PyFloat_FromDouble(m_sFilterEnvelope.MinX));
|
|
PyList_SetItem(list, 1, PyFloat_FromDouble(m_sFilterEnvelope.MinY));
|
|
PyList_SetItem(list, 2, PyFloat_FromDouble(m_sFilterEnvelope.MaxX));
|
|
PyList_SetItem(list, 3, PyFloat_FromDouble(m_sFilterEnvelope.MaxY));
|
|
PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", list);
|
|
Py_DecRef(list);
|
|
|
|
char *pszWKT = nullptr;
|
|
m_poFilterGeom->exportToWkt(&pszWKT);
|
|
PyObject *str = PyUnicode_FromString(pszWKT);
|
|
PyObject_SetAttrString(m_poLayer, "spatial_filter", str);
|
|
Py_DecRef(str);
|
|
CPLFree(pszWKT);
|
|
}
|
|
else
|
|
{
|
|
PyObject_SetAttrString(m_poLayer, "spatial_filter_extent", Py_None);
|
|
PyObject_SetAttrString(m_poLayer, "spatial_filter", Py_None);
|
|
}
|
|
|
|
if (PyObject_HasAttrString(m_poLayer, "spatial_filter_changed"))
|
|
{
|
|
auto poObj =
|
|
PyObject_GetAttrString(m_poLayer, "spatial_filter_changed");
|
|
Py_DecRef(CallPython(poObj));
|
|
Py_DecRef(poObj);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* SetSpatialFilter() */
|
|
/************************************************************************/
|
|
|
|
void PythonPluginLayer::SetSpatialFilter(OGRGeometry *poGeom)
|
|
{
|
|
OGRLayer::SetSpatialFilter(poGeom);
|
|
StoreSpatialFilter();
|
|
}
|
|
|
|
void PythonPluginLayer::SetSpatialFilter(int iGeomField, OGRGeometry *poGeom)
|
|
{
|
|
OGRLayer::SetSpatialFilter(iGeomField, poGeom);
|
|
StoreSpatialFilter();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetName() */
|
|
/************************************************************************/
|
|
|
|
const char *PythonPluginLayer::GetName()
|
|
{
|
|
if (m_osName.empty())
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
|
|
PyObject *poObj = PyObject_GetAttrString(m_poLayer, "name");
|
|
if (ErrOccurredEmitCPLError())
|
|
return m_osName;
|
|
if (PyCallable_Check(poObj))
|
|
{
|
|
m_osName = GetStringRes(m_poLayer, "name");
|
|
}
|
|
else
|
|
{
|
|
m_osName = GetString(poObj);
|
|
CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
|
|
}
|
|
Py_DecRef(poObj);
|
|
}
|
|
return m_osName;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TestCapability() */
|
|
/************************************************************************/
|
|
|
|
int PythonPluginLayer::TestCapability(const char *pszCap)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
if (PyObject_HasAttrString(m_poLayer, "test_capability"))
|
|
{
|
|
PyObject *poObj = PyObject_GetAttrString(m_poLayer, "test_capability");
|
|
if (ErrOccurredEmitCPLError())
|
|
return 0;
|
|
PyObject *pyArgs = PyTuple_New(1);
|
|
PyTuple_SetItem(pyArgs, 0, PyUnicode_FromString(pszCap));
|
|
PyObject *pRet = PyObject_Call(poObj, pyArgs, nullptr);
|
|
Py_DecRef(pyArgs);
|
|
Py_DecRef(poObj);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(pRet);
|
|
return 0;
|
|
}
|
|
int nRes = static_cast<int>(PyLong_AsLong(pRet));
|
|
Py_DecRef(pRet);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
return 0;
|
|
}
|
|
return nRes;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFIDColumn() */
|
|
/************************************************************************/
|
|
|
|
const char *PythonPluginLayer::GetFIDColumn()
|
|
{
|
|
if (!m_bHasFIDColumn)
|
|
{
|
|
m_bHasFIDColumn = true;
|
|
GIL_Holder oHolder(false);
|
|
PyObject *poObj = PyObject_GetAttrString(m_poLayer, "fid_name");
|
|
if (PyErr_Occurred())
|
|
{
|
|
PyErr_Clear();
|
|
}
|
|
else
|
|
{
|
|
if (PyCallable_Check(poObj))
|
|
{
|
|
m_osFIDColumn = GetStringRes(m_poLayer, "fid_name", true);
|
|
}
|
|
else
|
|
{
|
|
m_osFIDColumn = GetString(poObj);
|
|
CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
|
|
}
|
|
Py_DecRef(poObj);
|
|
}
|
|
}
|
|
return m_osFIDColumn;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* layer_featureCount() */
|
|
/************************************************************************/
|
|
|
|
static PyObject *layer_featureCount(PyObject * /*m*/, PyObject *args,
|
|
PyObject * /*kwargs*/)
|
|
{
|
|
PyObject *poPyLayer = nullptr;
|
|
int bForce = 0;
|
|
if (PyArg_ParseTuple(args, "O|i", &poPyLayer, &bForce))
|
|
{
|
|
PyObject *poPointer =
|
|
PyObject_GetAttrString(poPyLayer, "_gdal_pointer");
|
|
if (poPointer)
|
|
{
|
|
CPLString osPtr = GetString(poPointer);
|
|
Py_DecRef(poPointer);
|
|
void *pPtr = nullptr;
|
|
sscanf(osPtr, "%p", &pPtr);
|
|
PythonPluginLayer *poLayer = static_cast<PythonPluginLayer *>(pPtr);
|
|
return PyLong_FromLongLong(
|
|
poLayer->OGRLayer::GetFeatureCount(bForce));
|
|
}
|
|
}
|
|
Py_IncRef(Py_None);
|
|
return Py_None;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFeatureCount() */
|
|
/************************************************************************/
|
|
|
|
GIntBig PythonPluginLayer::GetFeatureCount(int bForce)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
|
|
if (PyObject_HasAttrString(m_poLayer, "feature_count") &&
|
|
(m_bFeatureCountHonourAttributeFilter || m_poAttrQuery == nullptr) &&
|
|
(m_bFeatureCountHonourSpatialFilter || m_poFilterGeom == nullptr))
|
|
{
|
|
auto poMethod = PyObject_GetAttrString(m_poLayer, "feature_count");
|
|
PyObject *poRet = CallPython(poMethod, bForce);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poRet);
|
|
return OGRLayer::GetFeatureCount(bForce);
|
|
}
|
|
|
|
GIntBig nRet = PyLong_AsLongLong(poRet);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poRet);
|
|
return OGRLayer::GetFeatureCount(bForce);
|
|
}
|
|
|
|
Py_DecRef(poRet);
|
|
return nRet;
|
|
}
|
|
return OGRLayer::GetFeatureCount(bForce);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetExtent() */
|
|
/************************************************************************/
|
|
|
|
OGRErr PythonPluginLayer::GetExtent(OGREnvelope *psExtent, int bForce)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
if (PyObject_HasAttrString(m_poLayer, "extent"))
|
|
{
|
|
PyObject *poMethod = PyObject_GetAttrString(m_poLayer, "extent");
|
|
if (poMethod != nullptr)
|
|
{
|
|
PyObject *poRet = CallPython(poMethod, bForce);
|
|
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poRet);
|
|
return OGRLayer::GetExtent(psExtent, bForce);
|
|
}
|
|
|
|
if (poRet == Py_None)
|
|
{
|
|
Py_DecRef(poRet);
|
|
return OGRERR_FAILURE;
|
|
}
|
|
|
|
if (PySequence_Size(poRet) == 4)
|
|
{
|
|
PyObject *poMinX = PySequence_GetItem(poRet, 0);
|
|
PyObject *poMinY = PySequence_GetItem(poRet, 1);
|
|
PyObject *poMaxX = PySequence_GetItem(poRet, 2);
|
|
PyObject *poMaxY = PySequence_GetItem(poRet, 3);
|
|
double dfMinX = PyFloat_AsDouble(poMinX);
|
|
double dfMinY = PyFloat_AsDouble(poMinY);
|
|
double dfMaxX = PyFloat_AsDouble(poMaxX);
|
|
double dfMaxY = PyFloat_AsDouble(poMaxY);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poRet);
|
|
return OGRLayer::GetExtent(psExtent, bForce);
|
|
}
|
|
Py_DecRef(poRet);
|
|
psExtent->MinX = dfMinX;
|
|
psExtent->MinY = dfMinY;
|
|
psExtent->MaxX = dfMaxX;
|
|
psExtent->MaxY = dfMaxY;
|
|
return OGRERR_NONE;
|
|
}
|
|
else
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined,
|
|
"List should have 4 values");
|
|
}
|
|
|
|
Py_DecRef(poRet);
|
|
}
|
|
}
|
|
return OGRLayer::GetExtent(psExtent, bForce);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* TranslateToOGRFeature() */
|
|
/************************************************************************/
|
|
|
|
OGRFeature *PythonPluginLayer::TranslateToOGRFeature(PyObject *poObj)
|
|
{
|
|
if (poObj == Py_None)
|
|
return nullptr;
|
|
|
|
OGRFeature *poFeature = new OGRFeature(GetLayerDefn());
|
|
|
|
PyObject *myBool = PyBool_FromLong(1);
|
|
PyObject *myBoolType = PyObject_Type(myBool);
|
|
PyObject *myInt = PyLong_FromLong(1);
|
|
PyObject *myIntType = PyObject_Type(myInt);
|
|
PyObject *myLong = PyLong_FromLongLong(1);
|
|
PyObject *myLongType = PyObject_Type(myLong);
|
|
PyObject *myFloat = PyFloat_FromDouble(1.0);
|
|
PyObject *myFloatType = PyObject_Type(myFloat);
|
|
PyObject *myStr = PyUnicode_FromString("");
|
|
PyObject *myStrType = PyObject_Type(myStr);
|
|
|
|
auto poFields = PyDict_GetItemString(poObj, "fields");
|
|
auto poGeometryFields = PyDict_GetItemString(poObj, "geometry_fields");
|
|
auto poId = PyDict_GetItemString(poObj, "id");
|
|
auto poStyleString = PyDict_GetItemString(poObj, "style");
|
|
PyErr_Clear();
|
|
|
|
if (poId && PyObject_IsInstance(poId, myLongType))
|
|
{
|
|
poFeature->SetFID(static_cast<GIntBig>(PyLong_AsLongLong(poId)));
|
|
}
|
|
else if (poId && PyObject_IsInstance(poId, myIntType))
|
|
{
|
|
poFeature->SetFID(static_cast<GIntBig>(PyLong_AsLong(poId)));
|
|
}
|
|
|
|
if (poStyleString && poStyleString != Py_None)
|
|
{
|
|
CPLString osValue = GetString(poStyleString);
|
|
if (!ErrOccurredEmitCPLError())
|
|
{
|
|
poFeature->SetStyleString(osValue);
|
|
}
|
|
}
|
|
|
|
if (poGeometryFields && poGeometryFields != Py_None)
|
|
{
|
|
PyObject *key = nullptr;
|
|
PyObject *value = nullptr;
|
|
size_t pos = 0;
|
|
while (PyDict_Next(poGeometryFields, &pos, &key, &value))
|
|
{
|
|
CPLString osKey = GetString(key);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
if (value != Py_None)
|
|
{
|
|
const int idx = m_poFeatureDefn->GetGeomFieldIndex(osKey);
|
|
if (idx >= 0)
|
|
{
|
|
OGRGeometry *poGeom = nullptr;
|
|
if (PyObject_IsInstance(value, myStrType))
|
|
{
|
|
// WKT
|
|
CPLString osValue = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
OGRGeometryFactory::createFromWkt(osValue.c_str(),
|
|
nullptr, &poGeom);
|
|
}
|
|
else
|
|
{
|
|
// WKB (from bytes, bytearray, memoryview)
|
|
PyObject *poBytes = PyBytes_FromObject(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
char *buffer = nullptr;
|
|
size_t length = 0;
|
|
PyBytes_AsStringAndSize(poBytes, &buffer, &length);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
|
|
OGRGeometryFactory::createFromWkb(
|
|
buffer, nullptr, &poGeom, length, wkbVariantIso);
|
|
}
|
|
|
|
if (poGeom)
|
|
{
|
|
const auto poGeomFieldDefn =
|
|
m_poFeatureDefn->GetGeomFieldDefn(idx);
|
|
if (poGeomFieldDefn)
|
|
poGeom->assignSpatialReference(
|
|
poGeomFieldDefn->GetSpatialRef());
|
|
}
|
|
poFeature->SetGeomFieldDirectly(idx, poGeom);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
PyObject *key = nullptr;
|
|
PyObject *value = nullptr;
|
|
size_t pos = 0;
|
|
while (poFields && poFields != Py_None &&
|
|
PyDict_Next(poFields, &pos, &key, &value))
|
|
{
|
|
CPLString osKey = GetString(key);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (value == Py_None)
|
|
{
|
|
int idx = m_poFeatureDefn->GetFieldIndex(osKey);
|
|
if (idx >= 0)
|
|
{
|
|
poFeature->SetFieldNull(idx);
|
|
}
|
|
}
|
|
else if (PyObject_IsInstance(value, myLongType))
|
|
{
|
|
int idx = m_poFeatureDefn->GetFieldIndex(osKey);
|
|
if (idx >= 0)
|
|
{
|
|
poFeature->SetField(
|
|
idx, static_cast<GIntBig>(PyLong_AsLongLong(value)));
|
|
}
|
|
}
|
|
else if (PyObject_IsInstance(value, myBoolType) ||
|
|
PyObject_IsInstance(value, myIntType))
|
|
{
|
|
int idx = m_poFeatureDefn->GetFieldIndex(osKey);
|
|
if (idx >= 0)
|
|
{
|
|
poFeature->SetField(idx,
|
|
static_cast<GIntBig>(PyLong_AsLong(value)));
|
|
}
|
|
}
|
|
else if (PyObject_IsInstance(value, myFloatType))
|
|
{
|
|
int idx = m_poFeatureDefn->GetFieldIndex(osKey);
|
|
if (idx >= 0)
|
|
{
|
|
poFeature->SetField(idx, PyFloat_AsDouble(value));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int idx = m_poFeatureDefn->GetFieldIndex(osKey);
|
|
if (idx >= 0 &&
|
|
m_poFeatureDefn->GetFieldDefn(idx)->GetType() == OFTBinary)
|
|
{
|
|
Py_ssize_t nSize = PyBytes_Size(value);
|
|
const char *pszBytes = PyBytes_AsString(value);
|
|
poFeature->SetField(
|
|
idx, static_cast<int>(nSize),
|
|
const_cast<GByte *>(
|
|
reinterpret_cast<const GByte *>(pszBytes)));
|
|
continue;
|
|
}
|
|
|
|
CPLString osValue = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
break;
|
|
}
|
|
if (idx >= 0)
|
|
{
|
|
poFeature->SetField(idx, osValue);
|
|
}
|
|
}
|
|
}
|
|
|
|
Py_DecRef(myBoolType);
|
|
Py_DecRef(myBool);
|
|
Py_DecRef(myIntType);
|
|
Py_DecRef(myInt);
|
|
Py_DecRef(myLongType);
|
|
Py_DecRef(myLong);
|
|
Py_DecRef(myFloatType);
|
|
Py_DecRef(myFloat);
|
|
Py_DecRef(myStr);
|
|
Py_DecRef(myStrType);
|
|
|
|
return poFeature;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFeature() */
|
|
/************************************************************************/
|
|
|
|
OGRFeature *PythonPluginLayer::GetFeature(GIntBig nFID)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
|
|
if (m_pyFeatureByIdMethod)
|
|
{
|
|
PyObject *pyArgs = PyTuple_New(1);
|
|
PyTuple_SetItem(pyArgs, 0, PyLong_FromLongLong(nFID));
|
|
PyObject *pRet = PyObject_Call(m_pyFeatureByIdMethod, pyArgs, nullptr);
|
|
Py_DecRef(pyArgs);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(pRet);
|
|
return nullptr;
|
|
}
|
|
auto poFeature = TranslateToOGRFeature(pRet);
|
|
Py_DecRef(pRet);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
return nullptr;
|
|
}
|
|
return poFeature;
|
|
}
|
|
return OGRLayer::GetFeature(nFID);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ResetReading() */
|
|
/************************************************************************/
|
|
|
|
void PythonPluginLayer::ResetReading()
|
|
{
|
|
m_bStopIteration = false;
|
|
|
|
GIL_Holder oHolder(false);
|
|
|
|
Py_DecRef(m_pyIterator);
|
|
m_pyIterator = PyObject_GetIter(m_poLayer);
|
|
CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetNextFeature() */
|
|
/************************************************************************/
|
|
|
|
OGRFeature *PythonPluginLayer::GetNextFeature()
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
|
|
if (m_bStopIteration)
|
|
return nullptr;
|
|
|
|
if (m_pyIterator == nullptr)
|
|
{
|
|
ResetReading();
|
|
if (m_pyIterator == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
while (true)
|
|
{
|
|
PyObject *poRet = PyIter_Next(m_pyIterator);
|
|
if (poRet == nullptr)
|
|
{
|
|
m_bStopIteration = true;
|
|
CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
|
|
return nullptr;
|
|
}
|
|
|
|
auto poFeature = TranslateToOGRFeature(poRet);
|
|
Py_DecRef(poRet);
|
|
if (poFeature == nullptr)
|
|
{
|
|
return nullptr;
|
|
}
|
|
|
|
if ((m_bIteratorHonourSpatialFilter || m_poFilterGeom == nullptr ||
|
|
FilterGeometry(poFeature->GetGeomFieldRef(m_iGeomFieldFilter))) &&
|
|
(m_bIteratorHonourAttributeFilter || m_poAttrQuery == nullptr ||
|
|
m_poAttrQuery->Evaluate(poFeature)))
|
|
{
|
|
return poFeature;
|
|
}
|
|
|
|
delete poFeature;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetLayerDefn() */
|
|
/************************************************************************/
|
|
|
|
OGRFeatureDefn *PythonPluginLayer::GetLayerDefn()
|
|
{
|
|
if (m_poFeatureDefn)
|
|
return m_poFeatureDefn;
|
|
|
|
GIL_Holder oHolder(false);
|
|
m_poFeatureDefn = new OGRFeatureDefn(GetName());
|
|
m_poFeatureDefn->Reference();
|
|
m_poFeatureDefn->SetGeomType(wkbNone);
|
|
|
|
GetFields();
|
|
GetGeomFields();
|
|
return m_poFeatureDefn;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetFields() */
|
|
/************************************************************************/
|
|
|
|
void PythonPluginLayer::GetFields()
|
|
{
|
|
PyObject *poFields = PyObject_GetAttrString(m_poLayer, "fields");
|
|
if (ErrOccurredEmitCPLError())
|
|
return;
|
|
if (PyCallable_Check(poFields))
|
|
{
|
|
PyObject *poFieldsRes = CallPython(poFields);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
Py_DecRef(poFields);
|
|
poFields = poFieldsRes;
|
|
}
|
|
|
|
size_t nSize = PySequence_Size(poFields);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
for (size_t i = 0; i < nSize; i++)
|
|
{
|
|
PyObject *poItem = PySequence_GetItem(poFields, i);
|
|
if (poItem == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
|
|
PyObject *key, *value;
|
|
size_t pos = 0;
|
|
CPLString osFieldName;
|
|
OGRFieldType eType = OFTString;
|
|
OGRFieldSubType eSubType = OFSTNone;
|
|
while (PyDict_Next(poItem, &pos, &key, &value))
|
|
{
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
CPLString osKey = GetString(key);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
if (strcmp(osKey, "name") == 0)
|
|
{
|
|
osFieldName = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else if (strcmp(osKey, "type") == 0)
|
|
{
|
|
PyObject *myInt = PyLong_FromLong(1);
|
|
PyObject *myIntType = PyObject_Type(myInt);
|
|
if (PyObject_IsInstance(value, myIntType))
|
|
{
|
|
int nType = static_cast<int>(PyLong_AsLong(value));
|
|
if (nType < 0 || nType > OFTMaxType)
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %d",
|
|
nType);
|
|
}
|
|
else
|
|
{
|
|
eType = static_cast<OGRFieldType>(nType);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CPLString osValue = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
if (EQUAL(osValue, "String"))
|
|
eType = OFTString;
|
|
else if (EQUAL(osValue, "Integer") ||
|
|
EQUAL(osValue, "Integer32") ||
|
|
EQUAL(osValue, "Int32"))
|
|
eType = OFTInteger;
|
|
else if (EQUAL(osValue, "Boolean"))
|
|
{
|
|
eType = OFTInteger;
|
|
eSubType = OFSTBoolean;
|
|
}
|
|
else if (EQUAL(osValue, "Integer16") ||
|
|
EQUAL(osValue, "Int16"))
|
|
{
|
|
eType = OFTInteger;
|
|
eSubType = OFSTInt16;
|
|
}
|
|
else if (EQUAL(osValue, "Integer64") ||
|
|
EQUAL(osValue, "Int64"))
|
|
eType = OFTInteger64;
|
|
else if (EQUAL(osValue, "Real"))
|
|
eType = OFTReal;
|
|
else if (EQUAL(osValue, "Float") ||
|
|
EQUAL(osValue, "Float32"))
|
|
{
|
|
eType = OFTReal;
|
|
eSubType = OFSTFloat32;
|
|
}
|
|
else if (EQUAL(osValue, "Binary"))
|
|
eType = OFTBinary;
|
|
else if (EQUAL(osValue, "DateTime"))
|
|
eType = OFTDateTime;
|
|
else if (EQUAL(osValue, "Date"))
|
|
eType = OFTDate;
|
|
else if (EQUAL(osValue, "Time"))
|
|
eType = OFTTime;
|
|
else
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %s",
|
|
osValue.c_str());
|
|
}
|
|
}
|
|
Py_DecRef(myInt);
|
|
Py_DecRef(myIntType);
|
|
}
|
|
else
|
|
{
|
|
CPLDebug("GDAL", "Unknown field property: %s", osKey.c_str());
|
|
}
|
|
}
|
|
|
|
if (!osFieldName.empty())
|
|
{
|
|
OGRFieldDefn oFieldDefn(osFieldName, eType);
|
|
oFieldDefn.SetSubType(eSubType);
|
|
m_poFeatureDefn->AddFieldDefn(&oFieldDefn);
|
|
}
|
|
}
|
|
|
|
Py_DecRef(poFields);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetGeomFields() */
|
|
/************************************************************************/
|
|
|
|
void PythonPluginLayer::GetGeomFields()
|
|
{
|
|
PyObject *poFields = PyObject_GetAttrString(m_poLayer, "geometry_fields");
|
|
if (ErrOccurredEmitCPLError())
|
|
return;
|
|
if (PyCallable_Check(poFields))
|
|
{
|
|
PyObject *poFieldsRes = CallPython(poFields);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
Py_DecRef(poFields);
|
|
poFields = poFieldsRes;
|
|
}
|
|
|
|
size_t nSize = PySequence_Size(poFields);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
for (size_t i = 0; i < nSize; i++)
|
|
{
|
|
PyObject *poItem = PySequence_GetItem(poFields, i);
|
|
if (poItem == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
|
|
PyObject *key, *value;
|
|
size_t pos = 0;
|
|
CPLString osFieldName, osSRS;
|
|
OGRwkbGeometryType eType = wkbUnknown;
|
|
while (PyDict_Next(poItem, &pos, &key, &value))
|
|
{
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
CPLString osKey = GetString(key);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
if (strcmp(osKey, "name") == 0)
|
|
{
|
|
osFieldName = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else if (strcmp(osKey, "type") == 0)
|
|
{
|
|
PyObject *myInt = PyLong_FromLong(1);
|
|
PyObject *myIntType = PyObject_Type(myInt);
|
|
if (PyObject_IsInstance(value, myIntType))
|
|
{
|
|
eType =
|
|
static_cast<OGRwkbGeometryType>(PyLong_AsLong(value));
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CPLString osValue = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
eType = OGRFromOGCGeomType(osValue);
|
|
if (eType == wkbUnknown && !EQUAL(osValue, "Geometry"))
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Wrong type: %s",
|
|
osValue.c_str());
|
|
}
|
|
}
|
|
Py_DecRef(myInt);
|
|
Py_DecRef(myIntType);
|
|
}
|
|
else if (strcmp(osKey, "srs") == 0)
|
|
{
|
|
if (value != Py_None)
|
|
{
|
|
osSRS = GetString(value);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poFields);
|
|
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CPLDebug("GDAL", "Unknown geometry field property: %s",
|
|
osKey.c_str());
|
|
}
|
|
}
|
|
|
|
OGRGeomFieldDefn oFieldDefn(osFieldName, eType);
|
|
if (!osSRS.empty())
|
|
{
|
|
OGRSpatialReference *poSRS = new OGRSpatialReference();
|
|
poSRS->SetAxisMappingStrategy(OAMS_TRADITIONAL_GIS_ORDER);
|
|
poSRS->SetFromUserInput(
|
|
osSRS, OGRSpatialReference::SET_FROM_USER_INPUT_LIMITATIONS);
|
|
oFieldDefn.SetSpatialRef(poSRS);
|
|
poSRS->Release();
|
|
}
|
|
m_poFeatureDefn->AddGeomFieldDefn(&oFieldDefn);
|
|
}
|
|
|
|
Py_DecRef(poFields);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadata() */
|
|
/************************************************************************/
|
|
|
|
static char **GetMetadata(PyObject *obj, const char *pszDomain)
|
|
{
|
|
if (!PyObject_HasAttrString(obj, "metadata"))
|
|
return nullptr;
|
|
PyObject *poMetadata = PyObject_GetAttrString(obj, "metadata");
|
|
CPLAssert(poMetadata);
|
|
PyObject *poMethodRes;
|
|
if (PyCallable_Check(poMetadata))
|
|
{
|
|
PyObject *pyArgs = PyTuple_New(1);
|
|
PyTuple_SetItem(pyArgs, 0,
|
|
pszDomain && pszDomain[0]
|
|
? PyUnicode_FromString(pszDomain)
|
|
: IncRefAndReturn(Py_None));
|
|
poMethodRes = PyObject_Call(poMetadata, pyArgs, nullptr);
|
|
Py_DecRef(pyArgs);
|
|
Py_DecRef(poMetadata);
|
|
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
return nullptr;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
poMethodRes = poMetadata;
|
|
}
|
|
|
|
if (poMethodRes == Py_None)
|
|
{
|
|
Py_DecRef(poMethodRes);
|
|
return nullptr;
|
|
}
|
|
char **papszMD = GetDict(poMethodRes);
|
|
Py_DecRef(poMethodRes);
|
|
return papszMD;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadata() */
|
|
/************************************************************************/
|
|
|
|
char **PythonPluginLayer::GetMetadata(const char *pszDomain)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
if (pszDomain == nullptr)
|
|
pszDomain = "";
|
|
m_oMapMD[pszDomain] = CPLStringList(::GetMetadata(m_poLayer, pszDomain));
|
|
return m_oMapMD[pszDomain].List();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* PythonPluginDataset */
|
|
/************************************************************************/
|
|
|
|
class PythonPluginDataset final : public GDALDataset
|
|
{
|
|
PyObject *m_poDataset = nullptr;
|
|
std::map<int, std::unique_ptr<OGRLayer>> m_oMapLayer{};
|
|
std::map<CPLString, CPLStringList> m_oMapMD{};
|
|
bool m_bHasLayersMember = false;
|
|
|
|
PythonPluginDataset(const PythonPluginDataset &) = delete;
|
|
PythonPluginDataset &operator=(const PythonPluginDataset &) = delete;
|
|
|
|
public:
|
|
PythonPluginDataset(GDALOpenInfo *poOpenInfo, PyObject *poDataset);
|
|
~PythonPluginDataset();
|
|
|
|
int GetLayerCount() override;
|
|
OGRLayer *GetLayer(int) override;
|
|
char **GetMetadata(const char *pszDomain = "") override;
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* PythonPluginDataset() */
|
|
/************************************************************************/
|
|
|
|
PythonPluginDataset::PythonPluginDataset(GDALOpenInfo *poOpenInfo,
|
|
PyObject *poDataset)
|
|
: m_poDataset(poDataset)
|
|
{
|
|
SetDescription(poOpenInfo->pszFilename);
|
|
|
|
GIL_Holder oHolder(false);
|
|
|
|
const auto poLayers = PyObject_GetAttrString(m_poDataset, "layers");
|
|
PyErr_Clear();
|
|
if (poLayers)
|
|
{
|
|
if (PySequence_Check(poLayers))
|
|
{
|
|
m_bHasLayersMember = true;
|
|
const int nSize = static_cast<int>(PySequence_Size(poLayers));
|
|
for (int i = 0; i < nSize; i++)
|
|
{
|
|
const auto poLayer = PySequence_GetItem(poLayers, i);
|
|
Py_IncRef(poLayer);
|
|
m_oMapLayer[i] = std::unique_ptr<PythonPluginLayer>(
|
|
new PythonPluginLayer(poLayer));
|
|
}
|
|
}
|
|
Py_DecRef(poLayers);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~PythonPluginDataset() */
|
|
/************************************************************************/
|
|
|
|
PythonPluginDataset::~PythonPluginDataset()
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
|
|
if (m_poDataset && PyObject_HasAttrString(m_poDataset, "close"))
|
|
{
|
|
PyObject *poClose = PyObject_GetAttrString(m_poDataset, "close");
|
|
PyObject *pyArgs = PyTuple_New(0);
|
|
Py_DecRef(PyObject_Call(poClose, pyArgs, nullptr));
|
|
Py_DecRef(pyArgs);
|
|
Py_DecRef(poClose);
|
|
|
|
CPL_IGNORE_RET_VAL(ErrOccurredEmitCPLError());
|
|
}
|
|
Py_DecRef(m_poDataset);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetLayerCount() */
|
|
/************************************************************************/
|
|
|
|
int PythonPluginDataset::GetLayerCount()
|
|
{
|
|
if (m_bHasLayersMember)
|
|
return static_cast<int>(m_oMapLayer.size());
|
|
|
|
GIL_Holder oHolder(false);
|
|
return GetIntRes(m_poDataset, "layer_count");
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetLayer() */
|
|
/************************************************************************/
|
|
|
|
OGRLayer *PythonPluginDataset::GetLayer(int idx)
|
|
{
|
|
if (idx < 0)
|
|
return nullptr;
|
|
|
|
auto oIter = m_oMapLayer.find(idx);
|
|
if (oIter != m_oMapLayer.end())
|
|
return m_oMapLayer[idx].get();
|
|
|
|
if (m_bHasLayersMember)
|
|
return nullptr;
|
|
|
|
GIL_Holder oHolder(false);
|
|
|
|
PyObject *poMethod = PyObject_GetAttrString(m_poDataset, "layer");
|
|
if (poMethod == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject *poMethodRes = CallPython(poMethod, idx);
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethod);
|
|
return nullptr;
|
|
}
|
|
Py_DecRef(poMethod);
|
|
|
|
if (poMethodRes == Py_None)
|
|
{
|
|
m_oMapLayer[idx] = nullptr;
|
|
Py_DecRef(poMethodRes);
|
|
return nullptr;
|
|
}
|
|
m_oMapLayer[idx] =
|
|
std::unique_ptr<PythonPluginLayer>(new PythonPluginLayer(poMethodRes));
|
|
return m_oMapLayer[idx].get();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* GetMetadata() */
|
|
/************************************************************************/
|
|
|
|
char **PythonPluginDataset::GetMetadata(const char *pszDomain)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
if (pszDomain == nullptr)
|
|
pszDomain = "";
|
|
m_oMapMD[pszDomain] = CPLStringList(::GetMetadata(m_poDataset, pszDomain));
|
|
return m_oMapMD[pszDomain].List();
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* PythonPluginDriver */
|
|
/************************************************************************/
|
|
|
|
class PythonPluginDriver : public GDALDriver
|
|
{
|
|
CPLMutex *m_hMutex = nullptr;
|
|
CPLString m_osFilename;
|
|
PyObject *m_poPlugin = nullptr;
|
|
|
|
PythonPluginDriver(const PythonPluginDriver &) = delete;
|
|
PythonPluginDriver &operator=(const PythonPluginDriver &) = delete;
|
|
|
|
bool LoadPlugin();
|
|
|
|
int Identify(GDALOpenInfo *);
|
|
static int IdentifyEx(GDALDriver *, GDALOpenInfo *);
|
|
|
|
GDALDataset *Open(GDALOpenInfo *);
|
|
static GDALDataset *OpenEx(GDALDriver *, GDALOpenInfo *);
|
|
|
|
public:
|
|
PythonPluginDriver(const char *pszFilename, const char *pszPluginName,
|
|
char **papszMD);
|
|
~PythonPluginDriver();
|
|
};
|
|
|
|
/************************************************************************/
|
|
/* LoadPlugin() */
|
|
/************************************************************************/
|
|
|
|
bool PythonPluginDriver::LoadPlugin()
|
|
{
|
|
CPLMutexHolder oMutexHolder(&m_hMutex);
|
|
if (m_poPlugin)
|
|
return true;
|
|
if (!InitializePythonAndLoadGDALPythonDriverModule())
|
|
return false;
|
|
GIL_Holder oHolder(false);
|
|
|
|
CPLString osStr;
|
|
VSILFILE *fp = VSIFOpenL(m_osFilename, "rb");
|
|
VSIFSeekL(fp, 0, SEEK_END);
|
|
auto nSize = VSIFTellL(fp);
|
|
if (nSize > 10 * 1024 * 1024)
|
|
{
|
|
VSIFCloseL(fp);
|
|
return false;
|
|
}
|
|
VSIFSeekL(fp, 0, SEEK_SET);
|
|
osStr.resize(static_cast<size_t>(nSize));
|
|
VSIFReadL(&osStr[0], 1, static_cast<size_t>(nSize), fp);
|
|
VSIFCloseL(fp);
|
|
PyObject *poCompiledString =
|
|
Py_CompileString(osStr, m_osFilename, Py_file_input);
|
|
if (poCompiledString == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "Couldn't compile code:\n%s",
|
|
GetPyExceptionString().c_str());
|
|
return false;
|
|
}
|
|
const CPLString osPluginModuleName(CPLGetBasename(m_osFilename));
|
|
PyObject *poModule =
|
|
PyImport_ExecCodeModule(osPluginModuleName, poCompiledString);
|
|
Py_DecRef(poCompiledString);
|
|
|
|
if (poModule == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
return false;
|
|
}
|
|
|
|
PyObject *poInstantiate = PyObject_GetAttrString(gpoGDALPythonDriverModule,
|
|
"_instantiate_plugin");
|
|
CPLAssert(poInstantiate);
|
|
|
|
PyObject *pyArgs = PyTuple_New(1);
|
|
PyTuple_SetItem(pyArgs, 0, poModule);
|
|
PyObject *poPlugin = PyObject_Call(poInstantiate, pyArgs, nullptr);
|
|
Py_DecRef(pyArgs);
|
|
Py_DecRef(poInstantiate);
|
|
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
m_poPlugin = poPlugin;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* BuildIdentifyOpenArgs() */
|
|
/************************************************************************/
|
|
|
|
static void BuildIdentifyOpenArgs(GDALOpenInfo *poOpenInfo, PyObject *&pyArgs,
|
|
PyObject *&pyKwargs)
|
|
{
|
|
pyArgs = PyTuple_New(3);
|
|
PyTuple_SetItem(pyArgs, 0, PyUnicode_FromString(poOpenInfo->pszFilename));
|
|
PyTuple_SetItem(pyArgs, 1,
|
|
PyBytes_FromStringAndSize(poOpenInfo->pabyHeader,
|
|
poOpenInfo->nHeaderBytes));
|
|
PyTuple_SetItem(pyArgs, 2, PyLong_FromLong(poOpenInfo->nOpenFlags));
|
|
pyKwargs = PyDict_New();
|
|
PyObject *pyOpenOptions = PyDict_New();
|
|
PyDict_SetItemString(pyKwargs, "open_options", pyOpenOptions);
|
|
if (poOpenInfo->papszOpenOptions)
|
|
{
|
|
for (char **papszIter = poOpenInfo->papszOpenOptions; *papszIter;
|
|
++papszIter)
|
|
{
|
|
char *pszKey = nullptr;
|
|
const char *pszValue = CPLParseNameValue(*papszIter, &pszKey);
|
|
if (pszKey && pszValue)
|
|
{
|
|
auto pyValue = PyUnicode_FromString(pszValue);
|
|
PyDict_SetItemString(pyOpenOptions, pszKey, pyValue);
|
|
Py_DecRef(pyValue);
|
|
}
|
|
CPLFree(pszKey);
|
|
}
|
|
}
|
|
Py_DecRef(pyOpenOptions);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Identify() */
|
|
/************************************************************************/
|
|
|
|
int PythonPluginDriver::Identify(GDALOpenInfo *poOpenInfo)
|
|
{
|
|
if (m_poPlugin == nullptr)
|
|
{
|
|
if (!LoadPlugin())
|
|
return FALSE;
|
|
}
|
|
|
|
GIL_Holder oHolder(false);
|
|
|
|
PyObject *poMethod = PyObject_GetAttrString(m_poPlugin, "identify");
|
|
if (poMethod == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
return 0;
|
|
}
|
|
|
|
PyObject *pyArgs = nullptr;
|
|
PyObject *pyKwargs = nullptr;
|
|
BuildIdentifyOpenArgs(poOpenInfo, pyArgs, pyKwargs);
|
|
PyObject *poMethodRes = PyObject_Call(poMethod, pyArgs, pyKwargs);
|
|
Py_DecRef(pyArgs);
|
|
Py_DecRef(pyKwargs);
|
|
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethod);
|
|
return 0;
|
|
}
|
|
Py_DecRef(poMethod);
|
|
|
|
int nRes = static_cast<int>(PyLong_AsLong(poMethodRes));
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethodRes);
|
|
return 0;
|
|
}
|
|
|
|
Py_DecRef(poMethodRes);
|
|
return nRes;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* IdentifyEx() */
|
|
/************************************************************************/
|
|
|
|
int PythonPluginDriver::IdentifyEx(GDALDriver *poDrv, GDALOpenInfo *poOpenInfo)
|
|
{
|
|
return reinterpret_cast<PythonPluginDriver *>(poDrv)->Identify(poOpenInfo);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* Open() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *PythonPluginDriver::Open(GDALOpenInfo *poOpenInfo)
|
|
{
|
|
if (m_poPlugin == nullptr)
|
|
{
|
|
if (!LoadPlugin())
|
|
return nullptr;
|
|
}
|
|
|
|
GIL_Holder oHolder(false);
|
|
|
|
PyObject *poMethod = PyObject_GetAttrString(m_poPlugin, "open");
|
|
if (poMethod == nullptr || PyErr_Occurred())
|
|
{
|
|
CPLError(CE_Failure, CPLE_AppDefined, "%s",
|
|
GetPyExceptionString().c_str());
|
|
return nullptr;
|
|
}
|
|
|
|
PyObject *pyArgs = nullptr;
|
|
PyObject *pyKwargs = nullptr;
|
|
BuildIdentifyOpenArgs(poOpenInfo, pyArgs, pyKwargs);
|
|
PyObject *poMethodRes = PyObject_Call(poMethod, pyArgs, pyKwargs);
|
|
Py_DecRef(pyArgs);
|
|
Py_DecRef(pyKwargs);
|
|
|
|
if (ErrOccurredEmitCPLError())
|
|
{
|
|
Py_DecRef(poMethod);
|
|
return nullptr;
|
|
}
|
|
Py_DecRef(poMethod);
|
|
|
|
if (poMethodRes == Py_None)
|
|
{
|
|
Py_DecRef(poMethodRes);
|
|
return nullptr;
|
|
}
|
|
return new PythonPluginDataset(poOpenInfo, poMethodRes);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* OpenEx() */
|
|
/************************************************************************/
|
|
|
|
GDALDataset *PythonPluginDriver::OpenEx(GDALDriver *poDrv,
|
|
GDALOpenInfo *poOpenInfo)
|
|
{
|
|
return reinterpret_cast<PythonPluginDriver *>(poDrv)->Open(poOpenInfo);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* PythonPluginDriver() */
|
|
/************************************************************************/
|
|
|
|
PythonPluginDriver::PythonPluginDriver(const char *pszFilename,
|
|
const char *pszPluginName,
|
|
char **papszMD)
|
|
: m_hMutex(nullptr), m_osFilename(pszFilename), m_poPlugin(nullptr)
|
|
{
|
|
SetDescription(pszPluginName);
|
|
SetMetadata(papszMD);
|
|
pfnIdentifyEx = IdentifyEx;
|
|
pfnOpenWithDriverArg = OpenEx;
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* ~PythonPluginDriver() */
|
|
/************************************************************************/
|
|
|
|
PythonPluginDriver::~PythonPluginDriver()
|
|
{
|
|
if (m_hMutex)
|
|
CPLDestroyMutex(m_hMutex);
|
|
|
|
if (m_poPlugin)
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
Py_DecRef(m_poPlugin);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* LoadPythonDriver() */
|
|
/************************************************************************/
|
|
|
|
static void LoadPythonDriver(const char *pszFilename)
|
|
{
|
|
char **papszLines = CSLLoad2(pszFilename, 1000, 1000, nullptr);
|
|
if (papszLines == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
CPLString osPluginName;
|
|
char **papszMD = nullptr;
|
|
bool bAPIOK = false;
|
|
constexpr int CURRENT_API_VERSION = 1;
|
|
for (int i = 0; papszLines[i] != nullptr; i++)
|
|
{
|
|
const char *pszLine = papszLines[i];
|
|
if (!STARTS_WITH_CI(pszLine, "# gdal: DRIVER_"))
|
|
continue;
|
|
pszLine += strlen("# gdal: DRIVER_");
|
|
|
|
const char *pszEqual = strchr(pszLine, '=');
|
|
if (pszEqual == nullptr)
|
|
continue;
|
|
|
|
CPLString osKey(pszLine);
|
|
osKey.resize(pszEqual - pszLine);
|
|
osKey.Trim();
|
|
|
|
CPLString osValue(pszEqual + 1);
|
|
osValue.Trim();
|
|
|
|
char chQuote = 0;
|
|
if (!osValue.empty() && (osValue[0] == '"' || osValue[0] == '\''))
|
|
{
|
|
chQuote = osValue[0];
|
|
osValue = osValue.substr(1);
|
|
}
|
|
if (!osValue.empty() && osValue[osValue.size() - 1] == chQuote)
|
|
osValue.resize(osValue.size() - 1);
|
|
if (EQUAL(osKey, "NAME"))
|
|
{
|
|
osPluginName = std::move(osValue);
|
|
}
|
|
else if (EQUAL(osKey, "SUPPORTED_API_VERSION"))
|
|
{
|
|
const CPLStringList aosTokens(
|
|
CSLTokenizeString2(osValue, "[, ]", 0));
|
|
for (int j = 0; j < aosTokens.size(); ++j)
|
|
{
|
|
if (atoi(aosTokens[j]) == CURRENT_API_VERSION)
|
|
{
|
|
bAPIOK = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
papszMD = CSLSetNameValue(papszMD, osKey.c_str(), osValue);
|
|
}
|
|
}
|
|
papszMD = CSLSetNameValue(papszMD, "DRIVER_LANGUAGE", "PYTHON");
|
|
CSLDestroy(papszLines);
|
|
|
|
if (osPluginName.empty())
|
|
{
|
|
CPLError(CE_Warning, CPLE_AppDefined,
|
|
"Missing global # gdal: DRIVER_NAME declaration in %s",
|
|
pszFilename);
|
|
}
|
|
else if (!bAPIOK)
|
|
{
|
|
CPLDebug(
|
|
"GDAL",
|
|
"Plugin %s does not declare # gdal: DRIVER_SUPPORTED_API_VERSION "
|
|
"or not at version %d",
|
|
osPluginName.c_str(), CURRENT_API_VERSION);
|
|
}
|
|
else if (GDALGetDriverByName(osPluginName) == nullptr)
|
|
{
|
|
GDALDriver *poDriver =
|
|
new PythonPluginDriver(pszFilename, osPluginName, papszMD);
|
|
GetGDALDriverManager()->RegisterDriver(poDriver);
|
|
}
|
|
CSLDestroy(papszMD);
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* AutoLoadPythonDrivers() */
|
|
/************************************************************************/
|
|
|
|
/**
|
|
* \brief Auto-load GDAL drivers from Python scripts.
|
|
*
|
|
* This function will automatically load drivers from Python scripts.
|
|
* It searches them first from the directory pointed by the
|
|
* GDAL_PYTHON_DRIVER_PATH configuration option. If not defined, it will
|
|
* use GDAL_DRIVER_PATH. If not defined, it will use the path for
|
|
* drivers hardcoded at build time.
|
|
* Scripts must begin with gdal_ or ogr_ and end up with .py
|
|
*
|
|
* @since GDAL 3.1
|
|
*/
|
|
|
|
void GDALDriverManager::AutoLoadPythonDrivers()
|
|
{
|
|
const char *pszPythonDriverPath =
|
|
CPLGetConfigOption("GDAL_PYTHON_DRIVER_PATH", nullptr);
|
|
if (pszPythonDriverPath == nullptr)
|
|
{
|
|
pszPythonDriverPath = CPLGetConfigOption("GDAL_DRIVER_PATH", nullptr);
|
|
}
|
|
char **papszSearchPaths = GetSearchPaths(pszPythonDriverPath);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Format the ABI version specific subdirectory to look in. */
|
|
/* -------------------------------------------------------------------- */
|
|
CPLString osABIVersion;
|
|
|
|
osABIVersion.Printf("%d.%d", GDAL_VERSION_MAJOR, GDAL_VERSION_MINOR);
|
|
|
|
/* -------------------------------------------------------------------- */
|
|
/* Scan each directory */
|
|
/* -------------------------------------------------------------------- */
|
|
std::vector<CPLString> aosPythonFiles;
|
|
const int nSearchPaths = CSLCount(papszSearchPaths);
|
|
for (int iDir = 0; iDir < nSearchPaths; ++iDir)
|
|
{
|
|
CPLString osABISpecificDir =
|
|
CPLFormFilename(papszSearchPaths[iDir], osABIVersion, nullptr);
|
|
|
|
VSIStatBufL sStatBuf;
|
|
if (VSIStatL(osABISpecificDir, &sStatBuf) != 0)
|
|
osABISpecificDir = papszSearchPaths[iDir];
|
|
|
|
char **papszFiles = CPLReadDir(osABISpecificDir);
|
|
for (int i = 0; papszFiles && papszFiles[i]; i++)
|
|
{
|
|
if ((STARTS_WITH_CI(papszFiles[i], "gdal_") ||
|
|
STARTS_WITH_CI(papszFiles[i], "ogr_")) &&
|
|
EQUAL(CPLGetExtension(papszFiles[i]), "py"))
|
|
{
|
|
aosPythonFiles.push_back(
|
|
CPLFormFilename(osABISpecificDir, papszFiles[i], nullptr));
|
|
}
|
|
}
|
|
CSLDestroy(papszFiles);
|
|
}
|
|
CSLDestroy(papszSearchPaths);
|
|
|
|
for (const auto &osPythonFile : aosPythonFiles)
|
|
{
|
|
LoadPythonDriver(osPythonFile);
|
|
}
|
|
}
|
|
|
|
/************************************************************************/
|
|
/* CleanupPythonDrivers() */
|
|
/************************************************************************/
|
|
|
|
void GDALDriverManager::CleanupPythonDrivers()
|
|
{
|
|
if (gpoGDALPythonDriverModule)
|
|
{
|
|
// On Windows, with pytest, GDALDestroy() can call this after having
|
|
// stopped Python, so do not attempt any Python related action.
|
|
if (Py_IsInitialized())
|
|
{
|
|
GIL_Holder oHolder(false);
|
|
Py_DecRef(Py_None);
|
|
Py_DecRef(gpoGDALPythonDriverModule);
|
|
}
|
|
Py_None = nullptr;
|
|
gpoGDALPythonDriverModule = nullptr;
|
|
}
|
|
}
|
|
|
|
#endif
|