1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2026 Fernando Sahmkow
#include <whiteout/models/m3/parser.h>
#include "../../common/binary_reader.h"
#include "../../common/streams.h"
#include "../../common/unicode_path.h"
#include "binary_parse_visitor.h"
#include <fstream>
#include <stdexcept>
namespace whiteout {
namespace m3 {
using common::BinaryReader;
// ============================================================================
// ParserImpl - Implementation class using PImpl idiom
// ============================================================================
class Parser::Impl {
public:
std::vector<std::string> issues;
Model parseFromReader(BinaryReader& reader);
void reportIssue(const std::string& message);
};
Model Parser::Impl::parseFromReader(BinaryReader& reader) {
issues.clear();
Model model;
BinaryParseVisitor visitor(reader);
visitor.read(model);
// Collect any issues from the visitor.
for (const auto& issue : visitor.getIssues()) {
reportIssue(issue);
}
return model;
}
void Parser::Impl::reportIssue(const std::string& message) {
issues.push_back(message);
}
// ============================================================================
// Parser Public Interface (using PImpl)
// ============================================================================
Parser::Parser() : pImpl(std::make_unique<Impl>()) {}
Parser::~Parser() = default;
Model Parser::parse(const std::string& filePath) {
auto file = common::open_ifstream(filePath, std::ios::binary);
if (!file.is_open()) {
pImpl->issues.push_back("Failed to open M3 file: " + filePath);
return {};
}
BinaryReader reader(file);
return pImpl->parseFromReader(reader);
}
Model Parser::parse(std::span<const u8> buffer) {
common::span_streambuf streambuf(buffer);
std::istream in(&streambuf);
BinaryReader reader(in);
return pImpl->parseFromReader(reader);
}
bool Parser::hasIssues() const {
return !pImpl->issues.empty();
}
const std::vector<std::string>& Parser::getIssues() const {
return pImpl->issues;
}
} // namespace m3
} // namespace whiteout