1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2024-11-09 01:07:16 +01:00
SqMod/source/Library/XML.hpp

2038 lines
63 KiB
C++
Raw Normal View History

#ifndef _LIBRARY_XML_HPP_
#define _LIBRARY_XML_HPP_
// ------------------------------------------------------------------------------------------------
#include "Base/Shared.hpp"
#include "Library/Numeric.hpp"
// ------------------------------------------------------------------------------------------------
#include <pugixml.hpp>
// ------------------------------------------------------------------------------------------------
namespace SqMod {
namespace XML {
// ------------------------------------------------------------------------------------------------
using namespace pugi;
// ------------------------------------------------------------------------------------------------
class XmlNode;
class XmlText;
class XmlDocument;
class XmlAttribute;
class XmlXpathNode;
class XmlXpathNodeSet;
class XmlXpathVariable;
class XmlXpathVariableSet;
class XmlXpathVariableQuery;
/* ------------------------------------------------------------------------------------------------
* Manages a reference counted xml document instance.
*/
class XmlDocumentRef
{
// --------------------------------------------------------------------------------------------
friend class XmlDocument;
private:
// --------------------------------------------------------------------------------------------
typedef xml_document Document;
// --------------------------------------------------------------------------------------------
typedef unsigned int Counter;
// --------------------------------------------------------------------------------------------
Document* m_Ptr; /* The document reader, writer and manager instance. */
Counter* m_Ref; /* Reference count to the managed instance. */
/* --------------------------------------------------------------------------------------------
* Grab a strong reference to a document instance.
*/
void Grab()
{
if (m_Ptr)
{
++(*m_Ref);
}
}
/* --------------------------------------------------------------------------------------------
* Drop a strong reference to a document instance.
*/
void Drop()
{
if (m_Ptr && --(*m_Ref) == 0)
{
delete m_Ptr;
delete m_Ref;
m_Ptr = NULL;
m_Ref = NULL;
}
}
/* --------------------------------------------------------------------------------------------
* Base constructor.
*/
XmlDocumentRef(VoidP /* unused */)
: m_Ptr(new Document())
, m_Ref(new Counter(1))
{
/* ... */
}
public:
/* --------------------------------------------------------------------------------------------
* Default constructor (null).
*/
XmlDocumentRef()
: m_Ptr(NULL), m_Ref(NULL)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor.
*/
XmlDocumentRef(const XmlDocumentRef & o)
: m_Ptr(o.m_Ptr), m_Ref(o.m_Ref)
{
Grab();
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~XmlDocumentRef()
{
Drop();
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator.
*/
XmlDocumentRef & operator = (const XmlDocumentRef & o)
{
if (m_Ptr != o.m_Ptr)
{
Drop();
m_Ptr = o.m_Ptr;
m_Ref = o.m_Ref;
Grab();
}
return *this;
}
/* --------------------------------------------------------------------------------------------
* Perform an equality comparison between two document instances.
*/
bool operator == (const XmlDocumentRef & o) const
{
return (m_Ptr == o.m_Ptr);
}
/* --------------------------------------------------------------------------------------------
* Perform an inequality comparison between two document instances.
*/
bool operator != (const XmlDocumentRef & o) const
{
return (m_Ptr != o.m_Ptr);
}
/* --------------------------------------------------------------------------------------------
* Implicit conversion to boolean for use in boolean operations.
*/
operator bool () const
{
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Member operator for dereferencing the managed pointer.
*/
Document * operator -> () const
{
assert(m_Ptr != NULL);
return m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Indirection operator for obtaining a reference of the managed pointer.
*/
Document & operator * () const
{
assert(m_Ptr != NULL);
return *m_Ptr;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the number of active references to the managed instance.
*/
Counter Count() const
{
return (m_Ptr && m_Ref) ? (*m_Ref) : 0;
}
};
/* ------------------------------------------------------------------------------------------------
* Parsing result.
*/
class XmlParseResult
{
// --------------------------------------------------------------------------------------------
friend class XmlDocument;
friend class XmlNode;
protected:
// --------------------------------------------------------------------------------------------
typedef xml_parse_result Result;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
XmlParseResult(const XmlDocumentRef doc, const Result & result)
: m_Doc(doc), m_Result(result)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Validate the document reference.
*/
bool Validate() const
{
if (m_Doc)
return true;
SqThrow("Invalid xml document reference");
return false;
}
private:
// ---------------------------------------------------------------------------------------------
XmlDocumentRef m_Doc; /* The main xml document instance. */
Result m_Result; /* The managed parse result. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
XmlParseResult()
: m_Doc(), m_Result()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
XmlParseResult(const XmlParseResult & o)
: m_Doc(o.m_Doc), m_Result(o.m_Result)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~XmlParseResult()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
XmlParseResult & operator = (const XmlParseResult & o)
{
m_Doc = o.m_Doc;
m_Result = o.m_Result;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const XmlParseResult & o)
{
if (m_Result.status == o.m_Result.status)
return 0;
else if (m_Result.status > o.m_Result.status)
return 1;
else
return -1;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return m_Result.description();
}
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid xml document.
*/
bool IsValid() const
{
return m_Doc;
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
Uint32 GetRefCount() const
{
return m_Doc.Count();
}
/* --------------------------------------------------------------------------------------------
* Cast to bool operator.
*/
bool IsOk() const
{
return m_Result;
}
/* --------------------------------------------------------------------------------------------
* Parsing status code.
*/
Int32 GetStatus() const
{
return m_Result.status;
}
/* --------------------------------------------------------------------------------------------
* Last parsed offset. (in char_t units from start of input data)
*/
SQInteger GetOffset() const
{
return SQInteger(m_Result.offset);
}
/* --------------------------------------------------------------------------------------------
* Source document encoding.
*/
Int32 GetEncoding() const
{
return m_Result.encoding;
}
/* --------------------------------------------------------------------------------------------
* Retrieve error description as a string.
*/
CSStr GetDescription() const
{
return m_Result.description();
}
/* --------------------------------------------------------------------------------------------
* Check the parse result and throw the necessary errors.
*/
void Check() const;
};
/* ------------------------------------------------------------------------------------------------
* A light-weight handle for manipulating attributes in DOM tree.
*/
class XmlAttribute
{
// --------------------------------------------------------------------------------------------
friend class XmlNode;
protected:
// --------------------------------------------------------------------------------------------
typedef xml_attribute Attribute;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
XmlAttribute(const XmlDocumentRef doc, const Attribute & attr)
: m_Doc(doc), m_Attr(attr)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Validate the document reference.
*/
bool Validate() const
{
if (m_Doc)
return true;
SqThrow("Invalid xml document reference");
return false;
}
private:
// ---------------------------------------------------------------------------------------------
XmlDocumentRef m_Doc; /* The main xml document instance. */
Attribute m_Attr; /* The managed node attribute. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
XmlAttribute()
: m_Doc(), m_Attr()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
XmlAttribute(const XmlAttribute & o)
: m_Doc(o.m_Doc), m_Attr(o.m_Attr)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~XmlAttribute()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
XmlAttribute & operator = (const XmlAttribute & o)
{
m_Doc = o.m_Doc;
m_Attr = o.m_Attr;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const XmlAttribute & o)
{
if (m_Attr == o.m_Attr)
return 0;
else if (m_Attr > o.m_Attr)
return 1;
else
return -1;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return m_Attr.value();
}
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid xml document.
*/
bool IsValid() const
{
return m_Doc;
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
Uint32 GetRefCount() const
{
return m_Doc.Count();
}
/* --------------------------------------------------------------------------------------------
* See whether the attribute is empty.
*/
bool IsEmpty() const
{
return m_Attr.empty();
}
/* --------------------------------------------------------------------------------------------
* Get hash value (unique for handles to the same object).
*/
SQInteger GetHashValue() const
{
return (SQInteger)m_Attr.hash_value();
}
/* --------------------------------------------------------------------------------------------
* Retrieve attribute name.
*/
CSStr GetName() const
{
return m_Attr.name();
}
/* --------------------------------------------------------------------------------------------
* Retrieve attribute name.
*/
void SetName(CSStr name)
{
if (!m_Attr.set_name(name))
SqThrow("Unable to set xml attribute name");
}
/* --------------------------------------------------------------------------------------------
* Modify the attribute name.
*/
bool ApplyName(CSStr name)
{
return m_Attr.set_name(name);
}
/* --------------------------------------------------------------------------------------------
* Retrieve attribute value.
*/
CSStr GetValue() const
{
return m_Attr.value();
}
/* --------------------------------------------------------------------------------------------
* Retrieve attribute value.
*/
void SetValue(CSStr name)
{
if (!m_Attr.set_value(name))
SqThrow("Unable to set xml attribute value");
}
/* --------------------------------------------------------------------------------------------
* Modify the attribute value.
*/
bool ApplyValue(CSStr value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a string or the specified default value if empty.
*/
CSStr AsString(CSStr def) const
{
return m_Attr.as_string(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a integer or the specified default value if empty.
*/
Int32 AsInt(Int32 def) const
{
return m_Attr.as_int(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned integer or the specified default value if empty.
*/
Uint32 AsUint(Uint32 def) const
{
return m_Attr.as_uint(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a floating point or the specified default value if empty.
*/
SQFloat AsFloat(SQFloat def) const
{
return (SQFloat)m_Attr.as_float(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a double floating point or the specified default value if empty.
*/
SQFloat AsDouble(SQFloat def) const
{
return (SQFloat)m_Attr.as_double(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a long integer or the specified default value if empty.
*/
SLongInt AsLong(const SLongInt & def) const
{
return SLongInt(m_Attr.as_llong(def.GetNum()));
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned long integer or the specified default value if empty.
*/
ULongInt AsUlong(const ULongInt & def) const
{
return ULongInt(m_Attr.as_ullong(def.GetNum()));
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a boolean or the specified default value if empty.
*/
bool AsBool(bool def) const
{
return m_Attr.as_bool(def);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a string.
*/
bool ApplyString(CSStr value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a integer.
*/
bool ApplyInt(Int32 value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned integer.
*/
bool ApplyUint(Uint32 value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a floating point.
*/
bool ApplyFloat(SQFloat value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a double floating point.
*/
bool ApplyDouble(SQFloat value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a long integer.
*/
bool ApplyLong(const SLongInt & value)
{
return m_Attr.set_value(value.GetNum());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned long integer.
*/
bool ApplyUlong(const ULongInt & value)
{
return m_Attr.set_value(value.GetNum());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a boolean.
*/
bool ApplyBool(bool value)
{
return m_Attr.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a string.
*/
CSStr GetString() const
{
return m_Attr.as_string();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a string.
*/
void SetString(CSStr value)
{
m_Attr = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a integer.
*/
Int32 GetInt() const
{
return m_Attr.as_int();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a integer.
*/
void SetInt(Int32 value)
{
m_Attr = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned integer.
*/
Uint32 GetUint() const
{
return m_Attr.as_uint();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned integer.
*/
void SetUint(Uint32 value)
{
m_Attr = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a floating point.
*/
SQFloat GetFloat() const
{
return (SQFloat)m_Attr.as_float();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a floating point.
*/
void SetFloat(SQFloat value)
{
m_Attr = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a double floating point.
*/
SQFloat GetDouble() const
{
return (SQFloat)m_Attr.as_double();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a double floating point.
*/
void SetDouble(SQFloat value)
{
m_Attr = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a long integer.
*/
SLongInt GetLong() const
{
return SLongInt(m_Attr.as_llong());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a long integer.
*/
void SetLong(const SLongInt & value)
{
m_Attr = value.GetNum();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned long integer.
*/
ULongInt GetUlong() const
{
return ULongInt(m_Attr.as_ullong());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned long integer.
*/
void SetUlong(const ULongInt & value)
{
m_Attr = value.GetNum();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a boolean.
*/
bool GetBool() const
{
return m_Attr.as_bool();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a boolean.
*/
void SetBool(bool value)
{
m_Attr = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve next attribute in the attribute list of the parent node.
*/
XmlAttribute NextAttribute() const
{
return XmlAttribute(m_Doc, m_Attr.next_attribute());
}
/* --------------------------------------------------------------------------------------------
* Retrieve previous attribute in the attribute list of the parent node.
*/
XmlAttribute PrevAttribute() const
{
return XmlAttribute(m_Doc, m_Attr.previous_attribute());
}
};
/* ------------------------------------------------------------------------------------------------
* A helper for working with text inside PCDATA nodes.
*/
class XmlText
{
// --------------------------------------------------------------------------------------------
friend class XmlNode;
protected:
// --------------------------------------------------------------------------------------------
typedef xml_text Text;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
XmlText(const XmlDocumentRef doc, const Text & text)
: m_Doc(doc), m_Text(text)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Validate the document reference.
*/
bool Validate() const
{
if (m_Doc)
return true;
SqThrow("Invalid xml document reference");
return false;
}
private:
// ---------------------------------------------------------------------------------------------
XmlDocumentRef m_Doc; /* The main xml document instance. */
Text m_Text; /* The managed document node. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
XmlText()
: m_Doc(), m_Text()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
XmlText(const XmlText & o)
: m_Doc(o.m_Doc), m_Text(o.m_Text)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~XmlText()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
XmlText & operator = (const XmlText & o)
{
m_Doc = o.m_Doc;
m_Text = o.m_Text;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const XmlText & o)
{
if (strcmp(m_Text.get(), o.m_Text.get()) == 0)
return 0;
else if (strlen(m_Text.get()) > strlen(o.m_Text.get()))
return 1;
else
return -1;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return m_Text.get();
}
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid xml document.
*/
bool IsValid() const
{
return m_Doc;
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
Uint32 GetRefCount() const
{
return m_Doc.Count();
}
/* --------------------------------------------------------------------------------------------
* See whether the text is empty.
*/
bool IsEmpty() const
{
return m_Text.empty();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the text value.
*/
CSStr GetValue() const
{
return m_Text.get();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a string or the specified default value if empty.
*/
CSStr AsString(CSStr def) const
{
return m_Text.as_string(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a integer or the specified default value if empty.
*/
Int32 AsInt(Int32 def) const
{
return m_Text.as_int(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned integer or the specified default value if empty.
*/
Uint32 AsUint(Uint32 def) const
{
return m_Text.as_uint(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a floating point or the specified default value if empty.
*/
SQFloat AsFloat(SQFloat def) const
{
return (SQFloat)m_Text.as_float(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a double floating point or the specified default value if empty.
*/
SQFloat AsDouble(SQFloat def) const
{
return (SQFloat)m_Text.as_double(def);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a long integer or the specified default value if empty.
*/
SLongInt AsLong(const SLongInt & def) const
{
return SLongInt(m_Text.as_llong(def.GetNum()));
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned long integer or the specified default value if empty.
*/
ULongInt AsUlong(const ULongInt & def) const
{
return ULongInt(m_Text.as_ullong(def.GetNum()));
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a boolean or the specified default value if empty.
*/
bool AsBool(bool def) const
{
return m_Text.as_bool(def);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a string.
*/
bool ApplyString(CSStr value)
{
return m_Text.set(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a integer.
*/
bool ApplyInt(Int32 value)
{
return m_Text.set(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned integer.
*/
bool ApplyUint(Uint32 value)
{
return m_Text.set(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a floating point.
*/
bool ApplyFloat(SQFloat value)
{
return m_Text.set(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a double floating point.
*/
bool ApplyDouble(SQFloat value)
{
return m_Text.set(value);
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a long integer.
*/
bool ApplyLong(const SLongInt & value)
{
return m_Text.set(value.GetNum());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned long integer.
*/
bool ApplyUlong(const ULongInt & value)
{
return m_Text.set(value.GetNum());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a boolean.
*/
bool ApplyBool(bool value)
{
return m_Text.set(value);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a string.
*/
CSStr GetString() const
{
return m_Text.as_string();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a string.
*/
void SetString(CSStr value)
{
m_Text = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a integer.
*/
Int32 GetInt() const
{
return m_Text.as_int();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a integer.
*/
void SetInt(Int32 value)
{
m_Text = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned integer.
*/
Uint32 GetUint() const
{
return m_Text.as_uint();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned integer.
*/
void SetUint(Uint32 value)
{
m_Text = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a floating point.
*/
SQFloat GetFloat() const
{
return (SQFloat)m_Text.as_float();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a floating point.
*/
void SetFloat(SQFloat value)
{
m_Text = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a double floating point.
*/
SQFloat GetDouble() const
{
return (SQFloat)m_Text.as_double();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a double floating point.
*/
void SetDouble(SQFloat value)
{
m_Text = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a long integer.
*/
SLongInt GetLong() const
{
return SLongInt(m_Text.as_llong());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a long integer.
*/
void SetLong(const SLongInt & value)
{
m_Text = value.GetNum();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a unsigned long integer.
*/
ULongInt GetUlong() const
{
return ULongInt(m_Text.as_ullong());
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a unsigned long integer.
*/
void SetUlong(const ULongInt & value)
{
m_Text = value.GetNum();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the value as a boolean.
*/
bool GetBool() const
{
return m_Text.as_bool();
}
/* --------------------------------------------------------------------------------------------
* Modify the value as a boolean.
*/
void SetBool(bool value)
{
m_Text = value;
}
/* --------------------------------------------------------------------------------------------
* Retrieve the data node (node_pcdata or node_cdata) for this object.
*/
XmlNode GetData() const;
};
/* ------------------------------------------------------------------------------------------------
* Class that can read/write and alter the contents of xml files.
*/
class XmlDocument
{
protected:
// --------------------------------------------------------------------------------------------
typedef xml_document Document;
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
XmlDocument(const XmlDocument & o);
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
XmlDocument & operator = (const XmlDocument & o);
/* --------------------------------------------------------------------------------------------
* Validate the document reference.
*/
bool Validate() const
{
if (m_Doc)
return true;
SqThrow("Invalid xml document reference");
return false;
}
/* --------------------------------------------------------------------------------------------
* See if the document can overwrite its contents.
*/
bool CanLoad() const
{
if (!Validate())
return false;
else if (m_Doc.Count() == 1)
return true;
SqThrow("Loading is disabled while document is referenced");
return false;
}
private:
// ---------------------------------------------------------------------------------------------
XmlDocumentRef m_Doc; /* The main xml document instance. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
XmlDocument()
: m_Doc(NULL)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~XmlDocument()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const XmlDocument & o) const
{
if (m_Doc && !o.m_Doc)
return 1;
else if (!m_Doc && o.m_Doc)
return -1;
else if (!m_Doc && !o.m_Doc)
return 0;
else if (*m_Doc == *o.m_Doc)
return 0;
else if (*m_Doc > *o.m_Doc)
return 1;
else
return -1;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
if (m_Doc)
return m_Doc->name();
return _SC("");
}
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid xml document.
*/
bool IsValid() const
{
return m_Doc;
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
Uint32 GetRefCount() const
{
return m_Doc ? *(m_Doc.m_Ref) : 0;
}
/* --------------------------------------------------------------------------------------------
* Removes all nodes, leaving the empty document.
*/
void Reset()
{
if (Validate())
m_Doc->reset();
}
/* --------------------------------------------------------------------------------------------
* Removes all nodes, then copies the entire contents of the specified document.
*/
void Reset(const XmlDocument & doc)
{
if (Validate() && doc.Validate())
m_Doc->reset(*doc.m_Doc);
}
/* --------------------------------------------------------------------------------------------
* Load document from zero-terminated string.
*/
XmlParseResult LoadString(CSStr source)
{
if (CanLoad())
return XmlParseResult(m_Doc, m_Doc->load_string(source));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Load document from zero-terminated string.
*/
XmlParseResult LoadString(CSStr source, Uint32 options)
{
if (CanLoad())
return XmlParseResult(m_Doc, m_Doc->load_string(source, options));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Load document from file on disk.
*/
XmlParseResult LoadFile(CSStr filepath)
{
if (CanLoad())
return XmlParseResult(m_Doc, m_Doc->load_file(filepath));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Load document from file on disk.
*/
XmlParseResult LoadFile(CSStr filepath, Uint32 options)
{
if (CanLoad())
return XmlParseResult(m_Doc, m_Doc->load_file(filepath, options));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Load document from file on disk.
*/
XmlParseResult LoadFile(CSStr filepath, Uint32 options, Int32 encoding)
{
if (CanLoad())
return XmlParseResult(m_Doc, m_Doc->load_file(filepath, options, (xml_encoding)encoding));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Save XML to file on disk.
*/
void SaveFile(CSStr filepath)
{
if (Validate())
m_Doc->save_file(filepath);
}
/* --------------------------------------------------------------------------------------------
* Save XML to file on disk.
*/
void SaveFile(CSStr filepath, CSStr indent)
{
if (Validate())
m_Doc->save_file(filepath, indent);
}
/* --------------------------------------------------------------------------------------------
* Save XML to file on disk.
*/
void SaveFile(CSStr filepath, CSStr indent, Uint32 format)
{
if (Validate())
m_Doc->save_file(filepath, indent, format);
}
/* --------------------------------------------------------------------------------------------
* Save XML to file on disk.
*/
void SaveFile(CSStr filepath, CSStr indent, Uint32 format, Int32 encoding)
{
if (Validate())
m_Doc->save_file(filepath, indent, format, (xml_encoding)encoding);
}
/* --------------------------------------------------------------------------------------------
* Retrieve the document root node.
*/
XmlNode GetNode() const;
};
/* ------------------------------------------------------------------------------------------------
* A light-weight handle for manipulating nodes in DOM tree.
*/
class XmlNode
{
// --------------------------------------------------------------------------------------------
friend class XmlDocument;
friend class XmlText;
protected:
// --------------------------------------------------------------------------------------------
typedef xml_node Node;
/* --------------------------------------------------------------------------------------------
* Explicit constructor.
*/
XmlNode(const XmlDocumentRef doc, const Node & node)
: m_Doc(doc), m_Node(node)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Validate the document reference.
*/
bool Validate() const
{
if (m_Doc)
return true;
SqThrow("Invalid xml document reference");
return false;
}
private:
// ---------------------------------------------------------------------------------------------
XmlDocumentRef m_Doc; /* The main xml document instance. */
Node m_Node; /* The managed document node. */
public:
/* --------------------------------------------------------------------------------------------
* Default constructor.
*/
XmlNode()
: m_Doc(), m_Node()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy constructor. (disabled)
*/
XmlNode(const XmlNode & o)
: m_Doc(o.m_Doc), m_Node(o.m_Node)
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Destructor.
*/
~XmlNode()
{
/* ... */
}
/* --------------------------------------------------------------------------------------------
* Copy assignment operator. (disabled)
*/
XmlNode & operator = (const XmlNode & o)
{
m_Doc = o.m_Doc;
m_Node = o.m_Node;
return *this;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to compare two instances of this type.
*/
Int32 Cmp(const XmlNode & o)
{
if (m_Node == o.m_Node)
return 0;
else if (m_Node > o.m_Node)
return 1;
else
return -1;
}
/* --------------------------------------------------------------------------------------------
* Used by the script engine to convert an instance of this type to a string.
*/
CSStr ToString() const
{
return m_Node.value();
}
/* --------------------------------------------------------------------------------------------
* See whether this instance references a valid xml document.
*/
bool IsValid() const
{
return m_Doc;
}
/* --------------------------------------------------------------------------------------------
* Return the number of active references to this document instance.
*/
Uint32 GetRefCount() const
{
return m_Doc.Count();
}
/* --------------------------------------------------------------------------------------------
* See whether the node is empty.
*/
bool IsEmpty() const
{
return m_Node.empty();
}
/* --------------------------------------------------------------------------------------------
* Get hash value (unique for handles to the same object).
*/
SQInteger GetHashValue() const
{
return (SQInteger)m_Node.hash_value();
}
/* --------------------------------------------------------------------------------------------
* Get node offset in parsed file/string (in char_t units) for debugging purposes.
*/
SQInteger GetOffsetDebug() const
{
return (SQInteger)m_Node.offset_debug();
}
/* --------------------------------------------------------------------------------------------
* Retrieve node type.
*/
Int32 GetType() const
{
return (Int32)m_Node.type();
}
/* --------------------------------------------------------------------------------------------
* Retrieve node name.
*/
CSStr GetName() const
{
return m_Node.name();
}
/* --------------------------------------------------------------------------------------------
* Retrieve node name.
*/
void SetName(CSStr name)
{
if (!m_Node.set_name(name))
SqThrow("Unable to set xml node name");
}
/* --------------------------------------------------------------------------------------------
* Modify the node name.
*/
bool ApplyName(CSStr name)
{
return m_Node.set_name(name);
}
/* --------------------------------------------------------------------------------------------
* Retrieve node value.
*/
CSStr GetValue() const
{
return m_Node.value();
}
/* --------------------------------------------------------------------------------------------
* Retrieve node value.
*/
void SetValue(CSStr name)
{
if (!m_Node.set_value(name))
SqThrow("Unable to set xml node value");
}
/* --------------------------------------------------------------------------------------------
* Modify the node value.
*/
bool ApplyValue(CSStr value)
{
return m_Node.set_value(value);
}
/* --------------------------------------------------------------------------------------------
* Parses buffer as an XML document fragment and appends all nodes as children of this node.
*/
XmlParseResult AppendBuffer(CSStr source)
{
if (source)
return XmlParseResult(m_Doc, m_Node.append_buffer(source,
std::char_traits< SQChar >::length(source) * sizeof(SQChar)));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Parses buffer as an XML document fragment and appends all nodes as children of this node.
*/
XmlParseResult AppendBuffer(CSStr source, Uint32 options)
{
if (source)
return XmlParseResult(m_Doc, m_Node.append_buffer(source,
std::char_traits< SQChar >::length(source) * sizeof(SQChar), options));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Parses buffer as an XML document fragment and appends all nodes as children of this node.
*/
XmlParseResult AppendBuffer(CSStr source, Uint32 options, Int32 encoding)
{
if (source)
return XmlParseResult(m_Doc, m_Node.append_buffer(source,
std::char_traits< SQChar >::length(source) * sizeof(SQChar)
, options, (xml_encoding)encoding));
return XmlParseResult();
}
/* --------------------------------------------------------------------------------------------
* Retrieve the first child attribute.
*/
XmlAttribute GetFirstAttr() const
{
return XmlAttribute(m_Doc, m_Node.first_attribute());
}
/* --------------------------------------------------------------------------------------------
* Retrieve the last child attribute.
*/
XmlAttribute GetLastAttr() const
{
return XmlAttribute(m_Doc, m_Node.last_attribute());
}
/* --------------------------------------------------------------------------------------------
* Retrieve the first child node.
*/
XmlNode GetFirstChild() const
{
return XmlNode(m_Doc, m_Node.first_child());
}
/* --------------------------------------------------------------------------------------------
* Retrieve the last child node.
*/
XmlNode GetLastChild() const
{
return XmlNode(m_Doc, m_Node.last_child());
}
/* --------------------------------------------------------------------------------------------
* Get next sibling in the children list of the parent node.
*/
XmlNode GetNextSibling() const
{
return XmlNode(m_Doc, m_Node.next_sibling());
}
/* --------------------------------------------------------------------------------------------
* Get previous sibling in the children list of the parent node
*/
XmlNode GetPrevSibling() const
{
return XmlNode(m_Doc, m_Node.previous_sibling());
}
/* --------------------------------------------------------------------------------------------
* Retrieve the parent node.
*/
XmlNode GetParent() const
{
return XmlNode(m_Doc, m_Node.parent());
}
/* --------------------------------------------------------------------------------------------
* Retrieve the root node.
*/
XmlNode GetRoot() const
{
return XmlNode(m_Doc, m_Node.root());
}
/* --------------------------------------------------------------------------------------------
* Retrieve the text object for the current node.
*/
XmlText GetText() const
{
return XmlText(m_Doc, m_Node.text());
}
/* --------------------------------------------------------------------------------------------
* Retrieve child node with the specified name.
*/
XmlNode Child(CSStr name) const
{
return XmlNode(m_Doc, m_Node.child(name));
}
/* --------------------------------------------------------------------------------------------
* Retrieve child attribute with the specified name.
*/
XmlAttribute Attribute(CSStr name) const
{
return XmlAttribute(m_Doc, m_Node.attribute(name));
}
/* --------------------------------------------------------------------------------------------
* Retrieve next sibling with the specified name.
*/
XmlNode NextSibling(CSStr name) const
{
return XmlNode(m_Doc, m_Node.next_sibling(name));
}
/* --------------------------------------------------------------------------------------------
* Retrieve previous sibling with the specified name.
*/
XmlNode PrevSibling(CSStr name) const
{
return XmlNode(m_Doc, m_Node.previous_sibling(name));
}
/* --------------------------------------------------------------------------------------------
* Retrieve child attribute, starting the search from a hint.
*/
XmlAttribute AttributeFrom(CSStr name, XmlAttribute & attr) const
{
return XmlAttribute(m_Doc, m_Node.attribute(name, attr.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Get child value of current node; that is, value of the first child node of type PCDATA/CDATA.
*/
CSStr GetChildValue() const
{
return m_Node.child_value();
}
/* --------------------------------------------------------------------------------------------
* Retrieve child value of child with specified name.
*/
CSStr ChildValue(CSStr name) const
{
return m_Node.child_value(name);
}
/* --------------------------------------------------------------------------------------------
* Append a child attribute with the specified name.
*/
XmlAttribute AppendAttr(CSStr name)
{
return XmlAttribute(m_Doc, m_Node.append_attribute(name));
}
/* --------------------------------------------------------------------------------------------
* Prepend a child attribute with the specified name.
*/
XmlAttribute PrependAttr(CSStr name)
{
return XmlAttribute(m_Doc, m_Node.prepend_attribute(name));
}
/* --------------------------------------------------------------------------------------------
* Insert a child attribute with the specified name, after the specified node.
*/
XmlAttribute InsertAttrAfter(CSStr name, const XmlAttribute & attr)
{
return XmlAttribute(m_Doc, m_Node.insert_attribute_after(name, attr.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Insert a child attribute with the specified name, before the specified node.
*/
XmlAttribute InsertAttrBefore(CSStr name, const XmlAttribute & attr)
{
return XmlAttribute(m_Doc, m_Node.insert_attribute_before(name, attr.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Append a copy of the specified attribute as a child.
*/
XmlAttribute AppendAttrCopy(const XmlAttribute & proto)
{
return XmlAttribute(m_Doc, m_Node.append_copy(proto.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Prepend a copy of the specified attribute as a child.
*/
XmlAttribute PrependAttrCopy(const XmlAttribute & proto)
{
return XmlAttribute(m_Doc, m_Node.prepend_copy(proto.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Insert a copy of the specified attribute as a child after the specified attribute.
*/
XmlAttribute InsertAttrCopyAfter(const XmlAttribute & proto, const XmlAttribute & attr)
{
return XmlAttribute(m_Doc, m_Node.insert_copy_after(proto.m_Attr, attr.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Insert a copy of the specified attribute as a child before the specified attribute.
*/
XmlAttribute InsertAttrCopyBefore(const XmlAttribute & proto, const XmlAttribute & attr)
{
return XmlAttribute(m_Doc, m_Node.insert_copy_before(proto.m_Attr, attr.m_Attr));
}
/* --------------------------------------------------------------------------------------------
* Append a basic child node with the specified name.
*/
XmlNode AppendChild(CSStr name)
{
return XmlNode(m_Doc, m_Node.append_child(name));
}
/* --------------------------------------------------------------------------------------------
* Prepend a basic child node with the specified name.
*/
XmlNode PrependChild(CSStr name)
{
return XmlNode(m_Doc, m_Node.prepend_child(name));
}
/* --------------------------------------------------------------------------------------------
* Append a basic child node.
*/
XmlNode AppendChildNode()
{
return XmlNode(m_Doc, m_Node.append_child());
}
/* --------------------------------------------------------------------------------------------
* Prepend a basic child node.
*/
XmlNode PrependChildNode()
{
return XmlNode(m_Doc, m_Node.prepend_child());
}
/* --------------------------------------------------------------------------------------------
* Append a basic child node with the specified type.
*/
XmlNode AppendChildType(Int32 type)
{
return XmlNode(m_Doc, m_Node.append_child((xml_node_type)type));
}
/* --------------------------------------------------------------------------------------------
* Prepend a basic child node with the specified type.
*/
XmlNode PrependChildType(Int32 type)
{
return XmlNode(m_Doc, m_Node.prepend_child((xml_node_type)type));
}
/* --------------------------------------------------------------------------------------------
* Insert a basic child node with the specified name, after the specified node.
*/
XmlNode InsertChildAfter(CSStr name, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_child_after(name, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert a basic child node with the specified name, before the specified node.
*/
XmlNode InsertChildBefore(CSStr name, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_child_before(name, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert a basic child node with the specified type, after the specified node.
*/
XmlNode InsertChildTypeAfter(Int32 type, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_child_after((xml_node_type)type, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert a basic child node with the specified type, before the specified node.
*/
XmlNode InsertChildTypeBefore(Int32 type, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_child_before((xml_node_type)type, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Append a copy of the specified node as a child.
*/
XmlNode AppendCopy(const XmlNode & proto)
{
return XmlNode(m_Doc, m_Node.append_copy(proto.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Prepend a copy of the specified node as a child.
*/
XmlNode PrependCopy(const XmlNode & proto)
{
return XmlNode(m_Doc, m_Node.prepend_copy(proto.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert a copy of the specified node as a child after the specified node.
*/
XmlNode InsertCopyAfter(const XmlNode & proto, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_copy_after(proto.m_Node, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert a copy of the specified node as a child before the specified node.
*/
XmlNode InsertCopyBefore(const XmlNode & proto, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_copy_before(proto.m_Node, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Append the specified node as a child and take ownersip of it.
*/
XmlNode AppendMove(const XmlNode & proto)
{
return XmlNode(m_Doc, m_Node.append_copy(proto.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Prepend the specified node as a child and take ownersip of it.
*/
XmlNode PrependMove(const XmlNode & proto)
{
return XmlNode(m_Doc, m_Node.prepend_copy(proto.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert the specified node as a child after the specified node and take ownersip of it.
*/
XmlNode InsertMoveAfter(const XmlNode & proto, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_copy_after(proto.m_Node, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Insert the specified node as a child before the specified node and take ownersip of it.
*/
XmlNode InsertMoveBefore(const XmlNode & proto, const XmlNode & node)
{
return XmlNode(m_Doc, m_Node.insert_copy_before(proto.m_Node, node.m_Node));
}
/* --------------------------------------------------------------------------------------------
* Remove the child attribute matching the specified name.
*/
bool RemoveAttr(CSStr name)
{
return m_Node.remove_attribute(name);
}
/* --------------------------------------------------------------------------------------------
* Remove the specified attribute.
*/
bool RemoveAttrInst(const XmlAttribute & attr)
{
return m_Node.remove_attribute(attr.m_Attr);
}
/* --------------------------------------------------------------------------------------------
* Remove the child node matching the specified name.
*/
bool RemoveChild(CSStr name)
{
return m_Node.remove_child(name);
}
/* --------------------------------------------------------------------------------------------
* Remove the specified node.
*/
bool RemoveChildInst(const XmlNode & node)
{
return m_Node.remove_child(node.m_Node);
}
/* --------------------------------------------------------------------------------------------
* Find child node by attribute name/value.
*/
XmlNode FindChildByAttr(CSStr attr_name, CSStr attr_value) const
{
return XmlNode(m_Doc, m_Node.find_child_by_attribute(attr_name, attr_value));
}
/* --------------------------------------------------------------------------------------------
* Find child node by attribute name/value.
*/
XmlNode FindChildByAttr(CSStr name, CSStr attr_name, CSStr attr_value) const
{
return XmlNode(m_Doc, m_Node.find_child_by_attribute(name, attr_name, attr_value));
}
/* --------------------------------------------------------------------------------------------
* Search for a node by path consisting of node names and . or .. elements.
*/
XmlNode FindElemByPath(CSStr path, SQChar delimiter) const
{
return XmlNode(m_Doc, m_Node.first_element_by_path(path, delimiter));
}
};
} // Namespace:: XML
} // Namespace:: SqMod
#endif // _LIBRARY_XML_HPP_