246 lines
8.0 KiB
C++
246 lines
8.0 KiB
C++
// MassBuilderSaveTool
|
|
// Copyright (C) 2021-2024 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 <Corrade/Containers/String.h>
|
|
|
|
#include "../../BinaryIo/Reader.h"
|
|
#include "../../BinaryIo/Writer.h"
|
|
#include "../PropertySerialiser.h"
|
|
#include "../Types/GenericStructProperty.h"
|
|
#include "../Types/NoneProperty.h"
|
|
#include "../../Logger/Logger.h"
|
|
|
|
#include "Struct.h"
|
|
|
|
namespace Gvas { namespace Serialisers {
|
|
|
|
StringArrayView
|
|
Struct::types() {
|
|
using namespace Containers::Literals;
|
|
static const Containers::Array<Containers::String> types{InPlaceInit, {"StructProperty"_s}};
|
|
return types;
|
|
}
|
|
|
|
PropertyArray
|
|
Struct::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
|
std::uint32_t count, BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
|
{
|
|
Containers::String item_type;
|
|
if(!reader.readUEString(item_type)) {
|
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s item type.", name);
|
|
return nullptr;
|
|
}
|
|
|
|
Containers::StaticArray<16, char> guid{ValueInit};
|
|
if(!reader.readStaticArray(guid)) {
|
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s GUID.", name);
|
|
return nullptr;
|
|
}
|
|
|
|
char terminator;
|
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
|
LOG_ERROR_FORMAT("Couldn't read a null byte in struct property {}.", name);
|
|
return nullptr;
|
|
}
|
|
|
|
Containers::Array<Types::UnrealPropertyBase::ptr> array;
|
|
|
|
if(count == 0) {
|
|
auto prop = Containers::pointer<Types::GenericStructProperty>();
|
|
prop->structType = Utility::move(item_type);
|
|
prop->structGuid = guid;
|
|
}
|
|
else {
|
|
for(std::uint32_t i = 0; i < count; i++) {
|
|
auto prop = Containers::pointer<Types::UnrealPropertyBase>();
|
|
|
|
prop = serialiser.readItem(reader, item_type, std::size_t(-1), name);
|
|
|
|
if(!prop) {
|
|
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
|
}
|
|
|
|
if(!prop) {
|
|
LOG_ERROR("Invalid property");
|
|
return nullptr;
|
|
}
|
|
|
|
dynamic_cast<Types::StructProperty*>(prop.get())->structGuid = guid;
|
|
|
|
arrayAppend(array, Utility::move(prop));
|
|
}
|
|
}
|
|
|
|
return array;
|
|
}
|
|
|
|
Types::UnrealPropertyBase::ptr
|
|
Struct::deserialise(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
|
{
|
|
Containers::String item_type;
|
|
if(!reader.readUEString(item_type)) {
|
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s item type.", name);
|
|
return nullptr;
|
|
}
|
|
|
|
if(item_type == "None") {
|
|
return Containers::pointer<Types::NoneProperty>();
|
|
}
|
|
|
|
Containers::StaticArray<16, char> guid{ValueInit};
|
|
if(!reader.readStaticArray(guid)) {
|
|
LOG_ERROR_FORMAT("Couldn't read struct property {}'s GUID.", name);
|
|
return nullptr;
|
|
}
|
|
|
|
char terminator;
|
|
if(!reader.readChar(terminator) || terminator != '\0') {
|
|
LOG_ERROR_FORMAT("Couldn't read a null byte in byte property {}.", name);
|
|
return nullptr;
|
|
}
|
|
|
|
auto prop = serialiser.readItem(reader, item_type, value_length, name);
|
|
|
|
if(!prop) {
|
|
prop = readStructValue(name, item_type, value_length, reader, serialiser);
|
|
if(prop) {
|
|
dynamic_cast<Types::GenericStructProperty*>(prop.get())->structGuid = guid;
|
|
}
|
|
}
|
|
|
|
return prop;
|
|
}
|
|
|
|
bool
|
|
Struct::serialise(PropertyArrayView props, Containers::StringView item_type, std::size_t& bytes_written,
|
|
BinaryIo::Writer& writer, PropertySerialiser& serialiser)
|
|
{
|
|
bytes_written += writer.writeUEStringToArray(*(props.front()->name));
|
|
bytes_written += writer.writeUEStringToArray(item_type);
|
|
std::size_t vl_pos = writer.arrayPosition();
|
|
bytes_written += writer.writeValueToArray<std::size_t>(0ull);
|
|
|
|
auto struct_prop = dynamic_cast<Types::StructProperty*>(props.front().get());
|
|
if(!struct_prop) {
|
|
LOG_ERROR("The property is not a valid struct property.");
|
|
return false;
|
|
}
|
|
|
|
bytes_written += writer.writeUEStringToArray(struct_prop->structType);
|
|
bytes_written += writer.writeDataToArray(arrayView(struct_prop->structGuid));
|
|
bytes_written += writer.writeValueToArray<char>('\0');
|
|
|
|
std::size_t vl_start = writer.arrayPosition();
|
|
|
|
std::size_t bytes_written_here = 0;
|
|
for(auto& prop : props) {
|
|
struct_prop = dynamic_cast<Types::StructProperty*>(prop.get());
|
|
if(!struct_prop) {
|
|
LOG_ERROR("The property is not a valid struct property.");
|
|
return false;
|
|
}
|
|
|
|
if(!serialiser.writeItem(prop, struct_prop->structType, bytes_written_here, writer)) {
|
|
if(!writeStructValue(struct_prop, bytes_written_here, writer, serialiser)) {
|
|
LOG_ERROR("Couldn't write the struct value.");
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
|
|
std::size_t vl_stop = writer.arrayPosition() - vl_start;
|
|
writer.writeValueToArrayAt(vl_stop, vl_pos);
|
|
bytes_written += vl_stop;
|
|
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
Struct::serialise(Types::UnrealPropertyBase::ptr& prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
|
PropertySerialiser& serialiser)
|
|
{
|
|
auto struct_prop = dynamic_cast<Types::StructProperty*>(prop.get());
|
|
if(!struct_prop) {
|
|
LOG_ERROR("The property is not a valid struct property.");
|
|
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)) {
|
|
std::size_t dummy_bytes_written = 0;
|
|
std::size_t vl_start = writer.arrayPosition();
|
|
if(!writeStructValue(struct_prop, dummy_bytes_written, writer, serialiser)) {
|
|
LOG_ERROR("Couldn't write the struct value.");
|
|
return false;
|
|
}
|
|
bytes_written += writer.arrayPosition() - vl_start;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
Types::StructProperty::ptr
|
|
Struct::readStructValue(Containers::StringView name, Containers::StringView type, std::size_t value_length,
|
|
BinaryIo::Reader& reader, PropertySerialiser& serialiser)
|
|
{
|
|
static_cast<void>(value_length);
|
|
|
|
auto st_prop = Containers::pointer<Types::GenericStructProperty>();
|
|
st_prop->structType = type;
|
|
|
|
Types::UnrealPropertyBase::ptr prop;
|
|
while((prop = serialiser.read(reader)) != nullptr) {
|
|
arrayAppend(st_prop->properties, Utility::move(prop));
|
|
|
|
if(st_prop->properties.back()->name == "None" &&
|
|
st_prop->properties.back()->propertyType == "NoneProperty" &&
|
|
dynamic_cast<Types::NoneProperty*>(st_prop->properties.back().get()) != nullptr)
|
|
{
|
|
break;
|
|
}
|
|
}
|
|
|
|
st_prop->name.emplace(name);
|
|
|
|
return st_prop;
|
|
}
|
|
|
|
bool
|
|
Struct::writeStructValue(Types::StructProperty* prop, std::size_t& bytes_written, BinaryIo::Writer& writer,
|
|
PropertySerialiser& serialiser)
|
|
{
|
|
auto struct_prop = dynamic_cast<Types::GenericStructProperty*>(prop);
|
|
if(!struct_prop) {
|
|
LOG_ERROR("The property is not a valid struct property.");
|
|
return false;
|
|
}
|
|
|
|
for(auto& item : struct_prop->properties) {
|
|
if(!serialiser.write(item, bytes_written, writer)) {
|
|
LOG_ERROR("Couldn't write the struct's data.");
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
}}
|