diff --git a/setup.py b/setup.py index 9637443..c6f8391 100644 --- a/setup.py +++ b/setup.py @@ -10,7 +10,7 @@ module_pEp = Extension('pEp', sources = glob('src/*.cc'), include_dirs = [prefix+'/include', boost+'/include',], library_dirs = [prefix+'/lib', boost+'/lib',], - libraries = ['pEpEngine', 'boost_python-mt',], + libraries = ['pEpEngine', 'boost_python-mt', 'boost_locale-mt',], ) setup( diff --git a/src/Identity.hh b/src/Identity.hh index 5c15414..4ad786d 100644 --- a/src/Identity.hh +++ b/src/Identity.hh @@ -8,6 +8,8 @@ namespace pEp { namespace PythonAdapter { using namespace utility; + // Identity is owning a pEp_identity + class Identity { pEp_identity *_ident; diff --git a/src/message.cc b/src/message.cc index 081b73b..e6b27c6 100644 --- a/src/message.cc +++ b/src/message.cc @@ -1,19 +1,83 @@ +#include #include "message.hh" #include +#include +#include namespace pEp { namespace PythonAdapter { using namespace std; - Message::Blob::Blob(bloblist_t *bl) - : data(bl->value, bl->value+bl->size) + Message::Blob::Blob(bloblist_t *bl) : _bl(bl), part_of_chain(false) { - if (bl->mime_type) - mime_type = bl->mime_type; - if (bl->filename) - filename = bl->filename; + if (!_bl) + throw bad_alloc(); + } + + Message::Blob::Blob(object data) : + _bl(new_bloblist(NULL, 0, NULL, NULL)), part_of_chain(false) + { + if (!_bl) + throw bad_alloc(); + + Py_buffer src; + int result = PyObject_GetBuffer(data.ptr(), &src, PyBUF_CONTIG_RO); + if (result) + throw invalid_argument("need a contiguous buffer to read"); + + char *mem = (char *)malloc(src.len); + if (!mem) { + PyBuffer_Release(&src); + throw bad_alloc(); + } + + memcpy(mem, src.buf, src.len); + free(_bl->value); + _bl->size = src.len; + _bl->value = mem; + + PyBuffer_Release(&src); + } + + Message::Blob::Blob(const Message::Blob& second) : + _bl(bloblist_dup(second._bl)), part_of_chain(false) + { + if (!_bl) + throw bad_alloc(); + } + + Message::Blob::~Blob() + { + if (!part_of_chain) { + free(_bl->value); + free(_bl); + } } + int Message::Blob::getbuffer(PyObject *self, Py_buffer *view, int flags) { + bloblist_t *bl = NULL; + + try { + Message::Blob& blob = extract< Message::Blob& >(self); + bl = blob._bl; + } + catch (exception& e) { + PyErr_SetString(PyExc_RuntimeError, "extract not possible"); + view->obj = NULL; + return -1; + } + + if (!(bl && bl->value)) { + PyErr_SetString(PyExc_RuntimeError, "no data available"); + view->obj = NULL; + return -1; + } + + return PyBuffer_FillInfo(view, self, bl->value, bl->size, 0, flags); + } + + PyBufferProcs Message::Blob::bp = { getbuffer, NULL }; + Message::Message(PEP_msg_direction dir) : _msg(new_message(dir)) { diff --git a/src/message.hh b/src/message.hh index 5b8813a..5ed0107 100644 --- a/src/message.hh +++ b/src/message.hh @@ -1,28 +1,50 @@ #pragma once +#include #include #include #include #include +#include #include "str_attr.hh" namespace pEp { namespace PythonAdapter { using namespace utility; + using namespace boost::python; - class Message { - struct Blob { - vector data; - string mime_type; - string filename; - Blob() { } - Blob(bloblist_t *bl); - operator bloblist_t *(); - }; + // Message is owning a message struct + class Message { message *_msg; public: + // Blob is owning a bloblist_t struct + + class Blob { + bloblist_t *_bl; + bool part_of_chain; + + public: + Blob(bloblist_t *bl = new_bloblist(NULL, 0, NULL, NULL)); + Blob(object data); + Blob(const Blob& second); + ~Blob(); + + string mime_type() { return _bl ? str_attr(_bl->mime_type) : ""; } + void mime_type(string value) { str_attr(_bl->mime_type, value); } + + string filename() { return str_attr(_bl->filename); } + void filename(string value) { str_attr(_bl->filename, value); } + + size_t size() { return _bl->size; } + + static PyBufferProcs bp; + + protected: + static int getbuffer(PyObject *self, Py_buffer *view, int flags); + }; + Message(PEP_msg_direction dir = PEP_dir_outgoing); Message(const Message& second); Message(message *ident); diff --git a/src/pEpmodule.cc b/src/pEpmodule.cc index fd1ee84..4d28030 100644 --- a/src/pEpmodule.cc +++ b/src/pEpmodule.cc @@ -1,7 +1,9 @@ #include "pEpmodule.hh" +#include #include #include #include "Identity.hh" +#include "Message.hh" namespace pEp { namespace PythonAdapter { @@ -19,10 +21,14 @@ namespace pEp { BOOST_PYTHON_MODULE(pEp) { using namespace boost::python; + using namespace boost::locale; using namespace pEp::PythonAdapter; docstring_options doc_options(true, true, false); + generator gen; + std::locale::global(gen("")); + def("about", about, "delivers the p≡p about string"); class_("Identity", "p≡p identity") @@ -51,5 +57,17 @@ BOOST_PYTHON_MODULE(pEp) "true if own identity, false otherwise") .add_property("flags", (identity_flags_t(Identity::*)()) &Identity::flags, (void(Identity::*)(identity_flags_t)) &Identity::flags); + + auto blob = class_("Blob", "Binary large object", + init< object >(args("data"), "init buffer with binary data") ) + .add_property("mime_type", (string(Message::Blob::*)()) &Message::Blob::mime_type, + (void(Message::Blob::*)(string)) &Message::Blob::mime_type, + "MIME type of object in Blob") + .add_property("filename", (string(Message::Blob::*)()) &Message::Blob::filename, + (void(Message::Blob::*)(string)) &Message::Blob::filename, + "filename of object in Blob") + .add_property("size", &Message::Blob::size, "size of Blob in bytes"); + + ((PyTypeObject *)(void *)blob.ptr())->tp_as_buffer = &Message::Blob::bp; } diff --git a/src/str_attr.cc b/src/str_attr.cc index 639be0d..1b28b9f 100644 --- a/src/str_attr.cc +++ b/src/str_attr.cc @@ -1,14 +1,17 @@ #include "str_attr.hh" #include +#include namespace pEp { namespace utility { using namespace std; + using namespace boost::locale; void str_attr(char *&str, string value) { + string normalized = normalize(value, norm_nfc); free(str); - str = strdup(value.c_str()); + str = strdup(normalized.c_str()); if (!str) throw bad_alloc(); }