Persistence: Enable binary dumps of properties

This commit is contained in:
ickby
2018-10-17 07:01:38 +02:00
committed by wmayer
parent 9820fca6a5
commit 59283c40b8
5 changed files with 163 additions and 88 deletions

View File

@@ -57,6 +57,23 @@ If the list contains 'Hidden' then the item even doesn't appear in the property
<UserDocu>Return the documentation string of the property of this class.</UserDocu>
</Documentation>
</Methode>
<Methode Name="dumpPropertyContent" Keyword="true" Const="true">
<Documentation>
<UserDocu>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)
</UserDocu>
</Documentation>
</Methode>
<Methode Name="restorePropertyContent">
<Documentation>
<UserDocu>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
</UserDocu>
</Documentation>
</Methode>
<Attribute Name="PropertiesList" ReadOnly="true">
<Documentation>
<UserDocu>A list of all property names</UserDocu>

View File

@@ -226,6 +226,42 @@ Py::List PropertyContainerPy::getPropertiesList(void) const
return ret;
}
PyObject* PropertyContainerPy::dumpPropertyContent(PyObject *args, PyObject *kwds) {
int compression = 3;
char* property;
static char* kwds_def[] = {"Compression",NULL};
PyErr_Clear();
if (!PyArg_ParseTupleAndKeywords(args, kwds, "s|i", kwds_def, &property, &compression)) {
return NULL;
}
Property* prop = getPropertyContainerPtr()->getPropertyByName(property);
if (!prop) {
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", property);
return 0;
}
return prop->dumpToPython(compression);
}
PyObject* PropertyContainerPy::restorePropertyContent(PyObject *args) {
PyObject* buffer;
char* property;
if( !PyArg_ParseTuple(args, "sO", &property, &buffer) )
return NULL;
Property* prop = getPropertyContainerPtr()->getPropertyByName(property);
if (!prop) {
PyErr_Format(PyExc_AttributeError, "Property container has no property '%s'", property);
return 0;
}
return prop->restoreFromPython(buffer);
}
PyObject *PropertyContainerPy::getCustomAttributes(const char* attr) const
{
// search in PropertyList

View File

@@ -22,6 +22,9 @@
#include "PreCompiled.h"
#include "Writer.h"
#include "Reader.h"
#include "PyObjectBase.h"
#ifndef _PreComp_
#endif
@@ -95,3 +98,102 @@ 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);
//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 (we need to encapsulte it with xml tags to be able to read single element xmls like happen for properties)
writer.Stream() << "<Content>" << std::endl;
Save(writer);
writer.Stream() << "</Content>";
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) {
//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;
}
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;
}

View File

@@ -148,6 +148,12 @@ public:
virtual void RestoreDocFile(Reader &/*reader*/);
/// 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);
//restore the persistence data from a python data structure that supports the buffer protocol
PyObject* restoreFromPython(PyObject*);
};
} //namespace Base

View File

@@ -23,7 +23,6 @@
#include "PreCompiled.h"
#include "Writer.h"
#include "Reader.h"
#include "Persistence.h"
// inclution of the generated files (generated By PersitancePy.xml)
@@ -63,53 +62,7 @@ PyObject* PersistencePy::dumpContent(PyObject *args, PyObject *kwds) {
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;
return getPersistencePtr()->dumpToPython(compression);
}
PyObject* PersistencePy::restoreContent(PyObject *args) {
@@ -119,46 +72,7 @@ PyObject* PersistencePy::restoreContent(PyObject *args) {
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;
return getPersistencePtr()->restoreFromPython(buffer);
}
PyObject *PersistencePy::getCustomAttributes(const char*) const