diff options
author | Justus Winter <[email protected]> | 2016-05-27 12:04:28 +0000 |
---|---|---|
committer | Justus Winter <[email protected]> | 2016-05-27 12:04:28 +0000 |
commit | 2ae847c02731994d99e69d3d025ff01f41406452 (patch) | |
tree | 71a4609243a69a10fced3a512715f1a4e915cc6a /lang/python/helpers.c | |
parent | python: Fix object deallocation. (diff) | |
download | gpgme-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.c | 242 |
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); +} |