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
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2026 Fernando Sahmkow
#include <whiteout/models/wem/converters.h>
#include <unordered_map>
namespace whiteout {
namespace models {
namespace wem {
// ============================================================================
// FormatConverter — default implementations
// ============================================================================
ConvertResult FormatConverter::importFromBytes(std::span<const u8>) const {
ConvertResult result;
result.issues.push_back("Import from bytes not supported for format: " + formatId());
return result;
}
ExportResult FormatConverter::exportToBytes(const Model&, u32) const {
ExportResult result;
result.issues.push_back("Export to bytes not supported for format: " + formatId());
return result;
}
// ============================================================================
// ConverterRegistry
// ============================================================================
struct ConverterRegistry::Impl {
std::vector<std::shared_ptr<FormatConverter>> converters;
std::unordered_map<std::string, size_t> idToIndex;
};
ConverterRegistry& ConverterRegistry::instance() {
static ConverterRegistry registry;
return registry;
}
ConverterRegistry::ConverterRegistry() : pImpl(std::make_unique<Impl>()) {
// Register built-in converters
registerConverter(std::make_shared<MdxConverter>());
registerConverter(std::make_shared<M2Converter>());
registerConverter(std::make_shared<M3Converter>());
}
ConverterRegistry::~ConverterRegistry() = default;
void ConverterRegistry::registerConverter(std::shared_ptr<FormatConverter> converter) {
if (!converter)
return;
auto id = converter->formatId();
auto it = pImpl->idToIndex.find(id);
if (it != pImpl->idToIndex.end()) {
pImpl->converters[it->second] = std::move(converter);
} else {
pImpl->idToIndex[id] = pImpl->converters.size();
pImpl->converters.push_back(std::move(converter));
}
}
const FormatConverter* ConverterRegistry::find(const std::string& formatId) const {
auto it = pImpl->idToIndex.find(formatId);
return (it != pImpl->idToIndex.end()) ? pImpl->converters[it->second].get() : nullptr;
}
std::vector<const FormatConverter*> ConverterRegistry::all() const {
std::vector<const FormatConverter*> result;
result.reserve(pImpl->converters.size());
for (const auto& c : pImpl->converters) {
result.push_back(c.get());
}
return result;
}
} // namespace wem
} // namespace models
} // namespace whiteout