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