MassBuilderSaveTool/src/UESaveFile/PropertySerialiser.cpp

255 lines
8.7 KiB
C++

// MassBuilderSaveTool
// Copyright (C) 2021-2022 Guillaume Jacquemin
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
#include <algorithm>
#include "Serialisers/ArrayPropertySerialiser.h"
#include "Serialisers/BoolPropertySerialiser.h"
#include "Serialisers/BytePropertySerialiser.h"
#include "Serialisers/ColourPropertySerialiser.h"
#include "Serialisers/DateTimePropertySerialiser.h"
#include "Serialisers/EnumPropertySerialiser.h"
#include "Serialisers/FloatPropertySerialiser.h"
#include "Serialisers/GuidPropertySerialiser.h"
#include "Serialisers/IntPropertySerialiser.h"
#include "Serialisers/MapPropertySerialiser.h"
#include "Serialisers/ResourcePropertySerialiser.h"
#include "Serialisers/RotatorPropertySerialiser.h"
#include "Serialisers/StringPropertySerialiser.h"
#include "Serialisers/SetPropertySerialiser.h"
#include "Serialisers/StructSerialiser.h"
#include "Serialisers/TextPropertySerialiser.h"
#include "Serialisers/VectorPropertySerialiser.h"
#include "Serialisers/Vector2DPropertySerialiser.h"
#include "Types/NoneProperty.h"
#include "BinaryReader.h"
#include "BinaryWriter.h"
#include "PropertySerialiser.h"
PropertySerialiser::PropertySerialiser() {
arrayAppend(_serialisers, Containers::pointer<ArrayPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<BoolPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<BytePropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<ColourPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<DateTimePropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<EnumPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<FloatPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<GuidPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<IntPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<MapPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<ResourcePropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<RotatorPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<StringPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<SetPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<TextPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<VectorPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<Vector2DPropertySerialiser>());
arrayAppend(_serialisers, Containers::pointer<StructSerialiser>());
arrayAppend(_collectionSerialisers, Containers::pointer<StructSerialiser>());
}
auto PropertySerialiser::read(BinaryReader& reader) -> UnrealPropertyBase::ptr {
if(reader.peekChar() < 0 || reader.eof()) {
return nullptr;
}
std::string name;
if(!reader.readUEString(name)) {
return nullptr;
}
if(name == "None") {
return Containers::pointer<NoneProperty>();
}
std::string type;
if(!reader.readUEString(type)) {
return nullptr;
}
UnsignedLong value_length;
if(!reader.readUnsignedLong(value_length)) {
return nullptr;
}
return deserialise(std::move(name), std::move(type), value_length, reader);
}
auto PropertySerialiser::readItem(BinaryReader& reader, std::string type, UnsignedLong value_length, std::string name) -> UnrealPropertyBase::ptr {
if(reader.peekChar() < 0 || reader.eof()) {
return nullptr;
}
return deserialise(std::move(name), std::move(type), value_length, reader);
}
auto PropertySerialiser::readSet(BinaryReader& reader, const std::string& item_type, UnsignedInt count) -> Containers::Array<UnrealPropertyBase::ptr> {
if(reader.peekChar() < 0 || reader.eof()) {
return nullptr;
}
auto serialiser = getCollectionSerialiser(item_type);
Containers::Array<UnrealPropertyBase::ptr> array;
if(serialiser) {
std::string name;
if(!reader.readUEString(name)) {
return nullptr;
}
std::string type;
if(!reader.readUEString(type)) {
return nullptr;
}
UnsignedLong value_length;
if(!reader.readUnsignedLong(value_length)) {
return nullptr;
}
array = serialiser->deserialise(name, type, value_length, count, reader, *this);
for(auto& item : array) {
if(item->name == Containers::NullOpt) {
item->name.emplace(name);
}
}
}
else {
for(UnsignedInt i = 0; i < count; i++) {
auto item = readItem(reader, item_type, UnsignedLong(-1), "");
arrayAppend(array, std::move(item));
}
}
return array;
}
auto PropertySerialiser::deserialise(std::string name, std::string type, UnsignedLong value_length,
BinaryReader& reader) -> UnrealPropertyBase::ptr
{
UnrealPropertyBase::ptr prop;
auto serialiser = getSerialiser(type);
if(serialiser == nullptr) {
return nullptr;
}
prop = serialiser->deserialise(name, type, value_length, reader, *this);
if(!prop) {
!Utility::Error{} << "No prop in" << __func__;
return nullptr;
}
prop->name = std::move(name);
prop->propertyType = std::move(type);
return prop;
}
auto PropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, const std::string& item_type, UnsignedLong& bytes_written,
BinaryWriter& writer) -> bool
{
auto serialiser = getSerialiser(item_type);
if(!serialiser) {
return false;
}
return serialiser->serialise(prop, bytes_written, writer, *this);
}
auto PropertySerialiser::write(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool {
if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast<NoneProperty*>(prop.get())) {
bytes_written += writer.writeUEStringToArray(*prop->name);
return true;
}
bytes_written += writer.writeUEStringToArray(*prop->name);
bytes_written += writer.writeUEStringToArray(prop->propertyType);
UnsignedLong value_length = 0;
UnsignedLong vl_position = writer.arrayPosition();
bytes_written += writer.writeValueToArray<UnsignedLong>(value_length);
bool ret = serialise(prop, prop->propertyType, value_length, writer);
writer.writeValueToArrayAt(value_length, vl_position);
bytes_written += value_length;
return ret;
}
auto PropertySerialiser::writeItem(UnrealPropertyBase::ptr& prop, const std::string& item_type,
UnsignedLong& bytes_written, BinaryWriter& writer) -> bool
{
if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast<NoneProperty*>(prop.get())) {
bytes_written += writer.writeUEStringToArray(*prop->name);
return true;
}
return serialise(prop, item_type, bytes_written, writer);
}
auto PropertySerialiser::writeSet(Containers::ArrayView<UnrealPropertyBase::ptr> props, const std::string& item_type,
UnsignedLong& bytes_written, BinaryWriter& writer) -> bool
{
auto serialiser = getCollectionSerialiser(item_type);
if(serialiser) {
return serialiser->serialise(props, item_type, bytes_written, writer, *this);
}
else {
for(auto& prop : props) {
if(!writeItem(prop, item_type, bytes_written, writer)) {
return false;
}
}
return true;
}
}
auto PropertySerialiser::getSerialiser(const std::string& item_type) -> AbstractUnrealPropertySerialiser* {
for(auto& item : _serialisers) {
for(const std::string& serialiser_type : item->types()) {
if(item_type == serialiser_type) {
return item.get();
}
}
}
return nullptr;
}
auto PropertySerialiser::getCollectionSerialiser(const std::string& item_type) -> AbstractUnrealCollectionPropertySerialiser* {
for(auto& item : _collectionSerialisers) {
for(const std::string& serialiser_type : item->types()) {
if(item_type == serialiser_type) {
return item.get();
}
}
}
return nullptr;
}