summaryrefslogtreecommitdiffstats
path: root/server/src/xml.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'server/src/xml.cpp')
-rw-r--r--server/src/xml.cpp61
1 files changed, 61 insertions, 0 deletions
diff --git a/server/src/xml.cpp b/server/src/xml.cpp
new file mode 100644
index 0000000..cad42d1
--- /dev/null
+++ b/server/src/xml.cpp
@@ -0,0 +1,61 @@
1module;
2
3#include <cassert>
4#include <expat.h>
5
6module routemon:xml$impl;
7
8import :xml;
9
10namespace routemon::xml {
11
12 auto qname_view::operator==(qname_view const& rhs) const -> bool {
13 return ns_uri == rhs.ns_uri && local == rhs.local;
14 }
15
16 executor::executor() :
17 p_{XML_ParserCreateNS("UTF-8", detail::qname_sep)}
18 {
19 XML_SetUserData(p_, this);
20 XML_SetElementHandler(p_, handle_start_element, handle_end_element);
21 XML_SetCharacterDataHandler(p_, handle_character_data);
22 XML_SetProcessingInstructionHandler(p_, handle_processing_instructions);
23 XML_SetExternalEntityRefHandler(p_, handle_external_entity_ref);
24 XML_SetNamespaceDeclHandler(p_, handle_start_namespace_decl, handle_end_namespace_decl);
25 XML_SetXmlDeclHandler(p_, handle_xml_decl);
26 }
27
28 executor::~executor() {
29 XML_ParserFree(p_);
30 }
31
32 auto executor::start() -> void {
33 continuation_.resume();
34 if (ex_) std::rethrow_exception(ex_);
35 }
36
37 auto executor::read(std::string_view xml, bool is_final) -> void {
38 if (ex_)
39 throw std::runtime_error{"refusing to restart parser that was thrown in"};
40 // TODO: narrow_cast
41 if (auto s = XML_Parse(p_, xml.data(), static_cast<int>(xml.size()), is_final); s != XML_STATUS_OK) {
42 auto errc = XML_GetErrorCode(p_);
43 if (errc == XML_ERROR_ABORTED) {
44 assert(ex_);
45 std::rethrow_exception(ex_);
46 } else {
47 throw std::runtime_error{std::format("failed to parse XML: {}", XML_ErrorString(errc))};
48 }
49 }
50 }
51
52 auto executor::end() -> void {
53 if (ex_)
54 throw std::runtime_error{"refusing to restart parser that was thrown in"};
55 ev_ = eof_event{};
56 advance_ = false;
57 while (continuation_) continuation_.resume();
58 if (ex_) std::rethrow_exception(ex_);
59 }
60
61} // namespace routemon::xml