| // 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. | 
 |  | 
 | #ifndef LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_ | 
 | #define LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_ | 
 |  | 
 | #include <expat.h> | 
 |  | 
 | #include <map> | 
 | #include <memory> | 
 | #include <stack> | 
 | #include <string> | 
 |  | 
 | #include <base/macros.h> | 
 |  | 
 | namespace weave { | 
 |  | 
 | class XmlNode; | 
 |  | 
 | // A simple XML stream parser. As the XML data is being read from a data source | 
 | // (for example, a socket), XmppStreamParser::ParseData() should be called. | 
 | // This method parses the provided XML data chunk and if it finds complete | 
 | // XML elements, it will call internal OnOpenElement(), OnCloseElement() and | 
 | // OnCharData() member functions. These will track the element nesting level. | 
 | // When a top-level element starts, the parser will call Delegate::OnStreamStart | 
 | // method. Once this happens, every complete XML element (including its children | 
 | // if they are present) will trigger Delegate::OnStanze() callback. | 
 | // Finally, when top-level element is closed, Delegate::OnStreamEnd() is called. | 
 | // This class is specifically tailored to XMPP streams which look like this: | 
 | // B:  <stream:stream to='example.com' xmlns='jabber:client' version='1.0'> | 
 | // S:    <presence><show/></presence> | 
 | // S:    <message to='foo'><body/></message> | 
 | // S:    <iq to='bar'><query/></iq> | 
 | // S:    ... | 
 | // E:  </stream:stream> | 
 | // Here, "B:" will trigger OnStreamStart(), "S:" will result in OnStanza() and | 
 | // "E:" will result in OnStreamEnd(). | 
 | class XmppStreamParser final { | 
 |  public: | 
 |   // Delegate interface that interested parties implement to receive | 
 |   // notifications of stream opening/closing and on new stanzas arriving. | 
 |   class Delegate { | 
 |    public: | 
 |     virtual void OnStreamStart( | 
 |         const std::string& node_name, | 
 |         std::map<std::string, std::string> attributes) = 0; | 
 |     virtual void OnStreamEnd(const std::string& node_name) = 0; | 
 |     virtual void OnStanza(std::unique_ptr<XmlNode> stanza) = 0; | 
 |  | 
 |    protected: | 
 |     virtual ~Delegate() = default; | 
 |   }; | 
 |  | 
 |   explicit XmppStreamParser(Delegate* delegate); | 
 |   ~XmppStreamParser(); | 
 |  | 
 |   // Parses additional XML data received from an input stream. | 
 |   void ParseData(const std::string& data); | 
 |  | 
 |   // Resets the parser to expect the top-level stream node again. | 
 |   void Reset(); | 
 |  | 
 |  private: | 
 |   // Raw expat callbacks. | 
 |   static void HandleElementStart(void* user_data, | 
 |                                  const XML_Char* element, | 
 |                                  const XML_Char** attr); | 
 |   static void HandleElementEnd(void* user_data, const XML_Char* element); | 
 |   static void HandleCharData(void* user_data, const char* content, int length); | 
 |  | 
 |   // Reinterpreted callbacks from expat with some data pre-processed. | 
 |   void OnOpenElement(const std::string& node_name, | 
 |                      std::map<std::string, std::string> attributes); | 
 |   void OnCloseElement(const std::string& node_name); | 
 |   void OnCharData(const std::string& text); | 
 |  | 
 |   Delegate* delegate_; | 
 |   XML_Parser parser_{nullptr}; | 
 |   bool started_{false}; | 
 |   std::stack<std::unique_ptr<XmlNode>> node_stack_; | 
 |  | 
 |   DISALLOW_COPY_AND_ASSIGN(XmppStreamParser); | 
 | }; | 
 |  | 
 | }  // namespace weave | 
 |  | 
 | #endif  // LIBWEAVE_SRC_NOTIFICATION_XMPP_STREAM_PARSER_H_ |