diff options
Diffstat (limited to 'xbmc/interfaces/python/swig.h')
-rw-r--r-- | xbmc/interfaces/python/swig.h | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/xbmc/interfaces/python/swig.h b/xbmc/interfaces/python/swig.h new file mode 100644 index 0000000..353d968 --- /dev/null +++ b/xbmc/interfaces/python/swig.h @@ -0,0 +1,202 @@ +/* + * Copyright (C) 2005-2018 Team Kodi + * This file is part of Kodi - https://kodi.tv + * + * SPDX-License-Identifier: GPL-2.0-or-later + * See LICENSES/README.md for more information. + */ + +#pragma once + +#include "interfaces/legacy/AddonClass.h" +#include "interfaces/legacy/Exception.h" +#include "interfaces/legacy/Window.h" + +#include <stdint.h> +#include <string> +#include <typeindex> + +#include <Python.h> + +namespace PythonBindings +{ + /** + * This call will convert the python object passed to a string. The object + * passed must be a python str or unicode object unless coerceToString is + * true. If coerceToString is true then the type must be castable to a string + * using the python call str(pObject). + * + * This method will handle a 'None' that's passed in. If 'None' is passed then + * the resulting buf will contain the value of XBMCAddon::emptyString (which + * is simply a std::string instantiated with the default constructor. + */ + void PyXBMCGetUnicodeString(std::string& buf, PyObject* pObject, bool coerceToString = false, + const char* pos = "unknown", + const char* methodname = "unknown"); + + struct TypeInfo + { + const char* swigType; + TypeInfo* parentType; + PyTypeObject pythonType; + const std::type_index typeIndex; + + explicit TypeInfo(const std::type_info& ti); + }; + + // This will hold the pointer to the api type, whether known or unknown + struct PyHolder + { + PyObject_HEAD + int32_t magicNumber; + const TypeInfo* typeInfo; + XBMCAddon::AddonClass* pSelf; + }; + +#define XBMC_PYTHON_TYPE_MAGIC_NUMBER 0x58626D63 + + /** + * This method retrieves the pointer from the PyHolder. The return value should + * be cast to the appropriate type. + * + * Since the calls to this are generated there's no NULL pointer checks + */ + inline XBMCAddon::AddonClass* retrieveApiInstance(PyObject* pythonObj, const TypeInfo* typeToCheck, + const char* methodNameForErrorString, + const char* typenameForErrorString) + { + if (pythonObj == NULL || pythonObj == Py_None) + return NULL; + if (reinterpret_cast<PyHolder*>(pythonObj)->magicNumber != XBMC_PYTHON_TYPE_MAGIC_NUMBER || !PyObject_TypeCheck(pythonObj, const_cast<PyTypeObject*>((&(typeToCheck->pythonType))))) + throw XBMCAddon::WrongTypeException("Incorrect type passed to \"%s\", was expecting a \"%s\".",methodNameForErrorString,typenameForErrorString); + return reinterpret_cast<PyHolder*>(pythonObj)->pSelf; + } + + bool isParameterRightType(const char* passedType, const char* expectedType, const char* methodNamespacePrefix, bool tryReverse = true); + + XBMCAddon::AddonClass* doretrieveApiInstance(const PyHolder* pythonObj, const TypeInfo* typeInfo, const char* expectedType, + const char* methodNamespacePrefix, const char* methodNameForErrorString); + + /** + * This method retrieves the pointer from the PyHolder. The return value should + * be cast to the appropriate type. + * + * Since the calls to this are generated there's no NULL pointer checks + * + * This method will return NULL if either the pythonObj is NULL or the + * pythonObj is Py_None. + */ + inline XBMCAddon::AddonClass* retrieveApiInstance(const PyObject* pythonObj, const char* expectedType, const char* methodNamespacePrefix, + const char* methodNameForErrorString) + { + return (pythonObj == NULL || pythonObj == Py_None) ? NULL : + doretrieveApiInstance(reinterpret_cast<const PyHolder*>(pythonObj),reinterpret_cast<const PyHolder*>(pythonObj)->typeInfo, expectedType, methodNamespacePrefix, methodNameForErrorString); + } + + /** + * This method is a helper for the generated API. It's called prior to any API + * class constructor being returned from the generated code to Python + */ + void prepareForReturn(XBMCAddon::AddonClass* c); + + /** + * This method is a helper for the generated API. It's called prior to any API + * class destructor being dealloc-ed from the generated code from Python + */ + void cleanForDealloc(XBMCAddon::AddonClass* c); + + /** + * This method is a helper for the generated API. It's called prior to any API + * class destructor being dealloc-ed from the generated code from Python + * + * There is a Catch-22 in the destruction of a Window. 'dispose' needs to be + * called on destruction but cannot be called from the destructor. + * This overrides the default cleanForDealloc to resolve that. + */ + void cleanForDealloc(XBMCAddon::xbmcgui::Window* c); + + /** + * This method allows for conversion of the native api Type to the Python type. + * + * When this form of the call is used (and pythonType isn't NULL) then the + * passed type is used in the instance. This is for classes that extend API + * classes in python. The type passed may not be the same type that's stored + * in the class metadata of the AddonClass of which 'api' is an instance, + * it can be a subclass in python. + * + * if pythonType is NULL then the type is inferred using the class metadata + * stored in the AddonClass instance 'api'. + */ + PyObject* makePythonInstance(XBMCAddon::AddonClass* api, PyTypeObject* pythonType, bool incrementRefCount); + + /** + * This method allows for conversion of the native api Type to the Python type. + * + * When this form of the call is used then the python type constructed will be the + * type given by the class metadata in the AddonClass instance 'api'. + * + * This is just a helper inline to call the other makePythonInstance with NULL as + * the pythonType. + */ + inline PyObject* makePythonInstance(XBMCAddon::AddonClass* api, bool incrementRefCount) + { + return makePythonInstance(api,NULL,incrementRefCount); + } + + void registerAddonClassTypeInformation(const TypeInfo* classInfo); + const TypeInfo* getTypeInfoForInstance(XBMCAddon::AddonClass* obj); + + int dummy_tp_init(PyObject* self, PyObject* args, PyObject* kwds); + + class Director + { + protected: + PyObject* self; + public: + inline Director() : self(NULL) {} + inline void setPyObjectForDirector(PyObject* pyargself) { self = pyargself; } + }; + + /** + * This exception is thrown from Director calls that call into python when the + * Python error is + */ + class PythonToCppException : public XbmcCommons::UncheckedException + { + public: + /** + * Assuming a PyErr_Occurred, this will fill the exception message with all + * of the appropriate information including the traceback if it can be + * obtained. It will also clear the python message. + */ + PythonToCppException(); + PythonToCppException(const std::string &exceptionType, const std::string &exceptionValue, const std::string &exceptionTraceback); + + static bool ParsePythonException(std::string &exceptionType, std::string &exceptionValue, std::string &exceptionTraceback); + + protected: + void SetMessage(const std::string &exceptionType, const std::string &exceptionValue, const std::string &exceptionTraceback); + }; + + template<class T> struct PythonCompare + { + static inline int compare(PyObject* obj1, PyObject* obj2, const char* swigType, const char* methodNamespacePrefix, const char* methodNameForErrorString) + { + XBMC_TRACE; + try + { + T* o1 = (T*)retrieveApiInstance(obj1, swigType, methodNamespacePrefix, methodNameForErrorString); + T* o2 = (T*)retrieveApiInstance(obj2, swigType, methodNamespacePrefix, methodNameForErrorString); + + return ((*o1) < (*o2) ? -1 : + ((*o1) > (*o2) ? 1 : 0)); + } + catch (const XBMCAddon::WrongTypeException& e) + { + CLog::Log(LOGERROR, "EXCEPTION: {}", e.GetExMessage()); + PyErr_SetString(PyExc_RuntimeError, e.GetExMessage()); + } + return -1; + } + }; +} |