151 lines
6.6 KiB
C++
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
|