aboutsummaryrefslogtreecommitdiffstats
path: root/lang/python/helpers.c
diff options
context:
space:
mode:
authorJustus Winter <[email protected]>2016-05-27 12:04:28 +0000
committerJustus Winter <[email protected]>2016-05-27 12:04:28 +0000
commit2ae847c02731994d99e69d3d025ff01f41406452 (patch)
tree71a4609243a69a10fced3a512715f1a4e915cc6a /lang/python/helpers.c
parentpython: Fix object deallocation. (diff)
downloadgpgme-2ae847c02731994d99e69d3d025ff01f41406452.tar.gz
gpgme-2ae847c02731994d99e69d3d025ff01f41406452.zip
python: Implement data callbacks.
* lang/python/gpgme.i (object_to_gpgme_t): Set exception on error. * lang/python/helpers.c (pyDataReadCb): New function. (pyDataWriteCb): Likewise. (pyDataSeekCb): Likewise. (pyDataReleaseCb): Likewise. (pygpgme_data_new_from_cbs): Likewise. * lang/python/helpers.h (pygpgme_data_new_from_cbs): New prototype. * lang/python/pyme/core.py (Data.__init__): Fix docstring, fix read callbacks. (Data.__del__): Fix read callbacks. (Data._free_readcb): Drop function. (Data._free_datacbs): New function. (Data.new_from_cbs): Fix setting the callbacks. (Data.write): Raise stashed exceptions. (Data.read): Likewise. * lang/python/tests/t-callbacks.py: Test new functionality. * lang/python/tests/t-data.py: Likewise. Signed-off-by: Justus Winter <[email protected]>
Diffstat (limited to 'lang/python/helpers.c')
-rw-r--r--lang/python/helpers.c242
1 files changed, 242 insertions, 0 deletions
diff --git a/lang/python/helpers.c b/lang/python/helpers.c
index 9fe81c9f..4792c87d 100644
--- a/lang/python/helpers.c
+++ b/lang/python/helpers.c
@@ -402,3 +402,245 @@ gpgme_error_t pyEditCb(void *opaque, gpgme_status_code_t status,
Py_XDECREF(retval);
return err_status;
}
+
+/* Data callbacks. */
+
+/* Read up to SIZE bytes into buffer BUFFER from the data object with
+ the handle HOOK. Return the number of characters read, 0 on EOF
+ and -1 on error. If an error occurs, errno is set. */
+static ssize_t pyDataReadCb(void *hook, void *buffer, size_t size)
+{
+ ssize_t result;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 1);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(2);
+ } else {
+ pyargs = PyTuple_New(1);
+ }
+
+ PyTuple_SetItem(pyargs, 0, PyLong_FromSize_t(size));
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 1, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ if (! PyBytes_Check(retval)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected bytes from read callback, got %s",
+ retval->ob_type->tp_name);
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ if (PyBytes_Size(retval) > size) {
+ PyErr_Format(PyExc_TypeError,
+ "expected %zu bytes from read callback, got %zu",
+ size, PyBytes_Size(retval));
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ memcpy(buffer, PyBytes_AsString(retval), PyBytes_Size(retval));
+ result = PyBytes_Size(retval);
+
+ leave:
+ Py_XDECREF(retval);
+ return result;
+}
+
+/* Write up to SIZE bytes from buffer BUFFER to the data object with
+ the handle HOOK. Return the number of characters written, or -1
+ on error. If an error occurs, errno is set. */
+static ssize_t pyDataWriteCb(void *hook, const void *buffer, size_t size)
+{
+ ssize_t result;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 2);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(2);
+ } else {
+ pyargs = PyTuple_New(1);
+ }
+
+ PyTuple_SetItem(pyargs, 0, PyBytes_FromStringAndSize(buffer, size));
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 1, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ if (! PyLong_Check(retval)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected int from read callback, got %s",
+ retval->ob_type->tp_name);
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ result = PyLong_AsSsize_t(retval);
+
+ leave:
+ Py_XDECREF(retval);
+ return result;
+}
+
+/* Set the current position from where the next read or write starts
+ in the data object with the handle HOOK to OFFSET, relativ to
+ WHENCE. Returns the new offset in bytes from the beginning of the
+ data object. */
+static off_t pyDataSeekCb(void *hook, off_t offset, int whence)
+{
+ off_t result;
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 3);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(3);
+ } else {
+ pyargs = PyTuple_New(2);
+ }
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+ PyTuple_SetItem(pyargs, 0, PyLong_FromLongLong((long long) offset));
+#else
+ PyTuple_SetItem(pyargs, 0, PyLong_FromLong((long) offset));
+#endif
+ PyTuple_SetItem(pyargs, 1, PyLong_FromLong((long) whence));
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 2, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred()) {
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+ if (! PyLong_Check(retval)) {
+ PyErr_Format(PyExc_TypeError,
+ "expected int from read callback, got %s",
+ retval->ob_type->tp_name);
+ pygpgme_stash_callback_exception(self);
+ result = -1;
+ goto leave;
+ }
+
+#if defined(_FILE_OFFSET_BITS) && _FILE_OFFSET_BITS == 64
+ result = PyLong_AsLongLong(retval);
+#else
+ result = PyLong_AsLong(retval);
+#endif
+
+ leave:
+ Py_XDECREF(retval);
+ return result;
+}
+
+/* Close the data object with the handle HOOK. */
+static void pyDataReleaseCb(void *hook)
+{
+ PyObject *pyhook = (PyObject *) hook;
+ PyObject *self = NULL;
+ PyObject *func = NULL;
+ PyObject *dataarg = NULL;
+ PyObject *pyargs = NULL;
+ PyObject *retval = NULL;
+
+ assert (PyTuple_Check(pyhook));
+ assert (PyTuple_Size(pyhook) == 5 || PyTuple_Size(pyhook) == 6);
+
+ self = PyTuple_GetItem(pyhook, 0);
+ func = PyTuple_GetItem(pyhook, 4);
+ if (PyTuple_Size(pyhook) == 6) {
+ dataarg = PyTuple_GetItem(pyhook, 5);
+ pyargs = PyTuple_New(1);
+ } else {
+ pyargs = PyTuple_New(0);
+ }
+
+ if (dataarg) {
+ Py_INCREF(dataarg);
+ PyTuple_SetItem(pyargs, 0, dataarg);
+ }
+
+ retval = PyObject_CallObject(func, pyargs);
+ Py_XDECREF(retval);
+ Py_DECREF(pyargs);
+ if (PyErr_Occurred())
+ pygpgme_stash_callback_exception(self);
+}
+
+gpgme_error_t pygpgme_data_new_from_cbs(gpgme_data_t *r_data,
+ PyObject *pycbs,
+ PyObject **freelater)
+{
+ static struct gpgme_data_cbs cbs = {
+ pyDataReadCb,
+ pyDataWriteCb,
+ pyDataSeekCb,
+ pyDataReleaseCb,
+ };
+ PyObject *dataarg = NULL;
+
+ assert (PyTuple_Check(pycbs));
+ assert (PyTuple_Size(pycbs) == 5 || PyTuple_Size(pycbs) == 6);
+
+ Py_INCREF(pycbs);
+ *freelater = pycbs;
+
+ return gpgme_data_new_from_cbs(r_data, &cbs, (void *) pycbs);
+}