diff --git a/src/App/PropertyContainerPy.xml b/src/App/PropertyContainerPy.xml index 112ad67a08..cac74ff110 100644 --- a/src/App/PropertyContainerPy.xml +++ b/src/App/PropertyContainerPy.xml @@ -60,17 +60,17 @@ If the list contains 'Hidden' then the item even doesn't appear in the property Dumps the content of the property, both the XML representation as well as the additional datafiles - required, into a byte representation. It will be returned as byte array. - dumpPropertyContent(propertyname) -- returns a byte array with full content - dumpPropertyContent(propertyname, [Compression=1-9]) -- Sets the data compression from 0 (no) to 9 (max) +required, into a byte representation. It will be returned as byte array. +dumpPropertyContent(propertyname) -- returns a byte array with full content +dumpPropertyContent(propertyname, [Compression=1-9]) -- Sets the data compression from 0 (no) to 9 (max) Restore the content of given property from a byte representation as stored by \"dumpContent\". - It could be restored from any python object implementing the buffer protocol. - restorePropertyContent(propertyname, buffer) -- restores from the given byte array +It could be restored from any python object implementing the buffer protocol. +restorePropertyContent(propertyname, buffer) -- restores from the given byte array diff --git a/src/App/PropertyContainerPyImp.cpp b/src/App/PropertyContainerPyImp.cpp index f8182dcac7..fe7b3821d2 100644 --- a/src/App/PropertyContainerPyImp.cpp +++ b/src/App/PropertyContainerPyImp.cpp @@ -32,6 +32,9 @@ #include "Property.h" #include "Application.h" +#include +#include + // inclution of the generated files (generated out of PropertyContainerPy.xml) #include "PropertyContainerPy.h" #include "PropertyContainerPy.cpp" @@ -241,9 +244,48 @@ PyObject* PropertyContainerPy::dumpPropertyContent(PyObject *args, PyObject *kwd if (!prop) { PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", property); return 0; + } + + //setup the stream. the in flag is needed to make "read" work + std::stringstream stream(std::stringstream::out | std::stringstream::in | std::stringstream::binary); + try { + prop->dumpToStream(stream, compression); + } + catch(...) { + PyErr_SetString(PyExc_IOError, "Unable parse content into binary representation"); + return NULL; + } + + //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; } - return prop->dumpToPython(compression); + 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* PropertyContainerPy::restorePropertyContent(PyObject *args) { @@ -259,7 +301,33 @@ PyObject* PropertyContainerPy::restorePropertyContent(PyObject *args) { return 0; } - return prop->restoreFromPython(buffer); + //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; + } + + //check if it really is a buffer + try { + typedef boost::iostreams::basic_array_source Device; + boost::iostreams::stream stream((char*)buf.buf, buf.len); + prop->restoreFromStream(stream); + } + catch(...) { + PyErr_SetString(PyExc_IOError, "Unable to restore content"); + return NULL; + } + + Py_Return; } PyObject *PropertyContainerPy::getCustomAttributes(const char* attr) const diff --git a/src/Base/Persistence.cpp b/src/Base/Persistence.cpp index e46f4c61aa..bcb0d4589b 100644 --- a/src/Base/Persistence.cpp +++ b/src/Base/Persistence.cpp @@ -26,9 +26,6 @@ #include "Reader.h" #include "PyObjectBase.h" -#include -#include - #ifndef _PreComp_ #endif @@ -102,10 +99,7 @@ std::string Persistence::encodeAttribute(const std::string& str) return tmp; } -PyObject* Persistence::dumpToPython(int compression) { - - //setup the stream. the in flag is needed to make "read" work^ - std::stringstream stream(std::stringstream::out | std::stringstream::in | std::stringstream::binary); +void Persistence::dumpToStream(std::ostream& stream, int compression) { //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... @@ -113,7 +107,7 @@ PyObject* Persistence::dumpToPython(int compression) { //create the writer Base::ZipWriter writer(stream); writer.setLevel(compression); - writer.putNextEntry("Document.xml"); + writer.putNextEntry("Persistence.xml"); writer.setMode("BinaryBrep"); //save the content (we need to encapsulte it with xml tags to be able to read single element xmls like happen for properties) @@ -122,81 +116,17 @@ PyObject* Persistence::dumpToPython(int compression) { writer.Stream() << ""; 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* Persistence::restoreFromPython(PyObject *buffer) { +void Persistence::restoreFromStream(std::istream& stream) { + + zipios::ZipInputStream zipstream(stream); + Base::XMLReader reader("", zipstream); - //check if it really is a buffer - if( !PyObject_CheckBuffer(buffer) ) { - PyErr_SetString(PyExc_TypeError, "Must be a buffer object"); - return NULL; - } + if (!reader.isValid()) + throw Base::ValueError("Unable to construct reader"); - 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 { - - typedef boost::iostreams::basic_array_source Device; - boost::iostreams::stream stream((char*)buf.buf, buf.len); - - zipios::ZipInputStream zipstream(stream); - Base::XMLReader reader("", zipstream); - - if (!reader.isValid()) { - PyErr_SetString(PyExc_IOError, "Unable to read file"); - return NULL; - } - - reader.readElement("Content"); - 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; + reader.readElement("Content"); + Restore(reader); + reader.readFiles(zipstream); } diff --git a/src/Base/Persistence.h b/src/Base/Persistence.h index 1ec0c0d81c..5b305e9845 100644 --- a/src/Base/Persistence.h +++ b/src/Base/Persistence.h @@ -149,11 +149,11 @@ public: /// Encodes an attribute upon saving. static std::string encodeAttribute(const std::string&); - //dump the persistence data into a python byte array data structure - PyObject* dumpToPython(int compression); + //dump the binary persistence data into into the stream + void dumpToStream(std::ostream& stream, int compression); - //restore the persistence data from a python data structure that supports the buffer protocol - PyObject* restoreFromPython(PyObject*); + //restore the binary persistence data from a stream. Must have the format used by dumpToStream + void restoreFromStream(std::istream& stream); }; } //namespace Base diff --git a/src/Base/PersistencePy.xml b/src/Base/PersistencePy.xml index cf10cd72a3..1be978748b 100644 --- a/src/Base/PersistencePy.xml +++ b/src/Base/PersistencePy.xml @@ -29,17 +29,17 @@ 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) +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 +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 823631b9ad..6d796778d1 100644 --- a/src/Base/PersistencePyImp.cpp +++ b/src/Base/PersistencePyImp.cpp @@ -24,6 +24,8 @@ #include "PreCompiled.h" #include "Writer.h" #include "Persistence.h" +#include +#include // inclution of the generated files (generated By PersitancePy.xml) #include "PersistencePy.h" @@ -62,7 +64,46 @@ PyObject* PersistencePy::dumpContent(PyObject *args, PyObject *kwds) { return NULL; } - return getPersistencePtr()->dumpToPython(compression); + //setup the stream. the in flag is needed to make "read" work + std::stringstream stream(std::stringstream::out | std::stringstream::in | std::stringstream::binary); + try { + getPersistencePtr()->dumpToStream(stream, compression); + } + catch(...) { + PyErr_SetString(PyExc_IOError, "Unable parse content into binary representation"); + return NULL; + } + + //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) { @@ -70,9 +111,34 @@ 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; + } //check if it really is a buffer - return getPersistencePtr()->restoreFromPython(buffer); + try { + typedef boost::iostreams::basic_array_source Device; + boost::iostreams::stream stream((char*)buf.buf, buf.len); + getPersistencePtr()->restoreFromStream(stream); + } + catch(...) { + PyErr_SetString(PyExc_IOError, "Unable to restore content"); + return NULL; + } + + Py_Return; } PyObject *PersistencePy::getCustomAttributes(const char*) const