134 lines
4.1 KiB
C++
134 lines
4.1 KiB
C++
#pragma once
|
|
|
|
|
|
#include <xmpp/xmpp_stanza.hpp>
|
|
|
|
#include <functional>
|
|
|
|
#include <expat.h>
|
|
|
|
/**
|
|
* A SAX XML parser that builds XML nodes and spawns events when a complete
|
|
* stanza is received (an element of level 2), or when the document is
|
|
* opened/closed (an element of level 1)
|
|
*
|
|
* After a stanza_event has been spawned, we delete the whole stanza. This
|
|
* means that even with a very long document (in XMPP the document is
|
|
* potentially infinite), the memory is never exhausted as long as each
|
|
* stanza is reasonnably short.
|
|
*
|
|
* The element names generated by expat contain the namespace of the
|
|
* element, a colon (':') and then the actual name of the element. To get
|
|
* an element "x" with a namespace of "http://jabber.org/protocol/muc", you
|
|
* just look for an XmlNode named "http://jabber.org/protocol/muc:x"
|
|
*
|
|
* TODO: enforce the size-limit for the stanza (limit the number of childs
|
|
* it can contain). For example forbid the parser going further than level
|
|
* 20 (arbitrary number here), and each XML node to have more than 15 childs
|
|
* (arbitrary number again).
|
|
*/
|
|
class XmppParser
|
|
{
|
|
public:
|
|
explicit XmppParser();
|
|
~XmppParser();
|
|
XmppParser(const XmppParser&) = delete;
|
|
XmppParser& operator=(const XmppParser&) = delete;
|
|
XmppParser(XmppParser&&) = delete;
|
|
XmppParser& operator=(XmppParser&&) = delete;
|
|
|
|
public:
|
|
/**
|
|
* Feed the parser with some XML data
|
|
*/
|
|
int feed(const char* data, const int len, const bool is_final);
|
|
/**
|
|
* Parse the data placed in the parser buffer
|
|
*/
|
|
int parse(const int size, const bool is_final);
|
|
/**
|
|
* Reset the parser, so it can be used from scratch afterward
|
|
*/
|
|
void reset();
|
|
/**
|
|
* Get a buffer provided by the xml parser.
|
|
*/
|
|
void* get_buffer(const size_t size) const;
|
|
/**
|
|
* Add one callback for the various events that this parser can spawn.
|
|
*/
|
|
void add_stanza_callback(std::function<void(const Stanza&)>&& callback);
|
|
void add_stream_open_callback(std::function<void(const XmlNode&)>&& callback);
|
|
void add_stream_close_callback(std::function<void(const XmlNode&)>&& callback);
|
|
|
|
/**
|
|
* Called when a new XML element has been opened. We instanciate a new
|
|
* XmlNode and set it as our current node. The parent of this new node is
|
|
* the previous "current" node. We have all the element's attributes in
|
|
* this event.
|
|
*
|
|
* We spawn a stream_event with this node if this is a level-1 element.
|
|
*/
|
|
void start_element(const XML_Char* name, const XML_Char** attribute);
|
|
/**
|
|
* Called when an XML element has been closed. We close the current_node,
|
|
* set our current_node as the parent of the current_node, and if that was
|
|
* a level-2 element we spawn a stanza_event with this node.
|
|
*
|
|
* And we then delete the stanza (and everything under it, its children,
|
|
* attribute, etc).
|
|
*/
|
|
void end_element(const XML_Char* name);
|
|
/**
|
|
* Some inner or tail data has been parsed
|
|
*/
|
|
void char_data(const XML_Char* data, const size_t len);
|
|
/**
|
|
* Calls all the stanza_callbacks one by one.
|
|
*/
|
|
void stanza_event(const Stanza& stanza) const;
|
|
/**
|
|
* Calls all the stream_open_callbacks one by one. Note: the passed node is not
|
|
* closed yet.
|
|
*/
|
|
void stream_open_event(const XmlNode& node) const;
|
|
/**
|
|
* Calls all the stream_close_callbacks one by one.
|
|
*/
|
|
void stream_close_event(const XmlNode& node) const;
|
|
|
|
private:
|
|
/**
|
|
* Init the XML parser and install the callbacks
|
|
*/
|
|
void init_xml_parser();
|
|
|
|
/**
|
|
* Expat structure.
|
|
*/
|
|
XML_Parser parser;
|
|
/**
|
|
* The current depth in the XML document
|
|
*/
|
|
size_t level;
|
|
/**
|
|
* The deepest XML node opened but not yet closed (to which we are adding
|
|
* new children, inner or tail)
|
|
*/
|
|
XmlNode* current_node;
|
|
/**
|
|
* The root node has no parent, so we keep it here: the XmppParser object
|
|
* is its owner.
|
|
*/
|
|
std::unique_ptr<XmlNode> root;
|
|
/**
|
|
* A list of callbacks to be called on an *_event, receiving the
|
|
* concerned Stanza/XmlNode.
|
|
*/
|
|
std::vector<std::function<void(const Stanza&)>> stanza_callbacks;
|
|
std::vector<std::function<void(const XmlNode&)>> stream_open_callbacks;
|
|
std::vector<std::function<void(const XmlNode&)>> stream_close_callbacks;
|
|
};
|
|
|
|
|