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 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 19 XmppStreamParser::~XmppStreamParser() { 20 XML_ParserFree(parser_); 21 } 22 23 void XmppStreamParser::ParseData(const std::string& data) { 24 XML_Parse(parser_, data.data(), data.size(), 0); 25 } 26 27 void XmppStreamParser::Reset() { 28 std::stack<std::unique_ptr<XmlNode>>{}.swap(node_stack_); 29 started_ = false; 30 } 31 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 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 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 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 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 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