MetaCore/Source/MetaCoreFoundation/Private/MetaCorePackage.cpp

151 lines
6.6 KiB
C++

#include "MetaCoreFoundation/MetaCorePackage.h"
#include <fstream>
namespace MetaCore {
namespace {
[[nodiscard]] std::optional<std::vector<std::byte>> MetaCoreReadAllBytes(const std::filesystem::path& path) {
std::ifstream input(path, std::ios::binary);
if (!input.is_open()) {
return std::nullopt;
}
input.seekg(0, std::ios::end);
const auto size = static_cast<std::size_t>(input.tellg());
input.seekg(0, std::ios::beg);
std::vector<std::byte> bytes(size);
if (size > 0 && !input.read(reinterpret_cast<char*>(bytes.data()), static_cast<std::streamsize>(size))) {
return std::nullopt;
}
return bytes;
}
template <typename T>
[[nodiscard]] std::optional<std::vector<std::byte>> MetaCoreSerializeSection(
const T& value,
const MetaCoreTypeRegistry& registry
) {
return MetaCoreSerializeToBytes(value, registry);
}
template <typename T>
[[nodiscard]] bool MetaCoreDeserializeSection(
const MetaCorePackageSection& section,
std::span<const std::byte> buffer,
T& value,
const MetaCoreTypeRegistry& registry
) {
if (section.Offset + section.Size > buffer.size()) {
return false;
}
return MetaCoreDeserializeFromBytes(
buffer.subspan(static_cast<std::size_t>(section.Offset), static_cast<std::size_t>(section.Size)),
value,
registry
);
}
} // namespace
bool MetaCoreWritePackageFile(
const std::filesystem::path& path,
MetaCorePackageDocument document,
const MetaCoreTypeRegistry& registry
) {
const auto serializedNames = MetaCoreSerializeSection(document.NameTable, registry);
const auto serializedImports = MetaCoreSerializeSection(document.Imports, registry);
const auto serializedExports = MetaCoreSerializeSection(document.Exports, registry);
const auto serializedDependencies = MetaCoreSerializeSection(document.Dependencies, registry);
const auto serializedCustomVersions = MetaCoreSerializeSection(document.CustomVersions, registry);
const auto serializedPayloads = MetaCoreSerializeSection(document.PayloadSections, registry);
if (!serializedNames.has_value() ||
!serializedImports.has_value() ||
!serializedExports.has_value() ||
!serializedDependencies.has_value() ||
!serializedCustomVersions.has_value() ||
!serializedPayloads.has_value()) {
return false;
}
const auto provisionalHeaderBytes = MetaCoreSerializeToBytes(document.Header, registry);
if (!provisionalHeaderBytes.has_value()) {
return false;
}
std::uint64_t cursor = static_cast<std::uint64_t>(provisionalHeaderBytes->size());
document.Header.NameTable = MetaCorePackageSection{cursor, static_cast<std::uint64_t>(serializedNames->size())};
cursor += document.Header.NameTable.Size;
document.Header.ImportTable = MetaCorePackageSection{cursor, static_cast<std::uint64_t>(serializedImports->size())};
cursor += document.Header.ImportTable.Size;
document.Header.ExportTable = MetaCorePackageSection{cursor, static_cast<std::uint64_t>(serializedExports->size())};
cursor += document.Header.ExportTable.Size;
document.Header.DependencyTable = MetaCorePackageSection{cursor, static_cast<std::uint64_t>(serializedDependencies->size())};
cursor += document.Header.DependencyTable.Size;
document.Header.CustomVersionTable = MetaCorePackageSection{cursor, static_cast<std::uint64_t>(serializedCustomVersions->size())};
cursor += document.Header.CustomVersionTable.Size;
document.Header.PayloadSections = MetaCorePackageSection{cursor, static_cast<std::uint64_t>(serializedPayloads->size())};
cursor += document.Header.PayloadSections.Size;
document.Header.FileSize = cursor;
const auto finalHeaderBytes = MetaCoreSerializeToBytes(document.Header, registry);
if (!finalHeaderBytes.has_value()) {
return false;
}
std::filesystem::create_directories(path.parent_path());
std::ofstream output(path, std::ios::binary | std::ios::trunc);
if (!output.is_open()) {
return false;
}
output.write(reinterpret_cast<const char*>(finalHeaderBytes->data()), static_cast<std::streamsize>(finalHeaderBytes->size()));
output.write(reinterpret_cast<const char*>(serializedNames->data()), static_cast<std::streamsize>(serializedNames->size()));
output.write(reinterpret_cast<const char*>(serializedImports->data()), static_cast<std::streamsize>(serializedImports->size()));
output.write(reinterpret_cast<const char*>(serializedExports->data()), static_cast<std::streamsize>(serializedExports->size()));
output.write(reinterpret_cast<const char*>(serializedDependencies->data()), static_cast<std::streamsize>(serializedDependencies->size()));
output.write(reinterpret_cast<const char*>(serializedCustomVersions->data()), static_cast<std::streamsize>(serializedCustomVersions->size()));
output.write(reinterpret_cast<const char*>(serializedPayloads->data()), static_cast<std::streamsize>(serializedPayloads->size()));
return output.good();
}
std::optional<MetaCorePackageDocument> MetaCoreReadPackageFile(
const std::filesystem::path& path,
const MetaCoreTypeRegistry& registry
) {
const auto bytes = MetaCoreReadAllBytes(path);
if (!bytes.has_value()) {
return std::nullopt;
}
MetaCorePackageDocument document;
MetaCoreArchiveReader headerReader(std::span<const std::byte>(bytes->data(), bytes->size()));
if (!MetaCoreDeserializeValue(headerReader, document.Header, registry)) {
return std::nullopt;
}
if (document.Header.Magic != GMetaCorePackageMagic ||
document.Header.FormatVersion != GMetaCorePackageFormatVersion ||
document.Header.Endianness != MetaCorePackageEndianness::Little ||
document.Header.FileSize != bytes->size()) {
return std::nullopt;
}
const std::span<const std::byte> byteSpan(bytes->data(), bytes->size());
if (!MetaCoreDeserializeSection(document.Header.NameTable, byteSpan, document.NameTable, registry) ||
!MetaCoreDeserializeSection(document.Header.ImportTable, byteSpan, document.Imports, registry) ||
!MetaCoreDeserializeSection(document.Header.ExportTable, byteSpan, document.Exports, registry) ||
!MetaCoreDeserializeSection(document.Header.DependencyTable, byteSpan, document.Dependencies, registry) ||
!MetaCoreDeserializeSection(document.Header.CustomVersionTable, byteSpan, document.CustomVersions, registry) ||
!MetaCoreDeserializeSection(document.Header.PayloadSections, byteSpan, document.PayloadSections, registry)) {
return std::nullopt;
}
return document;
}
} // namespace MetaCore