diff --git a/src/Base/PersistencePy.xml b/src/Base/PersistencePy.xml index 0408f0d15f..cf10cd72a3 100644 --- a/src/Base/PersistencePy.xml +++ b/src/Base/PersistencePy.xml @@ -14,7 +14,7 @@ This is the Persistence class This is a persistence class - + Content of the object in XML representation @@ -26,5 +26,22 @@ + + + Dumps the content of the object, both the XML representation as well as the additional datafiles + required, into a byte representation. It will be returned as byte array. + dumpContent() -- returns a byte array with full content + dumpContent(Compression=1-9) -- Sets the data compression from 0 (no) to 9 (max) + + + + + + Restore the content of the object from a byte representation as stored by \"dumpContent\". + It could be restored from any python object implementing the buffer protocol. + restoreContent(buffer) -- restores from the given byte array + + + - + diff --git a/src/Base/PersistencePyImp.cpp b/src/Base/PersistencePyImp.cpp index ac2d4c79b0..890773996b 100644 --- a/src/Base/PersistencePyImp.cpp +++ b/src/Base/PersistencePyImp.cpp @@ -23,6 +23,7 @@ #include "PreCompiled.h" #include "Writer.h" +#include "Reader.h" #include "Persistence.h" // inclution of the generated files (generated By PersitancePy.xml) @@ -48,16 +49,117 @@ Py::String PersistencePy::getContent(void) const return Py::String (writer.getString()); } -void PersistencePy::setContent(Py::String /*arg*/) -{ - throw Py::AttributeError(std::string("Attribute 'Content' of object 'Persistence' is read-only")); -} - Py::Int PersistencePy::getMemSize(void) const { return Py::Int((long)getPersistencePtr()->getMemSize()); } +PyObject* PersistencePy::dumpContent(PyObject *args, PyObject *kwds) { + + int compression = 3; + static char* kwds_def[] = {"Compression",NULL}; + PyErr_Clear(); + if (!PyArg_ParseTupleAndKeywords(args, kwds, "|i", kwds_def, &compression)) { + return NULL; + } + + //setup the streams + std::stringstream stream(std::stringstream::out | std::stringstream::in | std::stringstream::binary); + + //we need to close the zipstream to get a good result, the only way to do this is to delete the ZipWriter. + //Hence the scope... + { + //create the writer + Base::ZipWriter writer(stream); + writer.setLevel(compression); + writer.putNextEntry("Document.xml"); + writer.setMode("BinaryBrep"); + + //save the content + getPersistencePtr()->Save(writer); + writer.writeFiles(); + } + + //build the byte array with correct size + if(!stream.seekp(0, stream.end)) { + PyErr_SetString(PyExc_IOError, "Unable to find end of stream"); + return NULL; + } + std::stringstream::pos_type offset = stream.tellp(); + if(!stream.seekg(0, stream.beg)) { + PyErr_SetString(PyExc_IOError, "Unable to find begin of stream"); + return NULL; + } + + PyObject* ba = PyByteArray_FromStringAndSize(NULL, offset); + + //use the buffer protocol to access the underlying array and write into it + Py_buffer buf = Py_buffer(); + PyObject_GetBuffer(ba, &buf, PyBUF_WRITABLE); + try { + if(!stream.read((char*)buf.buf, offset)) { + PyErr_SetString(PyExc_IOError, "Error copying data into byte array"); + return NULL; + } + PyBuffer_Release(&buf); + } + catch(...) { + PyBuffer_Release(&buf); + PyErr_SetString(PyExc_IOError, "Error copying data into byte array"); + return NULL; + } + + return ba; +} + +PyObject* PersistencePy::restoreContent(PyObject *args) { + + PyObject* buffer; + if( !PyArg_ParseTuple(args, "O", &buffer) ) + return NULL; + + //check if it really is a buffer + if( !PyObject_CheckBuffer(buffer) ) { + PyErr_SetString(PyExc_TypeError, "Must be a buffer object"); + return NULL; + } + + Py_buffer buf; + if(PyObject_GetBuffer(buffer, &buf, PyBUF_SIMPLE) < 0) + return NULL; + + if(!PyBuffer_IsContiguous(&buf, 'C')) { + PyErr_SetString(PyExc_TypeError, "Buffer must be contiguous"); + return NULL; + } + + try { + + //TODO: this mkes a stupid copy, we should make a stream directly from the buffer + std::stringstream stream(std::string((char*)buf.buf, buf.len), std::stringstream::in | std::stringstream::binary); + + zipios::ZipInputStream zipstream(stream); + Base::XMLReader reader("", zipstream); + + if (!reader.isValid()) { + PyErr_SetString(PyExc_IOError, "Unable to read file"); + return NULL; + } + + getPersistencePtr()->Restore(reader); + reader.readFiles(zipstream); + } + catch (const Base::Exception& e) { + PyErr_SetString(PyExc_IOError, e.what()); + return NULL; + } + catch (const std::exception& e) { + PyErr_SetString(PyExc_IOError, e.what()); + return NULL; + } + + return Py_None; +} PyObject *PersistencePy::getCustomAttributes(const char*) const {