| // 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.emplace(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 |