summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCristian Maureira-Fredes <cristian.maureira-fredes@qt.io>2019-02-27 16:54:31 +0100
committerCristian Maureira-Fredes <cristian.maureira-fredes@qt.io>2019-03-15 16:47:46 +0000
commit45e3c96a8075d210b70eabdb2ef9c3f7f1ca17af (patch)
tree640e32355745259489fabcf7834c599cf717178d
parent264f7fccaffa79d947b872a8179993ef547e069c (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.cpp46
-rw-r--r--sources/pyside2/tests/support/voidptr_test.py18
-rw-r--r--sources/shiboken2/libshiboken/voidptr.cpp65
3 files changed, 100 insertions, 29 deletions
diff --git a/sources/pyside2/PySide2/glue/qtcore.cpp b/sources/pyside2/PySide2/glue/qtcore.cpp
index 62948445..6259724c 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 330788c6..c0402248 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 a306f7a9..e55ccfab 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 = {