Home | History | Annotate | Download | only in notification
      1 // Copyright 2015 The Weave Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "src/notification/xmpp_stream_parser.h"
      6 
      7 #include "src/notification/xml_node.h"
      8 
      9 namespace weave {
     10 
     11 XmppStreamParser::XmppStreamParser(Delegate* delegate) : delegate_{delegate} {
     12   parser_ = XML_ParserCreate(nullptr);
     13   XML_SetUserData(parser_, this);
     14   XML_SetElementHandler(parser_, &XmppStreamParser::HandleElementStart,
     15                         &XmppStreamParser::HandleElementEnd);
     16   XML_SetCharacterDataHandler(parser_, &XmppStreamParser::HandleCharData);
     17 }
     18 
     19 XmppStreamParser::~XmppStreamParser() {
     20   XML_ParserFree(parser_);
     21 }
     22 
     23 void XmppStreamParser::ParseData(const std::string& data) {
     24   XML_Parse(parser_, data.data(), data.size(), 0);
     25 }
     26 
     27 void XmppStreamParser::Reset() {
     28   std::stack<std::unique_ptr<XmlNode>>{}.swap(node_stack_);
     29   started_ = false;
     30 }
     31 
     32 void XmppStreamParser::HandleElementStart(void* user_data,
     33                                           const XML_Char* element,
     34                                           const XML_Char** attr) {
     35   auto self = static_cast<XmppStreamParser*>(user_data);
     36   std::map<std::string, std::string> attributes;
     37   if (attr != nullptr) {
     38     for (size_t n = 0; attr[n] != nullptr && attr[n + 1] != nullptr; n += 2) {
     39       attributes.insert(std::make_pair(attr[n], attr[n + 1]));
     40     }
     41   }
     42   self->OnOpenElement(element, std::move(attributes));
     43 }
     44 
     45 void XmppStreamParser::HandleElementEnd(void* user_data,
     46                                         const XML_Char* element) {
     47   auto self = static_cast<XmppStreamParser*>(user_data);
     48   self->OnCloseElement(element);
     49 }
     50 
     51 void XmppStreamParser::HandleCharData(void* user_data,
     52                                       const char* content,
     53                                       int length) {
     54   auto self = static_cast<XmppStreamParser*>(user_data);
     55   self->OnCharData(std::string{content, static_cast<size_t>(length)});
     56 }
     57 
     58 void XmppStreamParser::OnOpenElement(
     59     const std::string& node_name,
     60     std::map<std::string, std::string> attributes) {
     61   if (!started_) {
     62     started_ = true;
     63     if (delegate_)
     64       delegate_->OnStreamStart(node_name, std::move(attributes));
     65     return;
     66   }
     67   node_stack_.emplace(new XmlNode{node_name, std::move(attributes)});
     68 }
     69 
     70 void XmppStreamParser::OnCloseElement(const std::string& node_name) {
     71   if (node_stack_.empty()) {
     72     if (started_) {
     73       started_ = false;
     74       if (delegate_)
     75         delegate_->OnStreamEnd(node_name);
     76     }
     77     return;
     78   }
     79 
     80   auto node = std::move(node_stack_.top());
     81   node_stack_.pop();
     82   if (!node_stack_.empty()) {
     83     XmlNode* parent = node_stack_.top().get();
     84     parent->AddChild(std::move(node));
     85   } else if (delegate_) {
     86     delegate_->OnStanza(std::move(node));
     87   }
     88 }
     89 
     90 void XmppStreamParser::OnCharData(const std::string& text) {
     91   if (!node_stack_.empty()) {
     92     XmlNode* node = node_stack_.top().get();
     93     node->AppendText(text);
     94   }
     95 }
     96 
     97 }  // namespace weave
     98