// 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 . #include #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 "../Logger/Logger.h" #include "PropertySerialiser.h" PropertySerialiser::PropertySerialiser() { arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_serialisers, Containers::pointer()); arrayAppend(_collectionSerialisers, Containers::pointer()); } auto PropertySerialiser::instance() -> PropertySerialiser& { static PropertySerialiser serialiser; return serialiser; } auto PropertySerialiser::read(BinaryReader& reader) -> UnrealPropertyBase::ptr { if(reader.peekChar() < 0 || reader.eof()) { return nullptr; } Containers::String name; if(!reader.readUEString(name)) { return nullptr; } if(name == "None") { return Containers::pointer(); } Containers::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, Containers::String type, UnsignedLong value_length, Containers::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, Containers::StringView item_type, UnsignedInt count) -> Containers::Array { if(reader.peekChar() < 0 || reader.eof()) { return nullptr; } auto serialiser = getCollectionSerialiser(item_type); Containers::Array array; if(serialiser) { Containers::String name; if(!reader.readUEString(name)) { return nullptr; } Containers::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(Containers::String name, Containers::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) { LOG_ERROR("No property."); return nullptr; } prop->name = std::move(name); prop->propertyType = std::move(type); return prop; } auto PropertySerialiser::serialise(UnrealPropertyBase::ptr& prop, Containers::StringView 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(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(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, Containers::StringView item_type, UnsignedLong& bytes_written, BinaryWriter& writer) -> bool { if(prop->name == "None" && prop->propertyType == "NoneProperty" && dynamic_cast(prop.get())) { bytes_written += writer.writeUEStringToArray(*prop->name); return true; } return serialise(prop, item_type, bytes_written, writer); } auto PropertySerialiser::writeSet(Containers::ArrayView props, Containers::StringView 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(Containers::StringView item_type) -> AbstractUnrealPropertySerialiser* { for(auto& item : _serialisers) { for(auto serialiser_type : item->types()) { if(item_type == serialiser_type) { return item.get(); } } } return nullptr; } auto PropertySerialiser::getCollectionSerialiser(Containers::StringView item_type) -> AbstractUnrealCollectionPropertySerialiser* { for(auto& item : _collectionSerialisers) { for(Containers::StringView serialiser_type : item->types()) { if(item_type == serialiser_type) { return item.get(); } } } return nullptr; }