diff options
author | Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> | 2019-02-27 16:54:31 +0100 |
---|---|---|
committer | Cristian Maureira-Fredes <cristian.maureira-fredes@qt.io> | 2019-03-15 16:47:46 +0000 |
commit | 45e3c96a8075d210b70eabdb2ef9c3f7f1ca17af (patch) | |
tree | 640e32355745259489fabcf7834c599cf717178d | |
parent | 264f7fccaffa79d947b872a8179993ef547e069c (diff) |
Add toBytes() and BufferProtocol
VoidPtr:
Add toBytes() method that return a char* representation
of the void* pointer.
QByteArray:
The current implementation only provided the Buffer Protocol
for Python2, this patch includes the getbuffer implementation
for Python3.
Having a BufferProtocol implementation for Python3 allows the
initialization of VoidPtr to get access to the internal content,
so one can go back and forward with the representation of it:
ba = QByteArray(b"Hello World")
vp = VoidPtr(ba, ba.size())
vp.toBytes() # b"Hello World"
The BufferProtocol was also changed for Python2 including the new
buffer protocol (Py_TPFLAGS_HAVE_NEWBUFFER) function `bf_getbuffer`.
A test case was included.
Fixes: PYSIDE-934
Change-Id: I8936966da91b2dcc879c582cfc35e6a35f7a60b6
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Alexandru Croitor <alexandru.croitor@qt.io>
-rw-r--r-- | sources/pyside2/PySide2/glue/qtcore.cpp | 46 | ||||
-rw-r--r-- | sources/pyside2/tests/support/voidptr_test.py | 18 | ||||
-rw-r--r-- | sources/shiboken2/libshiboken/voidptr.cpp | 65 |
3 files changed, 100 insertions, 29 deletions
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp index 629484458..6259724c3 100644 --- a/sources/pyside2/PySide2/glue/qtcore.cpp +++ b/sources/pyside2/PySide2/glue/qtcore.cpp @@ -965,13 +965,33 @@ if (PyIndex_Check(_key)) { // @snippet qbytearray-msetitem // @snippet qbytearray-bufferprotocol -#if PY_VERSION_HEX < 0x03000000 - +extern "C" { // QByteArray buffer protocol functions // see: http://www.python.org/dev/peps/pep-3118/ -extern "C" { +static int SbkQByteArray_getbufferproc(PyObject* obj, Py_buffer *view, int flags) +{ + if (!view || !Shiboken::Object::isValid(obj)) + return -1; + + QByteArray* cppSelf = %CONVERTTOCPP[QByteArray*](obj); + view->obj = obj; + view->buf = reinterpret_cast<void*>(cppSelf->data()); + view->len = cppSelf->size(); + view->readonly = 0; + view->itemsize = 1; + view->format = const_cast<char*>("c"); + view->ndim = 1; + view->shape = NULL; + view->strides = &view->itemsize; + view->suboffsets = NULL; + view->internal = NULL; + + Py_XINCREF(obj); + return 0; +} +#if PY_VERSION_HEX < 0x03000000 static Py_ssize_t SbkQByteArray_segcountproc(PyObject* self, Py_ssize_t* lenp) { if (lenp) @@ -993,12 +1013,18 @@ PyBufferProcs SbkQByteArrayBufferProc = { /*bf_getreadbuffer*/ &SbkQByteArray_readbufferproc, /*bf_getwritebuffer*/ (writebufferproc) &SbkQByteArray_readbufferproc, /*bf_getsegcount*/ &SbkQByteArray_segcountproc, - /*bf_getcharbuffer*/ (charbufferproc) &SbkQByteArray_readbufferproc + /*bf_getcharbuffer*/ (charbufferproc) &SbkQByteArray_readbufferproc, + /*bf_getbuffer*/ (getbufferproc)SbkQByteArray_getbufferproc, }; +#else -} +static PyBufferProcs SbkQByteArrayBufferProc = { + /*bf_getbuffer*/ (getbufferproc)SbkQByteArray_getbufferproc, + /*bf_releasebuffer*/ (releasebufferproc)0, +}; #endif +} // @snippet qbytearray-bufferprotocol // @snippet qbytearray-operatorplus-1 @@ -1110,8 +1136,14 @@ if (PyBytes_Check(%PYARG_1)) { // @snippet qbytearray-py3 #if PY_VERSION_HEX < 0x03000000 - Shiboken::SbkType<QByteArray>()->tp_as_buffer = &SbkQByteArrayBufferProc; - Shiboken::SbkType<QByteArray>()->tp_flags |= Py_TPFLAGS_HAVE_GETCHARBUFFER; +Shiboken::SbkType<QByteArray>()->tp_as_buffer = &SbkQByteArrayBufferProc; +Shiboken::SbkType<QByteArray>()->tp_flags |= Py_TPFLAGS_HAVE_NEWBUFFER; +#else +#ifdef Py_LIMITED_API +PepType_AS_BUFFER(Shiboken::SbkType<QByteArray>()) = &SbkQByteArrayBufferProc; +#else +Shiboken::SbkType<QByteArray>()->tp_as_buffer = &SbkQByteArrayBufferProc; +#endif #endif // @snippet qbytearray-py3 diff --git a/sources/pyside2/tests/support/voidptr_test.py b/sources/pyside2/tests/support/voidptr_test.py index 330788c63..c04022489 100644 --- a/sources/pyside2/tests/support/voidptr_test.py +++ b/sources/pyside2/tests/support/voidptr_test.py @@ -38,9 +38,21 @@ class PySide2Support(unittest.TestCase): # a C++ object, a wrapped Shiboken Object type, # an object implementing the Python Buffer interface, # or another VoidPtr object. - ba = QByteArray(b"Hello world") - voidptr = VoidPtr(ba) - self.assertIsInstance(voidptr, shiboken.VoidPtr) + + # Original content + b = b"Hello world" + ba = QByteArray(b) + vp = VoidPtr(ba, ba.size()) + self.assertIsInstance(vp, shiboken.VoidPtr) + + # Create QByteArray from voidptr byte interpretation + nba = QByteArray.fromRawData(vp.toBytes()) + # Compare original bytes to toBytes() + self.assertTrue(b, vp.toBytes()) + # Compare original with new QByteArray data + self.assertTrue(b, nba.data()) + # Convert original and new to str + self.assertTrue(str(b), str(nba)) if __name__ == '__main__': unittest.main() diff --git a/sources/shiboken2/libshiboken/voidptr.cpp b/sources/shiboken2/libshiboken/voidptr.cpp index a306f7a9d..e55ccfab5 100644 --- a/sources/shiboken2/libshiboken/voidptr.cpp +++ b/sources/shiboken2/libshiboken/voidptr.cpp @@ -95,13 +95,6 @@ int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) sbkSelf->size = sbkOther->size; sbkSelf->isWritable = sbkOther->isWritable; } - // Shiboken::Object wrapper. - else if (Shiboken::Object::checkType(addressObject)) { - SbkObject *sbkOther = reinterpret_cast<SbkObject *>(addressObject); - sbkSelf->cptr = sbkOther->d->cptr[0]; - sbkSelf->size = size; - sbkSelf->isWritable = isWritable > 0 ? true : false; - } // Python buffer interface. else if (PyObject_CheckBuffer(addressObject)) { Py_buffer bufferView; @@ -111,26 +104,41 @@ int SbkVoidPtrObject_init(PyObject *self, PyObject *args, PyObject *kwds) return 0; sbkSelf->cptr = bufferView.buf; - sbkSelf->size = bufferView.len; + sbkSelf->size = bufferView.len > 0 ? bufferView.len : size; sbkSelf->isWritable = bufferView.readonly > 0 ? false : true; // Release the buffer. PyBuffer_Release(&bufferView); } + // Shiboken::Object wrapper. + else if (Shiboken::Object::checkType(addressObject)) { + SbkObject *sbkOther = reinterpret_cast<SbkObject *>(addressObject); + sbkSelf->cptr = sbkOther->d->cptr[0]; + sbkSelf->size = size; + sbkSelf->isWritable = isWritable > 0 ? true : false; + } // An integer representing an address. 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; + 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 ? true : false; } - sbkSelf->cptr = cptr; - sbkSelf->size = size; - sbkSelf->isWritable = isWritable > 0 ? true : false; } return 0; @@ -174,6 +182,24 @@ PyObject *SbkVoidPtrObject_int(PyObject *v) return PyLong_FromVoidPtr(sbkObject->cptr); } +PyObject *toBytes(PyObject *self, PyObject *args) +{ + SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(self); + if (sbkObject->size < 0) { + PyErr_SetString(PyExc_IndexError, "VoidPtr does not have a size set."); + return nullptr; + } + 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}, + {0} +}; + static Py_ssize_t SbkVoidPtrObject_length(PyObject *v) { SbkVoidPtrObject *sbkObject = reinterpret_cast<SbkVoidPtrObject *>(v); @@ -233,6 +259,7 @@ static PyType_Slot SbkVoidPtrType_slots[] = { {Py_tp_init, (void *)SbkVoidPtrObject_init}, {Py_tp_new, (void *)SbkVoidPtrObject_new}, {Py_tp_dealloc, (void *)object_dealloc}, + {Py_tp_methods, (void *)SbkVoidPtrObject_methods}, {0, 0} }; static PyType_Spec SbkVoidPtrType_spec = { |