705 lines
21 KiB
C++
705 lines
21 KiB
C++
/**
|
|
* xmlparser.h
|
|
* Yet Another XMPP Stack
|
|
* This file is part of the YATE Project http://YATE.null.ro
|
|
*
|
|
* Yet Another Telephony Engine - a fully featured software PBX and IVR
|
|
* Copyright (C) 2004-2006 Null Team
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
|
|
#ifndef __XMLPARSER_H
|
|
#define __XMLPARSER_H
|
|
|
|
#include <yateclass.h>
|
|
#include <tinyxml.h>
|
|
|
|
#ifdef _WINDOWS
|
|
|
|
#ifdef LIBYJINGLE_EXPORTS
|
|
#define YJINGLE_API __declspec(dllexport)
|
|
#else
|
|
#ifndef LIBYJINGLE_STATIC
|
|
#define YJINGLE_API __declspec(dllimport)
|
|
#endif
|
|
#endif
|
|
|
|
#endif /* _WINDOWS */
|
|
|
|
#ifndef YJINGLE_API
|
|
#define YJINGLE_API
|
|
#endif
|
|
|
|
/**
|
|
* Holds all Telephony Engine related classes.
|
|
*/
|
|
namespace TelEngine {
|
|
|
|
#define XMLPARSER_MAXDATABUFFER 8192 // Default max data buffer
|
|
|
|
class XMLElement;
|
|
class XMLParser;
|
|
class XMLElementOut;
|
|
|
|
/**
|
|
* This class holds an XML element
|
|
* @short An XML element
|
|
*/
|
|
class YJINGLE_API XMLElement : public GenObject
|
|
{
|
|
friend class XMLParser;
|
|
public:
|
|
/**
|
|
* Element type as enumeration
|
|
*/
|
|
enum Type {
|
|
// *** Stream related elements
|
|
StreamStart, // stream:stream
|
|
StreamEnd, // /stream:stream
|
|
StreamError, // stream::error
|
|
StreamFeatures, // stream::features
|
|
Register, // register
|
|
Starttls, // starttls
|
|
Handshake, // handshake
|
|
Auth, // auth
|
|
Challenge, // challenge
|
|
Abort, // abort
|
|
Aborted, // aborted
|
|
Response, // response
|
|
Proceed, // proceed
|
|
Success, // success
|
|
Failure, // failure
|
|
Mechanisms, // mechanisms
|
|
Mechanism, // mechanism
|
|
Session, // session
|
|
// *** Stanzas
|
|
Iq, // iq
|
|
Message, // message
|
|
Presence, // presence
|
|
// *** Stanza children
|
|
Error, // error
|
|
Query, // query
|
|
VCard, // vCard
|
|
Jingle, // session
|
|
// Description
|
|
Description, // description
|
|
PayloadType, // payload-type
|
|
// Transport
|
|
Transport, // transport
|
|
Candidate, // candidate
|
|
// Message
|
|
Body, // body
|
|
Subject, // subject
|
|
// Resources
|
|
Feature, // feature
|
|
Bind, // bind
|
|
Resource, // resource
|
|
// Jingle session info
|
|
Transfer, // transfer
|
|
Hold, // hold
|
|
Active, // active
|
|
Ringing, // ringing
|
|
Mute, // mute
|
|
// Miscellaneous
|
|
Registered, // registered
|
|
Remove, // remove
|
|
Jid, // jid
|
|
Username, // username
|
|
Password, // password
|
|
Digest, // digest
|
|
Required, // required
|
|
Dtmf, // dtmf
|
|
DtmfMethod, // dtmf-method
|
|
Command, // command
|
|
Text, // text
|
|
Item, // item
|
|
Group, // group
|
|
Reason, // reason
|
|
Content, // content
|
|
Parameter, // parameter
|
|
Crypto, // crypto
|
|
CryptoRequired, // crypto-required
|
|
Trying, // trying
|
|
Received, // received
|
|
File, // file
|
|
Offer, // offer
|
|
Request, // request
|
|
StreamHost, // streamhost
|
|
StreamHostUsed, // streamhost-used
|
|
Unknown, // Any text
|
|
Invalid, // m_element is 0
|
|
};
|
|
|
|
/**
|
|
* Constructor.
|
|
* Constructs a StreamEnd element
|
|
*/
|
|
XMLElement();
|
|
|
|
/**
|
|
* Copy constructor
|
|
* @param src Source element
|
|
*/
|
|
XMLElement(const XMLElement& src);
|
|
|
|
/**
|
|
* Constructor. Partially build this element from another one.
|
|
* Copy name and 'to', 'from', 'type', 'id' attributes
|
|
* @param src Source element
|
|
* @param response True to reverse 'to' and 'from' attributes
|
|
* @param result True to set type to "result", false to set it to "error".
|
|
* Ignored if response is false
|
|
*/
|
|
XMLElement(const XMLElement& src, bool response, bool result);
|
|
|
|
/**
|
|
* Constructor.
|
|
* Constructs an XML element with a TiXmlElement element with the given name.
|
|
* Used for outgoing elements
|
|
* @param name The element's name
|
|
* @param attributes Optional list of attributes
|
|
* @param text Optional text for the XML element
|
|
*/
|
|
XMLElement(const char* name, NamedList* attributes = 0, const char* text = 0);
|
|
|
|
/**
|
|
* Constructor.
|
|
* Constructs an XML element with a TiXmlElement element with the given type's name.
|
|
* Used for outgoing elements
|
|
* @param type The element's type
|
|
* @param attributes Optional list of attributes
|
|
* @param text Optional text for the XML element
|
|
*/
|
|
XMLElement(Type type, NamedList* attributes = 0, const char* text = 0);
|
|
|
|
/**
|
|
* Constructor.
|
|
* Build this XML element from a list containing name, attributes and text.
|
|
* Element's name must be a parameter whose name must be equal to prefix.
|
|
* Element's text must be a parameter whose name is prefix followed by a dot.
|
|
* The list of attributes will be built from parameters starting with prefix.attributename
|
|
* @param src The list containing data used to build this XML element
|
|
* @param prefix The prefix used to search the list of parameters
|
|
*/
|
|
XMLElement(NamedList& src, const char* prefix);
|
|
|
|
/**
|
|
* Destructor. Deletes the underlying TiXmlElement if owned
|
|
*/
|
|
virtual ~XMLElement();
|
|
|
|
/**
|
|
* Get the type of this object
|
|
* @return The type of this object as enumeration
|
|
*/
|
|
inline Type type() const
|
|
{ return m_type; }
|
|
|
|
/**
|
|
* Get the TiXmlElement's name
|
|
* @return The name of the TiXmlElement object or 0
|
|
*/
|
|
inline const char* name() const
|
|
{ return valid() ? m_element->Value() : 0; }
|
|
|
|
/**
|
|
* Check if the TiXmlElement's name is the given text
|
|
* @param text Text to compare with
|
|
* @return False if text is 0 or not equal to name
|
|
*/
|
|
inline bool nameIs(const char* text) const
|
|
{ return (text && name() && (0 == ::strcmp(name(),text))); }
|
|
|
|
/**
|
|
* Get the validity of this object
|
|
* @return True if m_element is non null
|
|
*/
|
|
inline bool valid() const
|
|
{ return m_element != 0; }
|
|
|
|
/**
|
|
* Change the type of this object
|
|
* @param t The new type of this object
|
|
*/
|
|
inline void changeType(Type t)
|
|
{ m_type = t; }
|
|
|
|
/**
|
|
* Put the element in a buffer
|
|
* @param dest Destination string
|
|
* @param unclose True to leave the tag unclosed
|
|
*/
|
|
void toString(String& dest, bool unclose = false) const;
|
|
|
|
/**
|
|
* Put this element's name, text and attributes to a list of parameters
|
|
* @param dest Destination list
|
|
* @param prefix Prefix to add to parameters
|
|
*/
|
|
void toList(NamedList& dest, const char* prefix);
|
|
|
|
/**
|
|
* Set the value of an existing attribute or adds a new one
|
|
* @param name Attribute's name
|
|
* @param value Attribute's value
|
|
*/
|
|
void setAttribute(const char* name, const char* value);
|
|
|
|
/**
|
|
* Set the value of an existing attribute or adds a new one if the value's length is not 0
|
|
* @param name Attribute's name
|
|
* @param value Attribute's value
|
|
*/
|
|
inline void setAttributeValid(const char* name, const String& value) {
|
|
if (value)
|
|
setAttribute(name,value);
|
|
}
|
|
|
|
/**
|
|
* Set the value of an existing attribute or adds a new one from an integer
|
|
* @param name Attribute's name
|
|
* @param value Attribute's value
|
|
*/
|
|
inline void setAttribute(const char* name, int value) {
|
|
String s(value);
|
|
setAttribute(name,s);
|
|
}
|
|
|
|
/**
|
|
* Get the value of an attribute
|
|
* @param name Attribute's name
|
|
* @return Attribute's value. May be 0 if doesn't exists or empty
|
|
*/
|
|
const char* getAttribute(const char* name) const;
|
|
|
|
/**
|
|
* Get the value of an attribute
|
|
* @param name Attribute's name
|
|
* @param value Destination string
|
|
* @return True if attribute with the given name exists and is not empty
|
|
*/
|
|
inline bool getAttribute(const char* name, String& value) const {
|
|
value = getAttribute(name);
|
|
return 0 != value.length();
|
|
}
|
|
|
|
/**
|
|
* Fill a list with element's attributes
|
|
* @param dest The destination list
|
|
*/
|
|
void getAttributes(NamedList& dest) const;
|
|
|
|
/**
|
|
* Check if an attribute with the given name and value exists
|
|
* @param name Attribute's name
|
|
* @param value Attribute's value
|
|
* @return True/False
|
|
*/
|
|
bool hasAttribute(const char* name, const char* value) const;
|
|
|
|
/**
|
|
* Get the text of this XML element
|
|
* @return Pointer to the text of this XML element or 0
|
|
*/
|
|
const char* getText() const;
|
|
|
|
/**
|
|
* Add a child to this object. Release the received element
|
|
* @param element XMLElement to add
|
|
*/
|
|
void addChild(XMLElement* element);
|
|
|
|
/**
|
|
* Find the first child element of this one.
|
|
* Remove it from the children list.
|
|
* If an element is returned, it owns the TiXmlElement pointer.
|
|
* This element must own its TiXmlElement pointer.
|
|
* @param name Optional name of the child
|
|
* @return Pointer to an XMLElement or 0 if not found
|
|
*/
|
|
XMLElement* removeChild(const char* name = 0);
|
|
|
|
/**
|
|
* Find the first child element of this one.
|
|
* Remove it from the children list.
|
|
* If an element is returned, it owns the TiXmlElement pointer.
|
|
* This element must own its TiXmlElement pointer.
|
|
* @param type Child's type to find
|
|
* @return Pointer to an XMLElement or 0 if not found
|
|
*/
|
|
inline XMLElement* removeChild(Type type)
|
|
{ return removeChild(typeName(type)); }
|
|
|
|
/**
|
|
* Find the first child element of this one.
|
|
* If an element is returned, it is a newly allocated one, not owning its TiXmlElement pointer
|
|
* @param name Optional name of the child
|
|
* @return Pointer to an XMLElement or 0 if not found
|
|
*/
|
|
XMLElement* findFirstChild(const char* name = 0);
|
|
|
|
/**
|
|
* Find the first child element of the given type.
|
|
* If an element is returned, it is a newly allocated one, not owning its TiXmlElement pointer
|
|
* @param type Child's type to find
|
|
* @return Pointer to an XMLElement or 0 if not found
|
|
*/
|
|
inline XMLElement* findFirstChild(Type type)
|
|
{ return findFirstChild(typeName(type)); }
|
|
|
|
/**
|
|
* Check if this element has a given child
|
|
* @param name Optional name of the child (check for the first one if 0)
|
|
* @return True if this element has the desired child
|
|
*/
|
|
inline bool hasChild(const char* name) {
|
|
XMLElement* tmp = findFirstChild(name);
|
|
bool ok = (0 != tmp);
|
|
TelEngine::destruct(tmp);
|
|
return ok;
|
|
}
|
|
|
|
/**
|
|
* Check if this element has a given child
|
|
* @param type Child's type to find
|
|
* @return True if this element has the desired child
|
|
*/
|
|
inline bool hasChild(Type type)
|
|
{ return hasChild(typeName(type)); }
|
|
|
|
/**
|
|
* Find the next child element. Delete the starting element if not 0.
|
|
* If an element is returned, it is a newly allocated one, not owning its TiXmlElement pointer
|
|
* @param element Starting XMLElement. O to find from the beginning
|
|
* @param name Optional name of the child
|
|
* @return Pointer to an XMLElement or 0 if not found
|
|
*/
|
|
XMLElement* findNextChild(XMLElement* element, const char* name = 0);
|
|
|
|
/**
|
|
* Find the next child element of the given type. Delete the starting element if not 0.
|
|
* If an element is returned, it is a newly allocated one, not owning its TiXmlElement pointer
|
|
* @param element Starting XMLElement. O to find from the beginning
|
|
* @param type Child's type to find
|
|
* @return Pointer to an XMLElement or 0 if not found
|
|
*/
|
|
inline XMLElement* findNextChild(XMLElement* element, Type type)
|
|
{ return findNextChild(element,typeName(type)); }
|
|
|
|
/**
|
|
* Find the first attribute
|
|
* @return Pointer to the first attribute or 0
|
|
*/
|
|
inline const TiXmlAttribute* firstAttribute() const
|
|
{ return valid() ? m_element->FirstAttribute() : 0; }
|
|
|
|
/**
|
|
* Get the name associated with the given type
|
|
* @param type Element type as enumeration
|
|
* @return Pointer to the name or 0
|
|
*/
|
|
static inline const char* typeName(Type type)
|
|
{ return lookup(type,s_names); }
|
|
|
|
/**
|
|
* Check if the given text is equal to the one associated with the given type
|
|
* @param txt Text to compare
|
|
* @param type Element type as enumeration
|
|
* @return True if txt equals the text associated with the given type
|
|
*/
|
|
static inline bool isType(const char* txt, Type type) {
|
|
const char* s = typeName(type);
|
|
return (txt && s && (0 == ::strcmp(txt,s)));
|
|
}
|
|
|
|
/**
|
|
* Get a pointer to this object
|
|
*/
|
|
virtual void* getObject(const String& name) const {
|
|
if (name == "XMLElement")
|
|
return (void*)this;
|
|
return GenObject::getObject(name);
|
|
}
|
|
|
|
/**
|
|
* Release memory
|
|
*/
|
|
virtual const String& toString() const
|
|
{ return m_name; }
|
|
|
|
/**
|
|
* Release memory
|
|
*/
|
|
virtual void destruct() {
|
|
if (m_owner && m_element)
|
|
delete m_element;
|
|
m_element = 0;
|
|
GenObject::destruct();
|
|
}
|
|
|
|
/**
|
|
* Get an xml element from a list's parameter
|
|
* @param list The list to be searched for the given parameter
|
|
* @param stole True to release parameter ownership (defaults to false)
|
|
* @param name Parameter name (defaults to 'xml')
|
|
* @param value Optional parameter value to check
|
|
* @return XMLElement pointer or 0. If a valid pointer is returned and
|
|
* stole is true the caller will own the pointer
|
|
*/
|
|
static XMLElement* getXml(NamedList& list, bool stole = false,
|
|
const char* name = "xml", const char* value = 0);
|
|
|
|
/**
|
|
* Associations between XML element name and type
|
|
*/
|
|
static TokenDict s_names[];
|
|
|
|
protected:
|
|
/**
|
|
* Constructor.
|
|
* Constructs an XML element from a TiXmlElement.
|
|
* Used to extract elements from parser and access the children.
|
|
* When extracting elements from parser the object will own the TiXmlElement.
|
|
* When accessing the children, the object will not own the TiXmlElement
|
|
* @param element Pointer to a valid TiXmlElement
|
|
* @param owner Owner flag
|
|
*/
|
|
XMLElement(TiXmlElement* element, bool owner);
|
|
|
|
/**
|
|
* Get the underlying TiXmlElement
|
|
* @return The underlying TiXmlElement object or 0
|
|
*/
|
|
inline TiXmlElement* get() const
|
|
{ return m_element; }
|
|
|
|
/**
|
|
* Release the ownership of the underlying TiXmlElement
|
|
* and returns it if the object owns it
|
|
* @return The underlying TiXmlElement object or 0 if not owned or 0
|
|
*/
|
|
TiXmlElement* releaseOwnership();
|
|
|
|
private:
|
|
// Set this object's type from m_element's name
|
|
inline void setType() {
|
|
m_name = name();
|
|
m_type = (Type)lookup(name(),s_names,Unknown);
|
|
}
|
|
|
|
Type m_type; // Element's type
|
|
bool m_owner; // Owner flag. If true, this object owns the XML element
|
|
String m_name; // The name of this element
|
|
TiXmlElement* m_element; // The underlying XML element
|
|
};
|
|
|
|
/**
|
|
* This class is responsable of parsing incoming data.
|
|
* Keeps the resulting XML elements and the input buffer
|
|
* @short An XML parser
|
|
*/
|
|
class YJINGLE_API XMLParser : public TiXmlDocument, public Mutex
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
* Constructs an XML parser
|
|
*/
|
|
inline XMLParser()
|
|
: TiXmlDocument(), Mutex(true), m_findstart(true)
|
|
{}
|
|
|
|
/**
|
|
* Destructor
|
|
*/
|
|
virtual ~XMLParser()
|
|
{}
|
|
|
|
/**
|
|
* Add data to buffer. Parse the buffer.
|
|
* On success, the already parsed data is removed from buffer.
|
|
* This method is thread safe
|
|
* @param data Pointer to the data to consume
|
|
* @param len Data length
|
|
* @return True on successfully parsed
|
|
*/
|
|
bool consume(const char* data, u_int32_t len);
|
|
|
|
/**
|
|
* Extract the first XML element from document.
|
|
* Remove non-element children of the document (e.g. declaration).
|
|
* This method is thread safe
|
|
* @return Pointer to an XMLElement or 0 if the document is empty
|
|
*/
|
|
XMLElement* extract();
|
|
|
|
/**
|
|
* Get the buffer length (incomplete data)
|
|
* @return The number of bytes belonging to an incomplete XML element
|
|
*/
|
|
inline unsigned int bufLen() const
|
|
{ return m_buffer.length(); }
|
|
|
|
/**
|
|
* Get a copy of the parser's buffer
|
|
* @param dest Destination string
|
|
*/
|
|
inline void getBuffer(String& dest) const
|
|
{ dest = m_buffer; }
|
|
|
|
/**
|
|
* Clear the parser's input buffer and already parsed elements. Reset data
|
|
*/
|
|
void reset();
|
|
|
|
/**
|
|
* The maximum allowed buffer length
|
|
*/
|
|
static u_int32_t s_maxDataBuffer;
|
|
|
|
/**
|
|
* The XML encoding
|
|
*/
|
|
static TiXmlEncoding s_xmlEncoding;
|
|
|
|
private:
|
|
String m_buffer; // Input data buffer
|
|
bool m_findstart; // Search for stream start tag or not
|
|
};
|
|
|
|
/**
|
|
* This class holds an XML element to be sent through a stream
|
|
* @short An outgoing XML element
|
|
*/
|
|
class YJINGLE_API XMLElementOut : public RefObject
|
|
{
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* @param element The XML element
|
|
* @param senderID Optional sender id
|
|
* @param unclose True to not close the tag when building the buffer
|
|
*/
|
|
inline XMLElementOut(XMLElement* element, const char* senderID = 0,
|
|
bool unclose = false)
|
|
: m_element(element), m_offset(0), m_id(senderID), m_unclose(unclose),
|
|
m_sent(false)
|
|
{}
|
|
|
|
/**
|
|
* Destructor
|
|
* Delete m_element if not 0
|
|
*/
|
|
virtual ~XMLElementOut()
|
|
{ TelEngine::destruct(m_element); }
|
|
|
|
/**
|
|
* Get the underlying element
|
|
* @return The underlying element
|
|
*/
|
|
inline XMLElement* element() const
|
|
{ return m_element; }
|
|
|
|
/**
|
|
* Check if this element was (partially) sent
|
|
* @return True if an attempt to send this element was already done
|
|
*/
|
|
inline bool sent() const
|
|
{ return m_sent; }
|
|
|
|
/**
|
|
* Get the data buffer
|
|
* @return The data buffer
|
|
*/
|
|
inline String& buffer()
|
|
{ return m_buffer; }
|
|
|
|
/**
|
|
* Get the id member
|
|
* @return The id member
|
|
*/
|
|
inline const String& id() const
|
|
{ return m_id; }
|
|
|
|
/**
|
|
* Get the remainig byte count to send
|
|
* @return The unsent number of bytes
|
|
*/
|
|
inline u_int32_t dataCount()
|
|
{ return m_buffer.length() - m_offset; }
|
|
|
|
/**
|
|
* Get the remainig data to send. Set the buffer if not already set
|
|
* @param nCount The number of unsent bytes
|
|
* @return Pointer to the remaining data or 0
|
|
*/
|
|
inline const char* getData(u_int32_t& nCount) {
|
|
if (!m_buffer)
|
|
prepareToSend();
|
|
nCount = dataCount();
|
|
return m_buffer.c_str() + m_offset;
|
|
}
|
|
|
|
/**
|
|
* Increase the offset with nCount bytes. Set the sent flag
|
|
* @param nCount The number of bytes sent
|
|
*/
|
|
inline void dataSent(u_int32_t nCount) {
|
|
m_sent = true;
|
|
m_offset += nCount;
|
|
if (m_offset > m_buffer.length())
|
|
m_offset = m_buffer.length();
|
|
}
|
|
|
|
/**
|
|
* Release the ownership of m_element
|
|
* The caller is responsable of returned pointer
|
|
* @return XMLElement pointer or 0
|
|
*/
|
|
inline XMLElement* release() {
|
|
XMLElement* e = m_element;
|
|
m_element = 0;
|
|
return e;
|
|
}
|
|
|
|
/**
|
|
* Fill a buffer with the XML element to send
|
|
* @param buffer The buffer to fill
|
|
*/
|
|
inline void toBuffer(String& buffer)
|
|
{ if (m_element) m_element->toString(buffer,m_unclose); }
|
|
|
|
/**
|
|
* Fill the buffer with the XML element to send
|
|
*/
|
|
inline void prepareToSend()
|
|
{ toBuffer(m_buffer); }
|
|
|
|
private:
|
|
XMLElement* m_element; // The XML element
|
|
String m_buffer; // Data to send
|
|
u_int32_t m_offset; // Offset to send
|
|
String m_id; // Sender's id
|
|
bool m_unclose; // Close or not the element's tag
|
|
bool m_sent; // Sent flag (true if an attempt to send was done)
|
|
};
|
|
|
|
};
|
|
|
|
#endif /* __XMLPARSER_H */
|
|
|
|
/* vi: set ts=8 sw=4 sts=4 noet: */
|