/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of PySide2. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 3 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL3 included in the ** packaging of this file. Please review the following information to ** ensure the GNU Lesser General Public License version 3 requirements ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 2.0 or (at your option) the GNU General ** Public license version 3 or any later version approved by the KDE Free ** Qt Foundation. The licenses are as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3 ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-2.0.html and ** https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #ifndef SBK_CONVERTER_P_H #define SBK_CONVERTER_P_H #include "sbkpython.h" #include "sbkconverter.h" #include "sbkstring.h" #include #include #include #include #include #include "sbkdbg.h" extern "C" { typedef std::pair ToCppConversion; typedef std::list ToCppConversionList; /** * \internal * Private structure of SbkConverter. */ struct SbkConverter { /** * Python type associated with this converter. If the type is a Shiboken * wrapper, then it must be a SbkObjectType; otherwise it will be the * Python type to which the C++ value will be converted (note that the * C++ type could be produced from various Python types). */ PyTypeObject* pythonType; /** * This function converts a C++ object to a Python object of the type * indicated in pythonType. The identity of the C++ object is kept, * because it looks for an already existing Python wrapper associated * with the C++ instance. * It is used to convert C++ pointers and references to Python objects. */ CppToPythonFunc pointerToPython; /** * This function converts a C++ object to a Python object of the type * indicated in pythonType. The identity of the object is not kept, * because a new instance of the C++ object is created. * It is used to convert objects passed by value, or reference, if said * reference can't be traced to an object that already has a Python * wrapper assigned for it. */ CppToPythonFunc copyToPython; /** * This is a special case of a Python to C++ conversion. It returns * the underlying C++ pointer of a Python wrapper passed as parameter * or NULL if the Python object is a None value. * It comes separated from the other toCppConversions because if you * have a Python object representing a Value Type the type checking * for both ValueType and ValueType* would be the same, thus the first * check would be true and the second would never be reached. */ ToCppConversion toCppPointerConversion; /** * This is a list of type checking functions that return the * proper Python to C++ conversion function, for the given Python * object. * For Object Types, that never have implicit conversions, this * list is always empty. */ ToCppConversionList toCppConversions; }; } // extern "C" template struct OverFlowCheckerBase { static void formatOverFlowMessage(const MaxLimitType& value, const std::string *valueAsString = 0) { std::ostringstream str; str << "libshiboken: Overflow: Value "; if (valueAsString != 0 && !valueAsString->empty()) str << *valueAsString; else str << value; str << " exceeds limits of type " << " [" << (isSigned ? "signed" : "unsigned") << "] \"" << typeid(T).name() << "\" (" << sizeof(T) << "bytes)."; const std::string message = str.str(); PyErr_WarnEx(PyExc_RuntimeWarning, message.c_str(), 0); } // Checks if an overflow occurred inside Python code. // Precondition: use after calls like PyLong_AsLongLong or PyLong_AsUnsignedLongLong. // Postcondition: if error ocurred, sets the string reference to the string representation of // the passed value. static bool checkForInternalPyOverflow(PyObject *pyIn, std::string &valueAsString) { if (PyErr_Occurred()) { PyErr_Print(); PyObject *stringRepresentation = PyObject_Str(pyIn); const char *cString = Shiboken::String::toCString(stringRepresentation); valueAsString.assign(cString); Py_DECREF(stringRepresentation); return true; } return false; } }; // Helper template for checking if a value overflows when cast to type T. // The MaxLimitType size is usually >= than type T size, so that it can still represent values that // can't be stored in T (unless the types are of course the same). // TLDR: MaxLimitType is either long long or unsigned long long. template::is_signed > struct OverFlowChecker; template struct OverFlowChecker : public OverFlowCheckerBase { static bool check(const MaxLimitType& value, PyObject *pyIn) { std::string valueAsString; const bool isOverflow = OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString) || value < std::numeric_limits::min() || value > std::numeric_limits::max(); if (isOverflow) OverFlowChecker::formatOverFlowMessage(value, &valueAsString); return isOverflow; } }; template struct OverFlowChecker : public OverFlowCheckerBase { static bool check(const MaxLimitType& value, PyObject *pyIn) { std::string valueAsString; const bool isOverflow = OverFlowChecker::checkForInternalPyOverflow(pyIn, valueAsString) || value < 0 || static_cast(value) > std::numeric_limits::max(); if (isOverflow) OverFlowChecker::formatOverFlowMessage(value, &valueAsString); return isOverflow; } }; template<> struct OverFlowChecker : public OverFlowCheckerBase { static bool check(const PY_LONG_LONG &value, PyObject *pyIn) { std::string valueAsString; const bool isOverflow = checkForInternalPyOverflow(pyIn, valueAsString); if (isOverflow) OverFlowChecker::formatOverFlowMessage(value, &valueAsString); return isOverflow; } }; template<> struct OverFlowChecker { static bool check(const double &, PyObject *) { return false; } }; template<> struct OverFlowChecker : public OverFlowCheckerBase { static bool check(const double& value, PyObject *) { const bool result = value < std::numeric_limits::min() || value > std::numeric_limits::max(); if (result) formatOverFlowMessage(value); return result; } }; // Basic primitive type converters --------------------------------------------------------- template struct Primitive {}; template struct OnePrimitive { static PyObject* toPython(const void*) { return 0; } static PythonToCppFunc isConvertible(PyObject*) { return 0; } static void toCpp(PyObject*, void*) {} static SbkConverter* createConverter() { SbkConverter* converter = Shiboken::Conversions::createConverter(Shiboken::SbkType(), Primitive::toPython); Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive::toCpp, Primitive::isConvertible); return converter; } }; template struct TwoPrimitive : OnePrimitive { static PythonToCppFunc isOtherConvertible(PyObject*) { return 0; } static void otherToCpp(PyObject*, void*) {} static SbkConverter* createConverter() { SbkConverter* converter = OnePrimitive::createConverter(); Shiboken::Conversions::addPythonToCppValueConversion(converter, Primitive::otherToCpp, Primitive::isOtherConvertible); return converter; } }; // Integers -------------------------------------------------------------------------------- template struct IntPrimitive : TwoPrimitive { static PyObject* toPython(const void* cppIn) { return PyInt_FromLong(*reinterpret_cast(cppIn)); } static void toCpp(PyObject* pyIn, void* cppOut) { double result = PyFloat_AS_DOUBLE(pyIn); // If cast to long directly it could overflow silently. if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = static_cast(result); } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (PyFloat_Check(pyIn)) return toCpp; return 0; } static void otherToCpp(PyObject* pyIn, void* cppOut) { PY_LONG_LONG result = PyLong_AsLongLong(pyIn); if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = static_cast(result); } static PythonToCppFunc isOtherConvertible(PyObject* pyIn) { if (SbkNumber_Check(pyIn)) return otherToCpp; return 0; } }; template <> struct Primitive : IntPrimitive {}; template <> struct Primitive : IntPrimitive {}; template <> struct Primitive : IntPrimitive {}; template <> struct Primitive : IntPrimitive {}; // Unsigned Long Integers ------------------------------------------------------------------ template struct UnsignedLongPrimitive : IntPrimitive { static PyObject* toPython(const void* cppIn) { return PyLong_FromUnsignedLong(*reinterpret_cast(cppIn)); } }; template <> struct Primitive : UnsignedLongPrimitive {}; template <> struct Primitive : UnsignedLongPrimitive {}; // Big integers ---------------------------------------------------------------------------- template <> struct Primitive : OnePrimitive { static PyObject* toPython(const void* cppIn) { return PyLong_FromLongLong(*((PY_LONG_LONG*)cppIn)); } static void toCpp(PyObject* pyIn, void* cppOut) { PY_LONG_LONG result = PyLong_AsLongLong(pyIn); if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = result; } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (SbkNumber_Check(pyIn)) return toCpp; return 0; } }; template <> struct Primitive : OnePrimitive { static PyObject* toPython(const void* cppIn) { return PyLong_FromUnsignedLongLong(*((unsigned PY_LONG_LONG*)cppIn)); } static void toCpp(PyObject* pyIn, void* cppOut) { #if PY_MAJOR_VERSION >= 3 if (PyLong_Check(pyIn)) { unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn); if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = result; } else { PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); } #else if (PyInt_Check(pyIn)) { long result = PyInt_AsLong(pyIn); if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = static_cast(result); } else if (PyLong_Check(pyIn)) { unsigned PY_LONG_LONG result = PyLong_AsUnsignedLongLong(pyIn); if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = result; } else { PyErr_SetString(PyExc_TypeError, "Invalid type for unsigned long long conversion"); } #endif // Python 2 } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (SbkNumber_Check(pyIn)) return toCpp; return 0; } }; // Floating point -------------------------------------------------------------------------- template struct FloatPrimitive : TwoPrimitive { static PyObject* toPython(const void* cppIn) { return PyFloat_FromDouble(*reinterpret_cast(cppIn)); } static void toCpp(PyObject* pyIn, void* cppOut) { *reinterpret_cast(cppOut) = FLOAT(PyLong_AsLong(pyIn)); } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (PyInt_Check(pyIn) || PyLong_Check(pyIn)) return toCpp; return 0; } static void otherToCpp(PyObject* pyIn, void* cppOut) { *reinterpret_cast(cppOut) = FLOAT(PyFloat_AsDouble(pyIn)); } static PythonToCppFunc isOtherConvertible(PyObject* pyIn) { if (SbkNumber_Check(pyIn)) return otherToCpp; return 0; } }; template <> struct Primitive : FloatPrimitive {}; template <> struct Primitive : FloatPrimitive {}; // Boolean --------------------------------------------------------------------------------- template <> struct Primitive : OnePrimitive { static PyObject* toPython(const void* cppIn) { return PyBool_FromLong(*reinterpret_cast(cppIn)); } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (SbkNumber_Check(pyIn)) return toCpp; return 0; } static void toCpp(PyObject* pyIn, void* cppOut) { *reinterpret_cast(cppOut) = PyInt_AS_LONG(pyIn) != 0; } }; // Characters ------------------------------------------------------------------------------ template struct CharPrimitive : IntPrimitive { static void toCpp(PyObject* pyIn, void* cppOut) { *reinterpret_cast(cppOut) = CHAR(Shiboken::String::toCString(pyIn)[0]); } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (Shiboken::String::checkChar(pyIn)) return toCpp; return 0; } static void otherToCpp(PyObject* pyIn, void* cppOut) { PY_LONG_LONG result = PyLong_AsLongLong(pyIn); if (OverFlowChecker::check(result, pyIn)) PyErr_SetObject(PyExc_OverflowError, 0); *reinterpret_cast(cppOut) = CHAR(result); } static PythonToCppFunc isOtherConvertible(PyObject* pyIn) { if (SbkNumber_Check(pyIn)) return otherToCpp; return 0; } static SbkConverter* createConverter() { SbkConverter* converter = IntPrimitive::createConverter(); Shiboken::Conversions::addPythonToCppValueConversion(converter, CharPrimitive::otherToCpp, CharPrimitive::isOtherConvertible); return converter; } }; template <> struct Primitive : CharPrimitive {}; template <> struct Primitive : CharPrimitive {}; template <> struct Primitive : CharPrimitive { using CharPrimitive::toPython; static PyObject* toPython(const void* cppIn) { return Shiboken::String::fromCString((const char*)cppIn, 1); } }; // Strings --------------------------------------------------------------------------------- template <> struct Primitive : TwoPrimitive { static PyObject* toPython(const void* cppIn) { if (!cppIn) Py_RETURN_NONE; return Shiboken::String::fromCString((const char*)cppIn); } static void toCpp(PyObject *, void *cppOut) { *((const char**)cppOut) = 0; } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (pyIn == Py_None) return toCpp; return 0; } static void otherToCpp(PyObject* pyIn, void* cppOut) { *((const char**)cppOut) = (const char*) Shiboken::String::toCString(pyIn); } static PythonToCppFunc isOtherConvertible(PyObject* pyIn) { if (Shiboken::String::check(pyIn)) return otherToCpp; return 0; } }; template <> struct Primitive : TwoPrimitive { static PyObject* toPython(const void* cppIn) { return Shiboken::String::fromCString(((std::string*)cppIn)->c_str()); } static void toCpp(PyObject *, void *cppOut) { *((std::string*)cppOut) = std::string(); } static PythonToCppFunc isConvertible(PyObject* pyIn) { if (pyIn == Py_None) return toCpp; return 0; } static void otherToCpp(PyObject* pyIn, void* cppOut) { *((std::string*)cppOut) = Shiboken::String::toCString(pyIn); } static PythonToCppFunc isOtherConvertible(PyObject* pyIn) { if (Shiboken::String::check(pyIn)) return otherToCpp; return 0; } }; #endif // SBK_CONVERTER_P_H