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
|
module;
#include <cassert>
#include <expat.h>
module routemon:xml$impl;
import :xml;
namespace routemon::xml {
auto qname_view::operator==(qname_view const& rhs) const -> bool {
return ns_uri == rhs.ns_uri && local == rhs.local;
}
executor::executor() :
p_{XML_ParserCreateNS("UTF-8", detail::qname_sep)}
{
XML_SetUserData(p_, this);
XML_SetElementHandler(p_, handle_start_element, handle_end_element);
XML_SetCharacterDataHandler(p_, handle_character_data);
XML_SetProcessingInstructionHandler(p_, handle_processing_instructions);
XML_SetExternalEntityRefHandler(p_, handle_external_entity_ref);
XML_SetNamespaceDeclHandler(p_, handle_start_namespace_decl, handle_end_namespace_decl);
XML_SetXmlDeclHandler(p_, handle_xml_decl);
}
executor::~executor() {
XML_ParserFree(p_);
}
auto executor::start() -> void {
continuation_.resume();
if (ex_) std::rethrow_exception(ex_);
}
auto executor::read(std::string_view xml, bool is_final) -> void {
if (ex_)
throw std::runtime_error{"refusing to restart parser that was thrown in"};
// TODO: narrow_cast
if (auto s = XML_Parse(p_, xml.data(), static_cast<int>(xml.size()), is_final); s != XML_STATUS_OK) {
auto errc = XML_GetErrorCode(p_);
if (errc == XML_ERROR_ABORTED) {
assert(ex_);
std::rethrow_exception(ex_);
} else {
throw std::runtime_error{std::format("failed to parse XML: {}", XML_ErrorString(errc))};
}
}
}
auto executor::end() -> void {
if (ex_)
throw std::runtime_error{"refusing to restart parser that was thrown in"};
ev_ = eof_event{};
advance_ = false;
while (continuation_) continuation_.resume();
if (ex_) std::rethrow_exception(ex_);
}
} // namespace routemon::xml
|