106 lines
2.9 KiB
C++
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;
|
|
}
|
|
|