• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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