349 lines
13 KiB
C++
349 lines
13 KiB
C++
#include "serializationmanager.h"
|
|
#include "serializable.h"
|
|
#include <sstream>
|
|
|
|
void ObjectSaver::addObject(Serializable *object)
|
|
{
|
|
if(object == nullptr)
|
|
return;
|
|
const std::string &type = object->getType();
|
|
ObjectType &objectsOfSameType = m_objects[type];
|
|
if(objectsOfSameType.count(object) == 0)
|
|
{
|
|
int n = objectsOfSameType.size();
|
|
objectsOfSameType[object] = n;
|
|
PropertySet *properties = object->getProperties();
|
|
for(AbstractProperty* p : *properties)
|
|
{
|
|
if(p->getPropertyType() == AbstractProperty::REFERENCE)
|
|
addObject(((Property<Serializable*>*)p)->getValueRef());
|
|
else if(p->getPropertyType() == AbstractProperty::ARRAY && ((AbstractArrayProperty*)p)->getDataType() == AbstractProperty::REFERENCE)
|
|
{
|
|
std::vector<Serializable*> &vecRef = ((ArrayProperty<Serializable*>*)p)->getValueRef();
|
|
for(Serializable *ref : vecRef)
|
|
addObject(ref);
|
|
}
|
|
}
|
|
delete properties;
|
|
}
|
|
}
|
|
|
|
std::ostream& ObjectSaver::saveBinary(std::ostream& os)
|
|
{
|
|
// loop on serializable types
|
|
Property<int>(m_objects.size()).saveBinary(os); // amount of types
|
|
for(const std::pair<std::string, ObjectType> &type : m_objects)
|
|
{
|
|
// serialize type
|
|
Property<std::string>(type.first).saveBinary(os); // type name
|
|
Property<int>(type.second.size()).saveBinary(os); // amount of objects of this type
|
|
|
|
// order the objects
|
|
std::vector<Serializable*> orderedObjects(type.second.size());
|
|
for(const std::pair<Serializable*, int> &entry : type.second)
|
|
orderedObjects[entry.second] = entry.first;
|
|
|
|
// serialize objects of this type
|
|
for(Serializable* object : orderedObjects)
|
|
{
|
|
PropertySet *properties = object->getProperties();
|
|
for(AbstractProperty *p : *properties)
|
|
{
|
|
if(p->getPropertyType() == AbstractProperty::REFERENCE)
|
|
{
|
|
Serializable *ref = ((Property<Serializable*>*)p)->getValueRef();
|
|
if(ref == nullptr)
|
|
Property<std::string>("null").saveBinary(os);
|
|
else
|
|
{
|
|
Property<std::string>(ref->getType()).saveBinary(os); // type name
|
|
Property<int>(m_objects[ref->getType()][ref]).saveBinary(os); // id of the object
|
|
}
|
|
}
|
|
else if(p->getPropertyType() == AbstractProperty::ARRAY && ((AbstractArrayProperty*)p)->getDataType() == AbstractProperty::REFERENCE)
|
|
{
|
|
std::vector<Serializable*> &vecRef = ((ArrayProperty<Serializable*>*)p)->getValueRef();
|
|
Property<int>(vecRef.size()).saveBinary(os); // amount of references
|
|
for(Serializable *ref : vecRef)
|
|
{
|
|
if(ref == nullptr)
|
|
Property<std::string>("null").saveBinary(os);
|
|
else
|
|
{
|
|
Property<std::string>(ref->getType()).saveBinary(os); // type name
|
|
Property<int>(m_objects[ref->getType()][ref]).saveBinary(os); // id of the object
|
|
}
|
|
}
|
|
}
|
|
else
|
|
p->saveBinary(os);
|
|
}
|
|
delete properties;
|
|
}
|
|
}
|
|
return os;
|
|
}
|
|
|
|
std::ostream& ObjectSaver::saveAscii(std::ostream& os)
|
|
{
|
|
os << "{" << std::endl;
|
|
// loop on serializable types
|
|
for(const std::pair<std::string, ObjectType> &type : m_objects)
|
|
{
|
|
// serialize type
|
|
os << "\t\"" << type.first << "\": [" << std::endl;
|
|
|
|
// order the objects
|
|
std::vector<Serializable*> orderedObjects(type.second.size());
|
|
for(const std::pair<Serializable*, int> &entry : type.second)
|
|
orderedObjects[entry.second] = entry.first;
|
|
|
|
// serialize objects of this type
|
|
for(Serializable* object : orderedObjects)
|
|
{
|
|
os << "\t\t{" << std::endl;
|
|
PropertySet *properties = object->getProperties();
|
|
for(AbstractProperty *p : *properties)
|
|
{
|
|
os << "\t\t\t";
|
|
if(p->getPropertyType() == AbstractProperty::REFERENCE)
|
|
{
|
|
Serializable *ref = ((Property<Serializable*>*)p)->getValueRef();
|
|
if(ref == nullptr)
|
|
os << "\"null\"";
|
|
else
|
|
os << "{\"" << ref->getType() << "\", " << (m_objects[ref->getType()][ref]) << "}";
|
|
}
|
|
else if(p->getPropertyType() == AbstractProperty::ARRAY && ((AbstractArrayProperty*)p)->getDataType() == AbstractProperty::REFERENCE)
|
|
{
|
|
std::vector<Serializable*> &vecRef = ((ArrayProperty<Serializable*>*)p)->getValueRef();
|
|
os << "[";
|
|
int i = vecRef.size();
|
|
for(Serializable *ref : vecRef)
|
|
{
|
|
if(ref == nullptr)
|
|
os << "\"null\"";
|
|
else
|
|
os << "{\"" << ref->getType() << "\", " << (m_objects[ref->getType()][ref]) << "}";
|
|
if(--i) os << ", ";
|
|
}
|
|
os << "]";
|
|
}
|
|
else
|
|
p->saveAscii(os);
|
|
|
|
if(properties->back() == p)
|
|
os << std::endl;
|
|
else
|
|
os << "," << std::endl;
|
|
}
|
|
delete properties;
|
|
os << "\t\t}";
|
|
if(orderedObjects.back() == object)
|
|
os << std::endl;
|
|
else
|
|
os << "," << std::endl;
|
|
}
|
|
os << "\t]" << std::endl;
|
|
}
|
|
return os << "}" << std::endl;
|
|
}
|
|
|
|
std::istream& ObjectLoader::loadBinary(std::istream& is)
|
|
{
|
|
Property<int> nbTypes;
|
|
nbTypes.loadBinary(is); // get amount of types to read
|
|
for(int i=0; i<nbTypes.getValueRef(); ++i) // loop on these types
|
|
{
|
|
Property<std::string> typeName;
|
|
typeName.loadBinary(is); // get the type name
|
|
Serializable::Instancer instancer = Serializable::getInstancer(typeName.getValueRef());
|
|
Property<int> nbObjects;
|
|
nbObjects.loadBinary(is); // get the amount of objects of that type
|
|
std::vector<Serializable*> &objectsOfThatType = m_objects[typeName.getValueRef()];
|
|
for(int j=0; j<nbObjects.getValueRef(); ++j) // loop on these objects
|
|
{
|
|
Serializable* object = instancer();
|
|
objectsOfThatType.push_back(object);
|
|
PropertySet* properties = object->getProperties();
|
|
for(AbstractProperty* p : *properties)
|
|
{
|
|
if(p->getPropertyType() == AbstractProperty::REFERENCE)
|
|
{
|
|
Property<std::string> type; // type name
|
|
type.loadBinary(is);
|
|
if(type.getValueRef().compare("null") != 0)
|
|
{
|
|
Property<int> id; // id of the object
|
|
id.loadBinary(is);
|
|
PendingReference ref;
|
|
ref.ptr = &(((Property<Serializable*>*)p)->getValueRef());
|
|
ref.type = type.getValueRef();
|
|
ref.id = id.getValueRef();
|
|
m_references.push_back(ref);
|
|
}
|
|
else
|
|
((Property<Serializable*>*)p)->getValueRef() = nullptr;
|
|
}
|
|
else if(p->getPropertyType() == AbstractProperty::ARRAY && ((AbstractArrayProperty*)p)->getDataType() == AbstractProperty::REFERENCE)
|
|
{
|
|
Property<int> nbRef; // amount of references in the array
|
|
nbRef.loadBinary(is);
|
|
std::vector<Serializable*> &vecRef = ((ArrayProperty<Serializable*>*)p)->getValueRef();
|
|
vecRef = std::vector<Serializable*>(nbRef.getValueRef(), nullptr);
|
|
for(Serializable* &it : vecRef)
|
|
{
|
|
Property<std::string> type; // type name
|
|
type.loadBinary(is);
|
|
if(type.getValueRef().compare("null") != 0)
|
|
{
|
|
Property<int> id; // id of the object
|
|
id.loadBinary(is);
|
|
PendingReference ref;
|
|
ref.ptr = ⁢
|
|
ref.type = type.getValueRef();
|
|
ref.id = id.getValueRef();
|
|
m_references.push_back(ref);
|
|
}
|
|
}
|
|
}
|
|
else
|
|
p->loadBinary(is);
|
|
}
|
|
delete properties;
|
|
}
|
|
}
|
|
buildReferences();
|
|
return is;
|
|
}
|
|
|
|
std::istream& ObjectLoader::loadAscii(std::istream& is)
|
|
{
|
|
// get trimmed version of the stream into a stringstream
|
|
while(is.get() != '{'); // got to first opening brace
|
|
int nbBraces = 1;
|
|
bool inString = false;
|
|
std::stringstream ss;
|
|
while(nbBraces > 0) // read and trim until we find the corresponding closing brace
|
|
{
|
|
int c = is.get();
|
|
switch(c)
|
|
{
|
|
case '{':
|
|
++nbBraces;
|
|
ss.put(c);
|
|
break;
|
|
case '}':
|
|
--nbBraces;
|
|
ss.put(c);
|
|
break;
|
|
case '\\':
|
|
if(is.peek() == '"')
|
|
inString = !inString;
|
|
ss.put(c);
|
|
break;
|
|
case '"':
|
|
inString = !inString;
|
|
ss.put(c);
|
|
break;
|
|
case ' ':
|
|
if(inString)
|
|
ss.put(c);
|
|
case '\n':
|
|
case '\t':
|
|
case '\r':
|
|
break;
|
|
default:
|
|
ss.put(c);
|
|
}
|
|
}
|
|
|
|
// begin parsing
|
|
while(ss.peek() != '}') // loop on serializable types
|
|
{
|
|
Property<std::string> typeName;
|
|
typeName.loadAscii(ss);
|
|
Serializable::Instancer instancer = Serializable::getInstancer(typeName.getValueRef());
|
|
std::vector<Serializable*> &objectsOfThatType = m_objects[typeName.getValueRef()];
|
|
ss.ignore(2); // :[
|
|
while(ss.peek() != ']') // loop on the objects of that type
|
|
{
|
|
ss.ignore(1); // {
|
|
Serializable* object = instancer();
|
|
objectsOfThatType.push_back(object);
|
|
PropertySet* properties = object->getProperties();
|
|
for(AbstractProperty* p : *properties)
|
|
{
|
|
if(p->getPropertyType() == AbstractProperty::REFERENCE)
|
|
{
|
|
if(ss.peek() == '{')
|
|
{
|
|
ss.ignore(1); // {
|
|
Property<std::string> type; // type name
|
|
type.loadAscii(ss);
|
|
ss.ignore(1); // ,
|
|
Property<int> id; // id of the object
|
|
id.loadAscii(ss);
|
|
ss.ignore(1);
|
|
PendingReference ref;
|
|
ref.ptr = &(((Property<Serializable*>*)p)->getValueRef());
|
|
ref.type = type.getValueRef();
|
|
ref.id = id.getValueRef();
|
|
m_references.push_back(ref);
|
|
ss.ignore(1); // }
|
|
}
|
|
else
|
|
{
|
|
ss.ignore(6); // "null"
|
|
((Property<Serializable*>*)p)->getValueRef() = nullptr;
|
|
}
|
|
}
|
|
else if(p->getPropertyType() == AbstractProperty::ARRAY && ((AbstractArrayProperty*)p)->getDataType() == AbstractProperty::REFERENCE)
|
|
{
|
|
std::vector<Serializable*> &vecRef = ((ArrayProperty<Serializable*>*)p)->getValueRef();
|
|
ss.ignore(1); // [
|
|
while(ss.peek() != ']')
|
|
{
|
|
vecRef.push_back(nullptr);
|
|
if(ss.peek() == '{')
|
|
{
|
|
ss.ignore(1); // {
|
|
Property<std::string> type; // type name
|
|
type.loadAscii(ss);
|
|
ss.ignore(1); // ,
|
|
Property<int> id; // id of the object
|
|
id.loadAscii(ss);
|
|
ss.ignore(1); // }
|
|
PendingReference ref;
|
|
ref.ptr = &(vecRef.back());
|
|
ref.type = type.getValueRef();
|
|
ref.id = id.getValueRef();
|
|
m_references.push_back(ref);
|
|
}
|
|
else
|
|
ss.ignore(6); // "null"
|
|
if(ss.peek() != ',')
|
|
ss.ignore(1); // ,
|
|
}
|
|
ss.ignore(1); // ]
|
|
}
|
|
else
|
|
p->loadAscii(ss);
|
|
if(p != properties->back())
|
|
ss.ignore(1); // ,
|
|
}
|
|
ss.ignore(1); // }
|
|
}
|
|
ss.ignore(1); // ]
|
|
}
|
|
buildReferences();
|
|
return is;
|
|
}
|
|
|
|
void ObjectLoader::buildReferences()
|
|
{
|
|
for(PendingReference &ref : m_references)
|
|
*(ref.ptr) = m_objects[ref.type][ref.id];
|
|
m_references.clear();
|
|
}
|