diff options
Diffstat (limited to 'sources/shiboken6/libshiboken/voidptr.cpp')
-rw-r--r-- | sources/shiboken6/libshiboken/voidptr.cpp | 434 |
1 files changed, 434 insertions, 0 deletions
diff --git a/sources/shiboken6/libshiboken/voidptr.cpp b/sources/shiboken6/libshiboken/voidptr.cpp new file mode 100644 index 000000000..8bb3f6ac8 --- /dev/null +++ b/sources/shiboken6/libshiboken/voidptr.cpp @@ -0,0 +1,434 @@ +// Copyright (C) 2017 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only + +#include "voidptr.h" +#include "pep384ext.h" +#include "sbkconverter.h" +#include "basewrapper.h" +#include "basewrapper_p.h" + +extern "C" +{ + +// Void pointer object definition. +struct SbkVoidPtrObject { + PyObject_HEAD + void *cptr; + Py_ssize_t size; + bool isWritable; +}; + +PyObject *SbkVoidPtrObject_new(PyTypeObject *type, PyObject * /* args */, PyObject * /* kwds */) +{ + // PYSIDE-560: It is much safer to first call a function and then do a + // type cast than to do everything in one line. The bad construct looked + // like this, actual call forgotten: + // SbkVoidPtrObject *self = + // reinterpret_cast<SbkVoidPtrObject *>(type->tp_alloc); + auto *self = PepExt_TypeCallAlloc<SbkVoidPtrObject>(type, 0); + + if (self != nullptr) { + self->cptr = nullptr; + self->size = -1; + self->isWritable = false; + } + + return reinterpret_cast<PyObject *>(self); +} + +#define SbkVoidPtr_Check(op) (Py_TYPE(op) == SbkVoidPtr_TypeF()) + + +int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) +{ + PyObject *addressObject; + Py_ssize_t size = -1; + int isWritable = 0; + auto *sbkSelf = reinterpret_cast<SbkVoidPtrObject *>(self); + + static const char *kwlist[] = {"address", "size", "writeable", nullptr}; + + if (!PyArg_ParseTupleAndKeywords(args, kwds, "O|ni", const_cast<char **>(kwlist), + &addressObject, &size, &isWritable)) + return -1; + + // Void pointer. + if (SbkVoidPtr_Check(addressObject)) { + auto *sbkOther = reinterpret_cast<SbkVoidPtrObject *>(addressObject); + sbkSelf->cptr = sbkOther->cptr; + sbkSelf->size = sbkOther->size; + sbkSelf->isWritable = sbkOther->isWritable; + } + // Python buffer interface. + else if (PyObject_CheckBuffer(addressObject)) { + Py_buffer bufferView; + + // Bail out if the object can't provide a simple contiguous buffer. + if (PyObject_GetBuffer(addressObject, &bufferView, PyBUF_SIMPLE) < 0) + return 0; + + sbkSelf->cptr = bufferView.buf; + sbkSelf->size = bufferView.len > 0 ? bufferView.len : size; + sbkSelf->isWritable = bufferView.readonly <= 0; + + // Release the buffer. + PyBuffer_Release(&bufferView); + } + // Shiboken::Object wrapper. + else if (Shiboken::Object::checkType(addressObject)) { + auto *sbkOther = reinterpret_cast<SbkObject *>(addressObject); + sbkSelf->cptr = sbkOther->d->cptr[0]; + sbkSelf->size = size; + sbkSelf->isWritable = isWritable > 0; + } + // An integer representing an address. + else { + if (addressObject == Py_None) { + sbkSelf->cptr = nullptr; + sbkSelf->size = 0; + sbkSelf->isWritable = false; + } + + else { + void *cptr = PyLong_AsVoidPtr(addressObject); + if (PyErr_Occurred()) { + PyErr_SetString(PyExc_TypeError, + "Creating a VoidPtr object requires an address of a C++ object, " + "a wrapped Shiboken Object type, " + "an object implementing the Python Buffer interface, " + "or another VoidPtr object."); + return -1; + } + sbkSelf->cptr = cptr; + sbkSelf->size = size; + sbkSelf->isWritable = isWritable > 0; + } + } + + return 0; +} + +PyObject *SbkVoidPtrObject_richcmp(PyObject *obj1, PyObject *obj2, int op) +{ + PyObject *result = Py_False; + void *cptr1 = nullptr; + void *cptr2 = nullptr; + bool validObjects = true; + + if (SbkVoidPtr_Check(obj1)) + cptr1 = reinterpret_cast<SbkVoidPtrObject *>(obj1)->cptr; + else + validObjects = false; + + if (SbkVoidPtr_Check(obj2)) + cptr2 = reinterpret_cast<SbkVoidPtrObject *>(obj2)->cptr; + else + validObjects = false; + + if (validObjects) { + switch (op) { + case Py_EQ: + if (cptr1 == cptr2) + result = Py_True; + break; + case Py_NE: + if (cptr1 != cptr2) + result = Py_True; + break; + case Py_LT: + case Py_LE: + case Py_GT: + case Py_GE: + break; + } + } + + Py_INCREF(result); + return result; +} + +PyObject *SbkVoidPtrObject_int(PyObject *v) +{ + auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); + return PyLong_FromVoidPtr(sbkObject->cptr); +} + +PyObject *toBytes(PyObject *self, PyObject * /* args */) +{ + auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self); + if (sbkObject->size < 0) + return PyErr_Format(PyExc_IndexError, "VoidPtr does not have a size set."); + + PyObject *bytes = PyBytes_FromStringAndSize(reinterpret_cast<const char *>(sbkObject->cptr), + sbkObject->size); + Py_XINCREF(bytes); + return bytes; +} + +static struct PyMethodDef SbkVoidPtrObject_methods[] = { + {"toBytes", toBytes, METH_NOARGS, nullptr}, + {nullptr, nullptr, 0, nullptr} +}; + +static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) +{ + auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); + if (sbkObject->size < 0) { + PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set."); + return -1; + } + + return sbkObject->size; +} + +static const char trueString[] = "True" ; +static const char falseString[] = "False" ; + +PyObject *SbkVoidPtrObject_repr(PyObject *v) +{ + + + auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); + PyObject *s = PyUnicode_FromFormat("%s(%p, %zd, %s)", + Py_TYPE(sbkObject)->tp_name, + sbkObject->cptr, + sbkObject->size, + sbkObject->isWritable ? trueString : falseString); + Py_XINCREF(s); + return s; +} + +PyObject *SbkVoidPtrObject_str(PyObject *v) +{ + auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); + PyObject *s = PyUnicode_FromFormat("%s(Address %p, Size %zd, isWritable %s)", + Py_TYPE(sbkObject)->tp_name, + sbkObject->cptr, + sbkObject->size, + sbkObject->isWritable ? trueString : falseString); + Py_XINCREF(s); + return s; +} + + +static int SbkVoidPtrObject_getbuffer(PyObject *obj, Py_buffer *view, int flags) +{ + if (view == nullptr) + return -1; + + auto *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(obj); + if (sbkObject->size < 0) + return -1; + + int readonly = sbkObject->isWritable ? 0 : 1; + if (((flags & PyBUF_WRITABLE) == PyBUF_WRITABLE) && + (readonly == 1)) { + PyErr_SetString(PyExc_BufferError, + "Object is not writable."); + return -1; + } + + view->obj = obj; + if (obj) + Py_XINCREF(obj); + view->buf = sbkObject->cptr; + view->len = sbkObject->size; + view->readonly = readonly; + view->itemsize = 1; + view->format = nullptr; + if ((flags & PyBUF_FORMAT) == PyBUF_FORMAT) + view->format = const_cast<char *>("B"); + view->ndim = 1; + view->shape = nullptr; + if ((flags & PyBUF_ND) == PyBUF_ND) + view->shape = &(view->len); + view->strides = nullptr; + if ((flags & PyBUF_STRIDES) == PyBUF_STRIDES) + view->strides = &(view->itemsize); + view->suboffsets = nullptr; + view->internal = nullptr; + return 0; +} + +static PyBufferProcs SbkVoidPtrObjectBufferProc = { + (getbufferproc)SbkVoidPtrObject_getbuffer, // bf_getbuffer + (releasebufferproc)nullptr // bf_releasebuffer +}; + +static PyTypeObject *createVoidPtrType() +{ + PyType_Slot SbkVoidPtrType_slots[] = { + {Py_tp_repr, reinterpret_cast<void *>(SbkVoidPtrObject_repr)}, + {Py_nb_int, reinterpret_cast<void *>(SbkVoidPtrObject_int)}, + {Py_sq_length, reinterpret_cast<void *>(SbkVoidPtrObject_length)}, + {Py_tp_str, reinterpret_cast<void *>(SbkVoidPtrObject_str)}, + {Py_tp_richcompare, reinterpret_cast<void *>(SbkVoidPtrObject_richcmp)}, + {Py_tp_init, reinterpret_cast<void *>(SbkVoidPtrObject_init)}, + {Py_tp_new, reinterpret_cast<void *>(SbkVoidPtrObject_new)}, + {Py_tp_dealloc, reinterpret_cast<void *>(Sbk_object_dealloc)}, + {Py_tp_methods, reinterpret_cast<void *>(SbkVoidPtrObject_methods)}, + {0, nullptr} + }; + + PyType_Spec SbkVoidPtrType_spec = { + "2:shiboken6.Shiboken.VoidPtr", + sizeof(SbkVoidPtrObject), + 0, + Py_TPFLAGS_DEFAULT, + SbkVoidPtrType_slots, + }; + + return SbkType_FromSpec_BMDWB(&SbkVoidPtrType_spec, + nullptr, nullptr, 0, 0, + &SbkVoidPtrObjectBufferProc); +} + +PyTypeObject *SbkVoidPtr_TypeF(void) +{ + static auto *type = createVoidPtrType(); + return type; +} + +} // extern "C" + +namespace VoidPtr { + +static int voidPointerInitialized = false; + +void init() +{ + if (PyType_Ready(SbkVoidPtr_TypeF()) < 0) + Py_FatalError("[libshiboken] Failed to initialize Shiboken.VoidPtr type."); + else + voidPointerInitialized = true; +} + +void addVoidPtrToModule(PyObject *module) +{ + if (voidPointerInitialized) { + Py_INCREF(SbkVoidPtr_TypeF()); + PyModule_AddObject(module, PepType_GetNameStr(SbkVoidPtr_TypeF()), + reinterpret_cast<PyObject *>(SbkVoidPtr_TypeF())); + } +} + +static PyObject *createVoidPtr(void *cppIn, Py_ssize_t size = 0, bool isWritable = false) +{ + if (!cppIn) + Py_RETURN_NONE; + + SbkVoidPtrObject *result = PyObject_New(SbkVoidPtrObject, SbkVoidPtr_TypeF()); + if (!result) + Py_RETURN_NONE; + + result->cptr = cppIn; + result->size = size; + result->isWritable = isWritable; + + return reinterpret_cast<PyObject *>(result); +} + +static PyObject *toPython(const void *cppIn) +{ + return createVoidPtr(const_cast<void *>(cppIn)); +} + +static void VoidPtrToCpp(PyObject *pyIn, void *cppOut) +{ + auto *sbkIn = reinterpret_cast<SbkVoidPtrObject *>(pyIn); + *reinterpret_cast<void **>(cppOut) = sbkIn->cptr; +} + +static PythonToCppFunc VoidPtrToCppIsConvertible(PyObject *pyIn) +{ + return SbkVoidPtr_Check(pyIn) ? VoidPtrToCpp : nullptr; +} + +static void SbkObjectToCpp(PyObject *pyIn, void *cppOut) +{ + auto *sbkIn = reinterpret_cast<SbkObject *>(pyIn); + *reinterpret_cast<void **>(cppOut) = sbkIn->d->cptr[0]; +} + +static PythonToCppFunc SbkObjectToCppIsConvertible(PyObject *pyIn) +{ + return Shiboken::Object::checkType(pyIn) ? SbkObjectToCpp : nullptr; +} + +static void PythonBufferToCpp(PyObject *pyIn, void *cppOut) +{ + if (PyObject_CheckBuffer(pyIn)) { + Py_buffer bufferView; + + // Bail out if the object can't provide a simple contiguous buffer. + if (PyObject_GetBuffer(pyIn, &bufferView, PyBUF_SIMPLE) < 0) + return; + + *reinterpret_cast<void **>(cppOut) = bufferView.buf; + + // Release the buffer. + PyBuffer_Release(&bufferView); + } +} + +static PythonToCppFunc PythonBufferToCppIsConvertible(PyObject *pyIn) +{ + if (PyObject_CheckBuffer(pyIn)) { + Py_buffer bufferView; + + // Bail out if the object can't provide a simple contiguous buffer. + if (PyObject_GetBuffer(pyIn, &bufferView, PyBUF_SIMPLE) < 0) + return nullptr; + + // Release the buffer. + PyBuffer_Release(&bufferView); + + return PythonBufferToCpp; + } + return nullptr; +} + +SbkConverter *createConverter() +{ + SbkConverter *converter = Shiboken::Conversions::createConverter(SbkVoidPtr_TypeF(), toPython); + Shiboken::Conversions::addPythonToCppValueConversion(converter, + VoidPtrToCpp, + VoidPtrToCppIsConvertible); + Shiboken::Conversions::addPythonToCppValueConversion(converter, + SbkObjectToCpp, + SbkObjectToCppIsConvertible); + Shiboken::Conversions::addPythonToCppValueConversion(converter, + PythonBufferToCpp, + PythonBufferToCppIsConvertible); + return converter; +} + +void setSize(PyObject *voidPtr, Py_ssize_t size) +{ + assert(voidPtr->ob_type == SbkVoidPtr_TypeF()); + auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr); + voidPtrObj->size = size; +} + +Py_ssize_t getSize(PyObject *voidPtr) +{ + assert(voidPtr->ob_type == SbkVoidPtr_TypeF()); + auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr); + return voidPtrObj->size; +} + +bool isWritable(PyObject *voidPtr) +{ + assert(voidPtr->ob_type == SbkVoidPtr_TypeF()); + auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr); + return voidPtrObj->isWritable; +} + +void setWritable(PyObject *voidPtr, bool isWritable) +{ + assert(voidPtr->ob_type == SbkVoidPtr_TypeF()); + auto *voidPtrObj = reinterpret_cast<SbkVoidPtrObject *>(voidPtr); + voidPtrObj->isWritable = isWritable; +} + +} // namespace VoidPtr |