|  | // 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() {} | 
|  | }; | 
|  |  | 
|  | 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_ |