1 // Copyright 2015 The Weave Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/notification/xmpp_stream_parser.h"
6
7 #include "src/notification/xml_node.h"
8
9 namespace weave {
10
XmppStreamParser(Delegate * delegate)11 XmppStreamParser::XmppStreamParser(Delegate* delegate) : delegate_{delegate} {
12 parser_ = XML_ParserCreate(nullptr);
13 XML_SetUserData(parser_, this);
14 XML_SetElementHandler(parser_, &XmppStreamParser::HandleElementStart,
15 &XmppStreamParser::HandleElementEnd);
16 XML_SetCharacterDataHandler(parser_, &XmppStreamParser::HandleCharData);
17 }
18
~XmppStreamParser()19 XmppStreamParser::~XmppStreamParser() {
20 XML_ParserFree(parser_);
21 }
22
ParseData(const std::string & data)23 void XmppStreamParser::ParseData(const std::string& data) {
24 XML_Parse(parser_, data.data(), data.size(), 0);
25 }
26
Reset()27 void XmppStreamParser::Reset() {
28 std::stack<std::unique_ptr<XmlNode>>{}.swap(node_stack_);
29 started_ = false;
30 }
31
HandleElementStart(void * user_data,const XML_Char * element,const XML_Char ** attr)32 void XmppStreamParser::HandleElementStart(void* user_data,
33 const XML_Char* element,
34 const XML_Char** attr) {
35 auto self = static_cast<XmppStreamParser*>(user_data);
36 std::map<std::string, std::string> attributes;
37 if (attr != nullptr) {
38 for (size_t n = 0; attr[n] != nullptr && attr[n + 1] != nullptr; n += 2) {
39 attributes.insert(std::make_pair(attr[n], attr[n + 1]));
40 }
41 }
42 self->OnOpenElement(element, std::move(attributes));
43 }
44
HandleElementEnd(void * user_data,const XML_Char * element)45 void XmppStreamParser::HandleElementEnd(void* user_data,
46 const XML_Char* element) {
47 auto self = static_cast<XmppStreamParser*>(user_data);
48 self->OnCloseElement(element);
49 }
50
HandleCharData(void * user_data,const char * content,int length)51 void XmppStreamParser::HandleCharData(void* user_data,
52 const char* content,
53 int length) {
54 auto self = static_cast<XmppStreamParser*>(user_data);
55 self->OnCharData(std::string{content, static_cast<size_t>(length)});
56 }
57
OnOpenElement(const std::string & node_name,std::map<std::string,std::string> attributes)58 void XmppStreamParser::OnOpenElement(
59 const std::string& node_name,
60 std::map<std::string, std::string> attributes) {
61 if (!started_) {
62 started_ = true;
63 if (delegate_)
64 delegate_->OnStreamStart(node_name, std::move(attributes));
65 return;
66 }
67 node_stack_.emplace(new XmlNode{node_name, std::move(attributes)});
68 }
69
OnCloseElement(const std::string & node_name)70 void XmppStreamParser::OnCloseElement(const std::string& node_name) {
71 if (node_stack_.empty()) {
72 if (started_) {
73 started_ = false;
74 if (delegate_)
75 delegate_->OnStreamEnd(node_name);
76 }
77 return;
78 }
79
80 auto node = std::move(node_stack_.top());
81 node_stack_.pop();
82 if (!node_stack_.empty()) {
83 XmlNode* parent = node_stack_.top().get();
84 parent->AddChild(std::move(node));
85 } else if (delegate_) {
86 delegate_->OnStanza(std::move(node));
87 }
88 }
89
OnCharData(const std::string & text)90 void XmppStreamParser::OnCharData(const std::string& text) {
91 if (!node_stack_.empty()) {
92 XmlNode* node = node_stack_.top().get();
93 node->AppendText(text);
94 }
95 }
96
97 } // namespace weave
98