| // 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 |