Files
Navmesher/Navmesher/esx_reader.cpp

106 lines
2.9 KiB
C++

#include "esx_reader_impl.hpp"
using namespace esxr;
Node read_unknown_record(std::istream &in);
[[nodiscard]] Header esxr::read_header(std::istream &in)
{
return read_header_impl<directly_readable>(in);
}
[[nodiscard]] std::size_t data_size(const RecordHeader& header)
{
return header.size;
}
[[nodiscard]] std::size_t data_size(const GroupHeader& header)
{
return header.size - header_size;
}
[[nodiscard]] std::streamsize data_ssize(const RecordHeader& header)
{
return static_cast<std::streamsize>(data_size(header));
}
[[nodiscard]] std::streamsize data_ssize(const GroupHeader& header)
{
return static_cast<std::streamsize>(data_size(header));
}
[[nodiscard]] std::size_t node_size(const RecordNode& node)
{
return node.header.size + header_size;
}
[[nodiscard]] std::size_t node_size(const GroupNode& node)
{
return node.header.size;
}
[[nodiscard]] std::streamsize node_ssize(const RecordNode& node)
{
return static_cast<std::streamsize>(node_size(node));
}
[[nodiscard]] std::streamsize node_ssize(const GroupNode& node)
{
return static_cast<std::streamsize>(node_size(node));
}
[[nodiscard]] std::streamsize node_ssize(const Node& node)
{
return std::visit(utility::overloaded{
[](const GroupNode &node) { return node_ssize(node); },
[](const RecordNode &node) { return node_ssize(node); },
}, node);
}
Node read_record(RecordHeader header, std::istream &in)
{
std::vector<char> data(data_size(header));
in.read(data.data(), data_ssize(header));
return { RecordNode{ header, std::move(data) } };
}
Node read_group(GroupHeader header, std::istream &in)
{
std::vector<Node> children{};
auto remaining = data_ssize(header);
while (remaining > 0) {
children.emplace_back(read_unknown_record(in));
remaining -= node_ssize(children.back());
}
if (remaining < 0)
throw std::runtime_error("Read past end of group data.");
return { GroupNode{ header, std::move(children) } };
}
Node read_unknown_record(std::istream &in)
{
auto header_variant = read_header(in);
struct visitor {
std::istream *in_ptr;
Node operator()(RecordHeader h) {
return read_record(h, *in_ptr);
}
Node operator()(GroupHeader h) {
return read_group(h, *in_ptr);
}
};
return std::visit(visitor{ &in }, std::move(header_variant));
}
[[nodiscard]] RootNode esxr::read_esx(std::istream &in, std::size_t file_size)
{
RootNode root{};
auto remaining = static_cast<std::streamsize>(file_size);
while (remaining != 0) {
root.children.emplace_back(read_unknown_record(in));
remaining -= node_ssize(root.children.back());
}
return root;
}