253 lines
8.6 KiB
C++
253 lines
8.6 KiB
C++
|
// MassBuilderSaveTool
|
||
|
// Copyright (C) 2021 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/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<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, -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;
|
||
|
}
|