#include "MetaCoreFoundation/MetaCorePackage.h" #include namespace MetaCore { namespace { [[nodiscard]] std::optional> 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(input.tellg()); input.seekg(0, std::ios::beg); std::vector bytes(size); if (size > 0 && !input.read(reinterpret_cast(bytes.data()), static_cast(size))) { return std::nullopt; } return bytes; } template [[nodiscard]] std::optional> MetaCoreSerializeSection( const T& value, const MetaCoreTypeRegistry& registry ) { return MetaCoreSerializeToBytes(value, registry); } template [[nodiscard]] bool MetaCoreDeserializeSection( const MetaCorePackageSection& section, std::span buffer, T& value, const MetaCoreTypeRegistry& registry ) { if (section.Offset + section.Size > buffer.size()) { return false; } return MetaCoreDeserializeFromBytes( buffer.subspan(static_cast(section.Offset), static_cast(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(provisionalHeaderBytes->size()); document.Header.NameTable = MetaCorePackageSection{cursor, static_cast(serializedNames->size())}; cursor += document.Header.NameTable.Size; document.Header.ImportTable = MetaCorePackageSection{cursor, static_cast(serializedImports->size())}; cursor += document.Header.ImportTable.Size; document.Header.ExportTable = MetaCorePackageSection{cursor, static_cast(serializedExports->size())}; cursor += document.Header.ExportTable.Size; document.Header.DependencyTable = MetaCorePackageSection{cursor, static_cast(serializedDependencies->size())}; cursor += document.Header.DependencyTable.Size; document.Header.CustomVersionTable = MetaCorePackageSection{cursor, static_cast(serializedCustomVersions->size())}; cursor += document.Header.CustomVersionTable.Size; document.Header.PayloadSections = MetaCorePackageSection{cursor, static_cast(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(finalHeaderBytes->data()), static_cast(finalHeaderBytes->size())); output.write(reinterpret_cast(serializedNames->data()), static_cast(serializedNames->size())); output.write(reinterpret_cast(serializedImports->data()), static_cast(serializedImports->size())); output.write(reinterpret_cast(serializedExports->data()), static_cast(serializedExports->size())); output.write(reinterpret_cast(serializedDependencies->data()), static_cast(serializedDependencies->size())); output.write(reinterpret_cast(serializedCustomVersions->data()), static_cast(serializedCustomVersions->size())); output.write(reinterpret_cast(serializedPayloads->data()), static_cast(serializedPayloads->size())); return output.good(); } std::optional 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(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 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