// 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>{}.swap(node_stack_); started_ = false; } void XmppStreamParser::HandleElementStart(void* user_data, const XML_Char* element, const XML_Char** attr) { auto self = static_cast(user_data); std::map 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(user_data); self->OnCloseElement(element); } void XmppStreamParser::HandleCharData(void* user_data, const char* content, int length) { auto self = static_cast(user_data); self->OnCharData(std::string{content, static_cast(length)}); } void XmppStreamParser::OnOpenElement( const std::string& node_name, std::map 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