219 lines
7.0 KiB
C++
219 lines
7.0 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 "../BinaryReader.h"
|
|
#include "../BinaryWriter.h"
|
|
#include "../PropertySerialiser.h"
|
|
|
|
#include "../Types/GenericStructProperty.h"
|
|
#include "../Types/NoneProperty.h"
|
|
|
|
#include "StructSerialiser.h"
|
|
|
|
auto StructSerialiser::types() -> Containers::ArrayView<const std::string> {
|
|
static const Containers::Array<std::string> types{InPlaceInit, {"StructProperty"}};
|
|
return types;
|
|
}
|
|
|
|
auto StructSerialiser::deserialise(const std::string& name, const std::string& type, UnsignedLong value_length,
|
|
UnsignedInt count, BinaryReader& reader, PropertySerialiser& serialiser) -> Containers::Array<UnrealPropertyBase::ptr>
|
|
{
|
|
std::string item_type;
|
|
if(!reader.readUEString(item_type)) {
|
|
return nullptr;
|
|
}
|
|
|
|
Containers::StaticArray<16, char> guid{ValueInit};
|
|
if(!reader.readStaticArray(guid)) {
|
|
return nullptr;
|
|
}
|
|
|
|
char terminator;
|
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
|
return nullptr;
|
|
}
|
|
|
|
Containers::Array<UnrealPropertyBase::ptr> array;
|
|
|
|
if(count == 0) {
|
|
auto prop = Containers::pointer<GenericStructProperty>();
|
|
prop->structType = std::move(item_type);
|
|
prop->structGuid = std::move(guid);
|
|
}
|
|
else {
|
|
for(UnsignedInt i = 0; i < count; i++) {
|
|
auto prop = Containers::pointer<UnrealPropertyBase>();
|
|
|
|
prop = serialiser.readItem(reader, item_type, UnsignedLong(-1), name);
|
|
|
|
if(!prop) {
|
|
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
|
}
|
|
|
|
if(!prop) {
|
|
return nullptr;
|
|
}
|
|
|
|
static_cast<StructProperty*>(prop.get())->structGuid = guid;
|
|
|
|
arrayAppend(array, std::move(prop));
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
auto StructSerialiser::deserialise(const std::string& name, const std::string& type, UnsignedLong value_length,
|
|
BinaryReader& reader, PropertySerialiser& serialiser) -> UnrealPropertyBase::ptr
|
|
{
|
|
std::string item_type;
|
|
if(!reader.readUEString(item_type)) {
|
|
return nullptr;
|
|
}
|
|
|
|
if(item_type == "None") {
|
|
return Containers::pointer<NoneProperty>();
|
|
}
|
|
|
|
Containers::StaticArray<16, char> guid{ValueInit};
|
|
if(!reader.readStaticArray(guid)) {
|
|
return nullptr;
|
|
}
|
|
|
|
char terminator;
|
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
|
return nullptr;
|
|
}
|
|
|
|
UnrealPropertyBase::ptr prop = serialiser.readItem(reader, item_type, value_length, name);
|
|
|
|
if(!prop) {
|
|
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
|
if(prop) {
|
|
dynamic_cast<GenericStructProperty*>(prop.get())->structGuid = std::move(guid);
|
|
}
|
|
}
|
|
|
|
return prop;
|
|
}
|
|
|
|
auto StructSerialiser::serialise(Containers::ArrayView<UnrealPropertyBase::ptr> props, const std::string& item_type,
|
|
UnsignedLong& bytes_written, BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
|
{
|
|
bytes_written += writer.writeUEStringToArray(*(props.front()->name));
|
|
bytes_written += writer.writeUEStringToArray(item_type);
|
|
UnsignedLong vl_pos = writer.arrayPosition();
|
|
bytes_written += writer.writeValueToArray<UnsignedLong>(0ull);
|
|
|
|
auto struct_prop = dynamic_cast<StructProperty*>(props.front().get());
|
|
if(!struct_prop) {
|
|
return false;
|
|
}
|
|
|
|
bytes_written += writer.writeUEStringToArray(struct_prop->structType);
|
|
bytes_written += writer.writeDataToArray(arrayView(struct_prop->structGuid));
|
|
bytes_written += writer.writeValueToArray<char>('\0');
|
|
|
|
UnsignedLong vl_start = writer.arrayPosition();
|
|
|
|
UnsignedLong bytes_written_here = 0;
|
|
for(auto& prop : props) {
|
|
struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
|
|
|
if(!struct_prop) {
|
|
return false;
|
|
}
|
|
|
|
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written_here, writer)) {
|
|
if(!writeStructValue(struct_prop, bytes_written_here, writer, serialiser)) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
UnsignedLong vl_stop = writer.arrayPosition() - vl_start;
|
|
writer.writeValueToArrayAt(vl_stop, vl_pos);
|
|
bytes_written += vl_stop;
|
|
|
|
return true;
|
|
}
|
|
|
|
auto StructSerialiser::serialise(UnrealPropertyBase::ptr& prop, UnsignedLong& bytes_written,
|
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
|
{
|
|
auto struct_prop = dynamic_cast<StructProperty*>(prop.get());
|
|
|
|
if(!struct_prop) {
|
|
return false;
|
|
}
|
|
|
|
writer.writeUEStringToArray(struct_prop->structType);
|
|
writer.writeDataToArray(arrayView(struct_prop->structGuid));
|
|
writer.writeValueToArray<char>('\0');
|
|
|
|
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written, writer)) {
|
|
UnsignedLong dummy_bytes_written = 0;
|
|
UnsignedLong vl_start = writer.arrayPosition();
|
|
if(!writeStructValue(struct_prop, dummy_bytes_written, writer, serialiser)) {
|
|
return false;
|
|
}
|
|
bytes_written += writer.arrayPosition() - vl_start;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
auto StructSerialiser::readStructValue(const std::string& name, const std::string& type, UnsignedLong value_length,
|
|
BinaryReader& reader, PropertySerialiser& serialiser) -> StructProperty::ptr
|
|
{
|
|
auto st_prop = Containers::pointer<GenericStructProperty>();
|
|
st_prop->structType = type;
|
|
|
|
UnrealPropertyBase::ptr prop;
|
|
while((prop = serialiser.read(reader)) != nullptr) {
|
|
arrayAppend(st_prop->properties, std::move(prop));
|
|
|
|
if(st_prop->properties.back()->name == "None" &&
|
|
st_prop->properties.back()->propertyType == "NoneProperty" &&
|
|
dynamic_cast<NoneProperty*>(st_prop->properties.back().get()) != nullptr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
st_prop->name.emplace(name);
|
|
|
|
return st_prop;
|
|
}
|
|
|
|
auto StructSerialiser::writeStructValue(StructProperty* prop, UnsignedLong& bytes_written,
|
|
BinaryWriter& writer, PropertySerialiser& serialiser) -> bool
|
|
{
|
|
auto struct_prop = dynamic_cast<GenericStructProperty*>(prop);
|
|
|
|
if(!struct_prop) {
|
|
return false;
|
|
}
|
|
|
|
for(auto& item : struct_prop->properties) {
|
|
if(!serialiser.write(item, bytes_written, writer)) {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|