|  | // Copyright 2015 The Weave Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "src/notification/xmpp_stream_parser.h" | 
|  |  | 
|  | #include "src/notification/xml_node.h" | 
|  |  | 
|  | namespace weave { | 
|  |  | 
|  | XmppStreamParser::XmppStreamParser(Delegate* delegate) : delegate_{delegate} { | 
|  | parser_ = XML_ParserCreate(nullptr); | 
|  | XML_SetUserData(parser_, this); | 
|  | XML_SetElementHandler(parser_, &XmppStreamParser::HandleElementStart, | 
|  | &XmppStreamParser::HandleElementEnd); | 
|  | XML_SetCharacterDataHandler(parser_, &XmppStreamParser::HandleCharData); | 
|  | } | 
|  |  | 
|  | XmppStreamParser::~XmppStreamParser() { | 
|  | XML_ParserFree(parser_); | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::ParseData(const std::string& data) { | 
|  | XML_Parse(parser_, data.data(), data.size(), 0); | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::Reset() { | 
|  | std::stack<std::unique_ptr<XmlNode>>{}.swap(node_stack_); | 
|  | started_ = false; | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::HandleElementStart(void* user_data, | 
|  | const XML_Char* element, | 
|  | const XML_Char** attr) { | 
|  | auto self = static_cast<XmppStreamParser*>(user_data); | 
|  | std::map<std::string, std::string> attributes; | 
|  | if (attr != nullptr) { | 
|  | for (size_t n = 0; attr[n] != nullptr && attr[n + 1] != nullptr; n += 2) { | 
|  | attributes.insert(std::make_pair(attr[n], attr[n + 1])); | 
|  | } | 
|  | } | 
|  | self->OnOpenElement(element, std::move(attributes)); | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::HandleElementEnd(void* user_data, | 
|  | const XML_Char* element) { | 
|  | auto self = static_cast<XmppStreamParser*>(user_data); | 
|  | self->OnCloseElement(element); | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::HandleCharData(void* user_data, | 
|  | const char* content, | 
|  | int length) { | 
|  | auto self = static_cast<XmppStreamParser*>(user_data); | 
|  | self->OnCharData(std::string{content, static_cast<size_t>(length)}); | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::OnOpenElement( | 
|  | const std::string& node_name, | 
|  | std::map<std::string, std::string> attributes) { | 
|  | if (!started_) { | 
|  | started_ = true; | 
|  | if (delegate_) | 
|  | delegate_->OnStreamStart(node_name, std::move(attributes)); | 
|  | return; | 
|  | } | 
|  | node_stack_.emplace(new XmlNode{node_name, std::move(attributes)}); | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::OnCloseElement(const std::string& node_name) { | 
|  | if (node_stack_.empty()) { | 
|  | if (started_) { | 
|  | started_ = false; | 
|  | if (delegate_) | 
|  | delegate_->OnStreamEnd(node_name); | 
|  | } | 
|  | return; | 
|  | } | 
|  |  | 
|  | auto node = std::move(node_stack_.top()); | 
|  | node_stack_.pop(); | 
|  | if (!node_stack_.empty()) { | 
|  | XmlNode* parent = node_stack_.top().get(); | 
|  | parent->AddChild(std::move(node)); | 
|  | } else if (delegate_) { | 
|  | delegate_->OnStanza(std::move(node)); | 
|  | } | 
|  | } | 
|  |  | 
|  | void XmppStreamParser::OnCharData(const std::string& text) { | 
|  | if (!node_stack_.empty()) { | 
|  | XmlNode* node = node_stack_.top().get(); | 
|  | node->AppendText(text); | 
|  | } | 
|  | } | 
|  |  | 
|  | }  // namespace weave |