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