/****************************************************************************/
/*! \mainpage XMLParser library
* \section intro_sec Introduction
*
* This is a basic XML parser written in ANSI C++ for portability.
* It works by using recursion and a node tree for breaking
* down the elements of an XML document.
*
* @version V2.41
* @author Frank Vanden Berghen
*
* The following license terms for the "XMLParser library from Business-Insight"
*apply to projects that are in some way related to the "mcpat project",
*including applications using "mcpat project" and tools developed for enhancing
*"mcpat project". All other projects (not related to "mcpat project") have to
*use the "XMLParser library from Business-Insight" code under the Aladdin Free
*Public License (AFPL) See the file "AFPL-license.txt" for more informations
*about the AFPL license. (see http://www.artifex.com/downloads/doc/Public.htm
*for detailed AFPL terms)
*
* Redistribution and use of the "XMLParser library from Business-Insight" in
*source and binary forms, with or without modification, are permitted provided
*that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of Frank Vanden Berghen nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY Business-Insight ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL Business-Insight BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright (c) 2002, Business-Insight
* Business-Insight
* All rights reserved.
*
* \section tutorial First Tutorial
* You can follow a simple Tutorial to know
*the basics...
*
* \section usage General usage: How to include the XMLParser library inside
*your project.
*
* The library is composed of two files: xmlParser.cpp and xmlParser.h. These are the ONLY 2 files that you
*need when using the library inside your own projects.
*
* All the functions of the library are documented inside the comments of the
*file xmlParser.h. These comments can be
*transformed in full-fledged HTML documentation using the DOXYGEN software:
*simply type: "doxygen doxy.cfg"
*
* By default, the XMLParser library uses (char*) for string representation.To
*use the (wchar_t*) version of the library, you need to define the "_UNICODE"
*preprocessor definition variable (this is usually done inside your project
*definition file) (This is done automatically for you when using Visual
*Studio).
*
* \section example Advanced Tutorial and Many Examples of usage.
*
* Some very small introductory examples are described inside the Tutorial file
* xmlParser.html
*
* Some additional small examples are also inside the file xmlTest.cpp (for the "char*" version of the
*library) and inside the file xmlTestUnicode.cpp (for the "wchar_t*"
* version of the library). If you have a question, please review these
*additionnal examples before sending an e-mail to the author.
*
* To build the examples:
* - linux/unix: type "make"
* - solaris: type "make -f makefile.solaris"
* - windows: Visual Studio: double-click on xmlParser.dsw
* (under Visual Studio .NET, the .dsp and .dsw files will be automatically
*converted to .vcproj and .sln files)
*
* In order to build the examples you need some additional files:
* - linux/unix: makefile
* - solaris: makefile.solaris
* - windows: Visual Studio: *.dsp, xmlParser.dsw and also xmlParser.lib and
*xmlParser.dll
*
* \section debugging Debugging with the XMLParser library
*
* \subsection debugwin Debugging under WINDOWS
*
* Inside Visual C++, the "debug versions" of the memory allocation
*functions are very slow: Do not forget to compile in "release mode" to get
*maximum speed. When I had to debug a software that was using the XMLParser
*Library, it was usually a nightmare because the library was sooOOOoooo slow in
*debug mode (because of the slow memory allocations in Debug mode). To solve
*this problem, during all the debugging session, I am now using a very fast DLL
*version of the XMLParser Library (the DLL is compiled in release mode). Using
*the DLL version of the XMLParser Library allows me to have lightening XML
*parsing speed even in debug! Other than that, the DLL version is useless: In
*the release version of my tool, I always use the normal, ".cpp"-based,
*XMLParser Library (I simply include the xmlParser.cpp and xmlParser.h files into the project).
*
* The file XMLNodeAutoexp.txt
*contains some "tweaks" that improve substancially the display of the content
*of the XMLNode objects inside the Visual Studio Debugger. Believe me, once you
*have seen inside the debugger the "smooth" display of the XMLNode objects, you
*cannot live without it anymore!
*
* \subsection debuglinux Debugging under LINUX/UNIX
*
* The speed of the debug version of the XMLParser library is tolerable so
*no extra work.has been done.
*
****************************************************************************/
#ifndef __INCLUDE_XML_NODE__
#define __INCLUDE_XML_NODE__
#include
#ifdef _UNICODE
// If you comment the next "define" line then the library will never "switch to"
// _UNICODE (wchar_t*) mode (16/32 bits per characters). This is useful when you
// get error messages like:
// 'XMLNode::openFileHelper' : cannot convert parameter 2 from 'const char
// [5]' to 'const wchar_t *'
// The _XMLWIDECHAR preprocessor variable force the XMLParser library into
// either utf16/32-mode (the proprocessor variable must be defined) or
// utf8-mode(the pre-processor variable must be undefined).
#define _XMLWIDECHAR
#endif
#if defined(WIN32) || defined(UNDER_CE) || defined(_WIN32) || \
defined(WIN64) || defined(__BORLANDC__)
// comment the next line if you are under windows and the compiler is not
// Microsoft Visual Studio (6.0 or .NET) or Borland
#define _XMLWINDOWS
#endif
#ifdef XMLDLLENTRY
#undef XMLDLLENTRY
#endif
#ifdef _USE_XMLPARSER_DLL
#ifdef _DLL_EXPORTS_
#define XMLDLLENTRY __declspec(dllexport)
#else
#define XMLDLLENTRY __declspec(dllimport)
#endif
#else
#define XMLDLLENTRY
#endif
// uncomment the next line if you want no support for wchar_t* (no need for the
// or libraries anymore to compile)
// #define XML_NO_WIDE_CHAR
#ifdef XML_NO_WIDE_CHAR
#undef _XMLWINDOWS
#undef _XMLWIDECHAR
#endif
#ifdef _XMLWINDOWS
#include
#else
#define XMLDLLENTRY
#ifndef XML_NO_WIDE_CHAR
#include // to have 'wcsrtombs' for ANSI version
// to have 'mbsrtowcs' for WIDECHAR version
#endif
#endif
// Some common types for char set portable code
#ifdef _XMLWIDECHAR
#define _CXML(c) L##c
#define XMLCSTR const wchar_t *
#define XMLSTR wchar_t *
#define XMLCHAR wchar_t
#else
#define _CXML(c) c
#define XMLCSTR const char *
#define XMLSTR char *
#define XMLCHAR char
#endif
#ifndef FALSE
#define FALSE 0
#endif /* FALSE */
#ifndef TRUE
#define TRUE 1
#endif /* TRUE */
/// Enumeration for XML parse errors.
typedef enum XMLError {
eXMLErrorNone = 0,
eXMLErrorMissingEndTag,
eXMLErrorNoXMLTagFound,
eXMLErrorEmpty,
eXMLErrorMissingTagName,
eXMLErrorMissingEndTagName,
eXMLErrorUnmatchedEndTag,
eXMLErrorUnmatchedEndClearTag,
eXMLErrorUnexpectedToken,
eXMLErrorNoElements,
eXMLErrorFileNotFound,
eXMLErrorFirstTagNotFound,
eXMLErrorUnknownCharacterEntity,
eXMLErrorCharacterCodeAbove255,
eXMLErrorCharConversionError,
eXMLErrorCannotOpenWriteFile,
eXMLErrorCannotWriteFile,
eXMLErrorBase64DataSizeIsNotMultipleOf4,
eXMLErrorBase64DecodeIllegalCharacter,
eXMLErrorBase64DecodeTruncatedData,
eXMLErrorBase64DecodeBufferTooSmall
} XMLError;
/// Enumeration used to manage type of data. Use in conjunction with structure
/// XMLNodeContents
typedef enum XMLElementType {
eNodeChild = 0,
eNodeAttribute = 1,
eNodeText = 2,
eNodeClear = 3,
eNodeNULL = 4
} XMLElementType;
/// Structure used to obtain error details if the parse fails.
typedef struct XMLResults {
enum XMLError error;
int nLine, nColumn;
} XMLResults;
/// Structure for XML clear (unformatted) node (usually comments)
typedef struct XMLClear {
XMLCSTR lpszValue;
XMLCSTR lpszOpenTag;
XMLCSTR lpszCloseTag;
} XMLClear;
/// Structure for XML attribute.
typedef struct XMLAttribute {
XMLCSTR lpszName;
XMLCSTR lpszValue;
} XMLAttribute;
/// XMLElementPosition are not interchangeable with simple indexes
typedef int XMLElementPosition;
struct XMLNodeContents;
/** @defgroup XMLParserGeneral The XML parser */
/// Main Class representing a XML node
/**
* All operations are performed using this class.
* \note The constructors of the XMLNode class are protected, so use instead one
* of these four methods to get your first instance of XMLNode: -
* XMLNode::parseString
- XMLNode::parseFile
-
* XMLNode::openFileHelper
- XMLNode::createXMLTopNode (or
* XMLNode::createXMLTopNode_WOSD)
*
*/
typedef struct XMLDLLENTRY XMLNode {
private:
struct XMLNodeDataTag;
/// Constructors are protected, so use instead one of: XMLNode::parseString,
/// XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
XMLNode(struct XMLNodeDataTag *pParent, XMLSTR lpszName, char isDeclaration);
/// Constructors are protected, so use instead one of: XMLNode::parseString,
/// XMLNode::parseFile, XMLNode::openFileHelper, XMLNode::createXMLTopNode
XMLNode(struct XMLNodeDataTag *p);
public:
static XMLCSTR getVersion(); ///< Return the XMLParser library version number
/** @defgroup conversions Parsing XML files/strings to an XMLNode structure
* and Rendering XMLNode's to files/string.
* @ingroup XMLParserGeneral
* @{ */
/// Parse an XML string and return the root of a XMLNode tree representing the
/// string.
static XMLNode parseString(XMLCSTR lpXMLString, XMLCSTR tag = NULL,
XMLResults *pResults = NULL);
/**< The "parseString" function parse an XML string and return the root of a
* XMLNode tree. The "opposite" of this function is the function
* "createXMLString" that re-creates an XML string from an XMLNode tree. If
* the XML document is corrupted, the "parseString" method will initialize the
* "pResults" variable with some information that can be used to trace the
* error. If you still want to parse the file, you can use the
* APPROXIMATE_PARSING option as explained inside the note at the beginning of
* the "xmlParser.cpp" file.
*
* @param lpXMLString the XML string to parse
* @param tag the name of the first tag inside the XML file. If the tag
* parameter is omitted, this function returns a node that represents the head
* of the xml document including the declaration term ( ... ?>).
* @param pResults a pointer to a XMLResults variable that will contain some
* information that can be used to trace the XML parsing error. You can have a
* user-friendly explanation of the parsing error with the "getError"
* function.
*/
/// Parse an XML file and return the root of a XMLNode tree representing the
/// file.
static XMLNode parseFile(XMLCSTR filename, XMLCSTR tag = NULL,
XMLResults *pResults = NULL);
/**< The "parseFile" function parse an XML file and return the root of a
* XMLNode tree. The "opposite" of this function is the function "writeToFile"
* that re-creates an XML file from an XMLNode tree. If the XML document is
* corrupted, the "parseFile" method will initialize the "pResults" variable
* with some information that can be used to trace the error. If you still
* want to parse the file, you can use the APPROXIMATE_PARSING option as
* explained inside the note at the beginning of the "xmlParser.cpp" file.
*
* @param filename the path to the XML file to parse
* @param tag the name of the first tag inside the XML file. If the tag
* parameter is omitted, this function returns a node that represents the head
* of the xml document including the declaration term ( ... ?>).
* @param pResults a pointer to a XMLResults variable that will contain some
* information that can be used to trace the XML parsing error. You can have a
* user-friendly explanation of the parsing error with the "getError"
* function.
*/
/// Parse an XML file and return the root of a XMLNode tree representing the
/// file. A very crude error checking is made. An attempt to guess the Char
/// Encoding used in the file is made.
static XMLNode openFileHelper(XMLCSTR filename, XMLCSTR tag = NULL);
/**< The "openFileHelper" function reports to the screen all the warnings and
* errors that occurred during parsing of the XML file. This function also
* tries to guess char Encoding (UTF-8, ASCII or SHIT-JIS) based on the first
* 200 bytes of the file. Since each application has its own way to report and
* deal with errors, you should rather use the "parseFile" function to parse
* XML files and program yourself thereafter an "error reporting" tailored for
* your needs (instead of using the very crude "error reporting" mechanism
* included inside the "openFileHelper" function).
*
* If the XML document is corrupted, the "openFileHelper" method will:
* - display an error message on the console (or inside a messageBox
* for windows).
* - stop execution (exit).
*
* I strongly suggest that you write your own "openFileHelper" method tailored
* to your needs. If you still want to parse the file, you can use the
* APPROXIMATE_PARSING option as explained inside the note at the beginning of
* the "xmlParser.cpp" file.
*
* @param filename the path of the XML file to parse.
* @param tag the name of the first tag inside the XML file. If the tag
* parameter is omitted, this function returns a node that represents the head
* of the xml document including the declaration term ( ... ?>).
*/
static XMLCSTR getError(
XMLError error); ///< this gives you a user-friendly explanation of the
///< parsing error
/// Create an XML string starting from the current XMLNode.
XMLSTR createXMLString(int nFormat = 1, int *pnSize = NULL) const;
/**< The returned string should be free'd using the "freeXMLString" function.
*
* If nFormat==0, no formatting is required otherwise this returns an user
* friendly XML string from a given element
* with appropriate white spaces and carriage returns. if pnSize is given it
* returns the size in character of the string. */
/// Save the content of an xmlNode inside a file
XMLError writeToFile(XMLCSTR filename, const char *encoding = NULL,
char nFormat = 1) const;
/**< If nFormat==0, no formatting is required otherwise this returns an user
* friendly XML string from a given element with appropriate white spaces and
* carriage returns. If the global parameter
* "characterEncoding==encoding_UTF8", then the "encoding" parameter is
* ignored and always set to "utf-8". If the global parameter
* "characterEncoding==encoding_ShiftJIS", then the "encoding" parameter is
* ignored and always set to "SHIFT-JIS". If "_XMLWIDECHAR=1", then the
* "encoding" parameter is ignored and always set to "utf-16". If no
* "encoding" parameter is given the "ISO-8859-1" encoding is used. */
/** @} */
/** @defgroup navigate Navigate the XMLNode structure
* @ingroup XMLParserGeneral
* @{ */
XMLCSTR getName() const; ///< name of the node
XMLCSTR getText(int i = 0) const; ///< return ith text field
int nText() const; ///< nbr of text field
XMLNode getParentNode() const; ///< return the parent node
XMLNode getChildNode(int i = 0) const; ///< return ith child node
XMLNode getChildNode(XMLCSTR name, int i)
const; ///< return ith child node with specific name (return an empty
///< node if failing). If i==-1, this returns the last XMLNode
///< with the given name.
XMLNode getChildNode(XMLCSTR name, int *i = NULL)
const; ///< return next child node with specific name (return an empty
///< node if failing)
XMLNode getChildNodeWithAttribute(
XMLCSTR tagName, XMLCSTR attributeName, XMLCSTR attributeValue = NULL,
int *i = NULL) const; ///< return child node with specific name/attribute
///< (return an empty node if failing)
XMLNode getChildNodeByPath(XMLCSTR path, char createNodeIfMissing = 0,
XMLCHAR sep = '/');
///< return the first child node with specific path
XMLNode getChildNodeByPathNonConst(XMLSTR path, char createNodeIfMissing = 0,
XMLCHAR sep = '/');
///< return the first child node with specific path.
int nChildNode(XMLCSTR name)
const; ///< return the number of child node with specific name
int nChildNode() const; ///< nbr of child node
XMLAttribute getAttribute(int i = 0) const; ///< return ith attribute
XMLCSTR getAttributeName(int i = 0) const; ///< return ith attribute name
XMLCSTR getAttributeValue(int i = 0) const; ///< return ith attribute value
char isAttributeSet(XMLCSTR name)
const; ///< test if an attribute with a specific name is given
XMLCSTR getAttribute(
XMLCSTR name, int i) const; ///< return ith attribute content with
///< specific name (return a NULL if failing)
XMLCSTR getAttribute(XMLCSTR name, int *i = NULL)
const; ///< return next attribute content with specific name (return a
///< NULL if failing)
int nAttribute() const; ///< nbr of attribute
XMLClear getClear(int i = 0) const; ///< return ith clear field (comments)
int nClear() const; ///< nbr of clear field
XMLNodeContents enumContents(XMLElementPosition i)
const; ///< enumerate all the different contents (attribute,child,text,
///< clear) of the current XMLNode. The order is reflecting the
///< order of the original file/string. NOTE: 0 <= i < nElement();
int nElement() const; ///< nbr of different contents for current node
char isEmpty() const; ///< is this node Empty?
char isDeclaration() const; ///< is this node a declaration .... ?>
XMLNode deepCopy() const; ///< deep copy (duplicate/clone) a XMLNode
static XMLNode emptyNode(); ///< return XMLNode::emptyXMLNode;
/** @} */
~XMLNode();
XMLNode(const XMLNode &A); ///< to allow shallow/fast copy:
XMLNode &operator=(const XMLNode &A); ///< to allow shallow/fast copy:
XMLNode() : d(NULL){};
static XMLNode emptyXMLNode;
static XMLClear emptyXMLClear;
static XMLAttribute emptyXMLAttribute;
/** @defgroup xmlModify Create or Update the XMLNode structure
* @ingroup XMLParserGeneral
* The functions in this group allows you to create from scratch (or update)
* a XMLNode structure. Start by creating your top node with the
* "createXMLTopNode" function and then add new nodes with the "addChild"
* function. The parameter 'pos' gives the position where the childNode, the
* text or the XMLClearTag will be inserted. The default value (pos=-1)
* inserts at the end. The value (pos=0) insert at the beginning (Insertion at
* the beginning is slower than at the end).
*
* REMARK: 0 <= pos < nChild()+nText()+nClear()
*/
/** @defgroup creation Creating from scratch a XMLNode structure
* @ingroup xmlModify
* @{ */
static XMLNode createXMLTopNode(
XMLCSTR lpszName,
char isDeclaration =
FALSE); ///< Create the top node of an XMLNode structure
XMLNode addChild(XMLCSTR lpszName, char isDeclaration = FALSE,
XMLElementPosition pos = -1); ///< Add a new child node
XMLNode addChild(XMLNode nodeToAdd,
XMLElementPosition pos =
-1); ///< If the "nodeToAdd" has some parents, it will
///< be detached from it's parents before being
///< attached to the current XMLNode
XMLAttribute *addAttribute(XMLCSTR lpszName,
XMLCSTR lpszValuev); ///< Add a new attribute
XMLCSTR addText(XMLCSTR lpszValue,
XMLElementPosition pos = -1); ///< Add a new text content
XMLClear *addClear(XMLCSTR lpszValue, XMLCSTR lpszOpen = NULL,
XMLCSTR lpszClose = NULL, XMLElementPosition pos = -1);
/**< Add a new clear tag
* @param lpszOpen default value ""
*/
/** @} */
/** @defgroup xmlUpdate Updating Nodes
* @ingroup xmlModify
* Some update functions:
* @{
*/
XMLCSTR updateName(XMLCSTR lpszName); ///< change node's name
XMLAttribute *updateAttribute(
XMLAttribute *newAttribute,
XMLAttribute *oldAttribute); ///< if the attribute to update is missing,
///< a new one will be added
XMLAttribute *updateAttribute(
XMLCSTR lpszNewValue, XMLCSTR lpszNewName = NULL,
int i = 0); ///< if the attribute to update is missing, a new one will be
///< added
XMLAttribute *updateAttribute(
XMLCSTR lpszNewValue, XMLCSTR lpszNewName,
XMLCSTR
lpszOldName); ///< set lpszNewName=NULL if you don't want to change
///< the name of the attribute if the attribute to
///< update is missing, a new one will be added
XMLCSTR updateText(XMLCSTR lpszNewValue,
int i = 0); ///< if the text to update is missing, a new
///< one will be added
XMLCSTR updateText(
XMLCSTR lpszNewValue,
XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one
///< will be added
XMLClear *updateClear(XMLCSTR lpszNewContent,
int i = 0); ///< if the clearTag to update is missing,
///< a new one will be added
XMLClear *updateClear(XMLClear *newP,
XMLClear *oldP); ///< if the clearTag to update is
///< missing, a new one will be added
XMLClear *updateClear(
XMLCSTR lpszNewValue,
XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new
///< one will be added
/** @} */
/** @defgroup xmlDelete Deleting Nodes or Attributes
* @ingroup xmlModify
* Some deletion functions:
* @{
*/
/// The "deleteNodeContent" function forces the deletion of the content of
/// this XMLNode and the subtree.
void deleteNodeContent();
/**< \note The XMLNode instances that are referring to the part of the subtree
* that has been deleted CANNOT be used anymore!!. Unexpected results will
* occur if you continue using them. */
void deleteAttribute(
int i = 0); ///< Delete the ith attribute of the current XMLNode
void deleteAttribute(
XMLCSTR lpszName); ///< Delete the attribute with the given name (the
///< "strcmp" function is used to find the right
///< attribute)
void deleteAttribute(
XMLAttribute
*anAttribute); ///< Delete the attribute with the name
///< "anAttribute->lpszName" (the "strcmp" function is
///< used to find the right attribute)
void deleteText(
int i = 0); ///< Delete the Ith text content of the current XMLNode
void deleteText(
XMLCSTR lpszValue); ///< Delete the text content "lpszValue" inside the
///< current XMLNode (direct "pointer-to-pointer"
///< comparison is used to find the right text)
void deleteClear(
int i = 0); ///< Delete the Ith clear tag inside the current XMLNode
void deleteClear(
XMLCSTR lpszValue); ///< Delete the clear tag "lpszValue" inside the
///< current XMLNode (direct "pointer-to-pointer"
///< comparison is used to find the clear tag)
void deleteClear(
XMLClear
*p); ///< Delete the clear tag "p" inside the current XMLNode (direct
///< "pointer-to-pointer" comparison on the lpszName of the
///< clear tag is used to find the clear tag)
/** @} */
/** @defgroup xmlWOSD ???_WOSD functions.
* @ingroup xmlModify
* The strings given as parameters for the "add" and "update" methods that
* have a name with the postfix "_WOSD" (that means "WithOut String
* Duplication")(for example "addText_WOSD") will be free'd by the XMLNode
* class. For example, it means that this is incorrect: \code
* xNode.addText_WOSD("foo");
* xNode.updateAttribute_WOSD("#newcolor" ,NULL,"color");
* \endcode
* In opposition, this is correct:
* \code
* xNode.addText("foo");
* xNode.addText_WOSD(stringDup("foo"));
* xNode.updateAttribute("#newcolor" ,NULL,"color");
* xNode.updateAttribute_WOSD(stringDup("#newcolor"),NULL,"color");
* \endcode
* Typically, you will never do:
* \code
* char *b=(char*)malloc(...);
* xNode.addText(b);
* free(b);
* \endcode
* ... but rather:
* \code
* char *b=(char*)malloc(...);
* xNode.addText_WOSD(b);
* \endcode
* ('free(b)' is performed by the XMLNode class)
* @{ */
static XMLNode createXMLTopNode_WOSD(
XMLSTR lpszName,
char isDeclaration =
FALSE); ///< Create the top node of an XMLNode structure
XMLNode addChild_WOSD(XMLSTR lpszName, char isDeclaration = FALSE,
XMLElementPosition pos = -1); ///< Add a new child node
XMLAttribute *addAttribute_WOSD(XMLSTR lpszName,
XMLSTR lpszValue); ///< Add a new attribute
XMLCSTR addText_WOSD(XMLSTR lpszValue, XMLElementPosition pos =
-1); ///< Add a new text content
XMLClear *addClear_WOSD(
XMLSTR lpszValue, XMLCSTR lpszOpen = NULL, XMLCSTR lpszClose = NULL,
XMLElementPosition pos = -1); ///< Add a new clear Tag
XMLCSTR updateName_WOSD(XMLSTR lpszName); ///< change node's name
XMLAttribute *updateAttribute_WOSD(
XMLAttribute *newAttribute,
XMLAttribute *oldAttribute); ///< if the attribute to update is missing,
///< a new one will be added
XMLAttribute *updateAttribute_WOSD(
XMLSTR lpszNewValue, XMLSTR lpszNewName = NULL,
int i = 0); ///< if the attribute to update is missing, a new one will be
///< added
XMLAttribute *updateAttribute_WOSD(
XMLSTR lpszNewValue, XMLSTR lpszNewName,
XMLCSTR
lpszOldName); ///< set lpszNewName=NULL if you don't want to change
///< the name of the attribute if the attribute to
///< update is missing, a new one will be added
XMLCSTR updateText_WOSD(XMLSTR lpszNewValue,
int i = 0); ///< if the text to update is missing, a
///< new one will be added
XMLCSTR updateText_WOSD(
XMLSTR lpszNewValue,
XMLCSTR lpszOldValue); ///< if the text to update is missing, a new one
///< will be added
XMLClear *updateClear_WOSD(XMLSTR lpszNewContent,
int i = 0); ///< if the clearTag to update is
///< missing, a new one will be added
XMLClear *updateClear_WOSD(
XMLClear *newP, XMLClear *oldP); ///< if the clearTag to update is
///< missing, a new one will be added
XMLClear *updateClear_WOSD(
XMLSTR lpszNewValue,
XMLCSTR lpszOldValue); ///< if the clearTag to update is missing, a new
///< one will be added
/** @} */
/** @defgroup xmlPosition Position helper functions (use in conjunction with
* the update&add functions
* @ingroup xmlModify
* These are some useful functions when you want to insert a childNode, a text
* or a XMLClearTag in the middle (at a specified position) of a XMLNode tree
* already constructed. The value returned by these methods is to be used as
* last parameter (parameter 'pos') of addChild, addText or addClear.
* @{ */
XMLElementPosition positionOfText(int i = 0) const;
XMLElementPosition positionOfText(XMLCSTR lpszValue) const;
XMLElementPosition positionOfClear(int i = 0) const;
XMLElementPosition positionOfClear(XMLCSTR lpszValue) const;
XMLElementPosition positionOfClear(XMLClear *a) const;
XMLElementPosition positionOfChildNode(int i = 0) const;
XMLElementPosition positionOfChildNode(XMLNode x) const;
XMLElementPosition positionOfChildNode(XMLCSTR name, int i = 0)
const; ///< return the position of the ith childNode with the specified
///< name if (name==NULL) return the position of the ith childNode
/** @} */
/// Enumeration for XML character encoding.
typedef enum XMLCharEncoding {
char_encoding_error = 0,
char_encoding_UTF8 = 1,
char_encoding_legacy = 2,
char_encoding_ShiftJIS = 3,
char_encoding_GB2312 = 4,
char_encoding_Big5 = 5,
char_encoding_GBK = 6 // this is actually the same as Big5
} XMLCharEncoding;
/** \addtogroup conversions
* @{ */
/// Sets the global options for the conversions
static char setGlobalOptions(
XMLCharEncoding characterEncoding = XMLNode::char_encoding_UTF8,
char guessWideCharChars = 1, char dropWhiteSpace = 1,
char removeCommentsInMiddleOfText = 1);
/**< The "setGlobalOptions" function allows you to change four global
* parameters that affect string & file parsing. First of all, you
* most-probably will never have to change these 3 global parameters.
*
* @param guessWideCharChars If "guessWideCharChars"=1 and if this library is
* compiled in WideChar mode, then the XMLNode::parseFile and
* XMLNode::openFileHelper functions will test if the file contains ASCII
* characters. If this is the case, then the file will be loaded and
* converted in memory to WideChar before being parsed. If 0, no conversion
* will be performed.
*
* @param guessWideCharChars If "guessWideCharChars"=1 and if this library is
* compiled in ASCII/UTF8/char* mode, then the XMLNode::parseFile and
* XMLNode::openFileHelper functions will test if the file contains WideChar
* characters. If this is the case, then the file will be loaded and
* converted in memory to ASCII/UTF8/char* before being parsed. If 0, no
* conversion will be performed.
*
* @param characterEncoding This parameter is only meaningful when compiling
* in char* mode (multibyte character mode). In wchar_t* (wide char mode),
* this parameter is ignored. This parameter should be one of the three
* currently recognized encodings: XMLNode::encoding_UTF8,
* XMLNode::encoding_ascii, XMLNode::encoding_ShiftJIS.
*
* @param dropWhiteSpace In most situations, text fields containing only white
* spaces (and carriage returns) are useless. Even more, these "empty" text
* fields are annoying because they increase the complexity of the user's code
* for parsing. So, 99% of the time, it's better to drop the "empty" text
* fields. However The XML specification indicates that no white spaces should
* be lost when parsing the file. So to be perfectly XML-compliant, you should
* set dropWhiteSpace=0. A note of caution: if you set "dropWhiteSpace=0", the
* parser will be slower and your code will be more complex.
*
* @param removeCommentsInMiddleOfText To explain this parameter, let's
* consider this code: \code XMLNode x=XMLNode::parseString("foobarchu","a"); \endcode If
* removeCommentsInMiddleOfText=0, then we will have: \code x.getText(0) ->
* "foo" x.getText(1) -> "bar" x.getText(2) -> "chu" x.getClear(0) --> "" x.getClear(1) --> "" \endcode If
* removeCommentsInMiddleOfText=1, then we will have: \code x.getText(0) ->
* "foobar" x.getText(1) -> "chu" x.getClear(0) --> ""
* \endcode
*
* \return "0" when there are no errors. If you try to set an unrecognized
* encoding then the return value will be "1" to signal an error.
*
* \note Sometime, it's useful to set "guessWideCharChars=0" to disable any
* conversion because the test to detect the file-type (ASCII/UTF8/char* or
* WideChar) may fail (rarely). */
/// Guess the character encoding of the string (ascii, utf8 or shift-JIS)
static XMLCharEncoding guessCharEncoding(void *buffer, int bufLen,
char useXMLEncodingAttribute = 1);
/**< The "guessCharEncoding" function try to guess the character encoding. You
* most-probably will never have to use this function. It then returns the
* appropriate value of the global parameter "characterEncoding" described in
* the XMLNode::setGlobalOptions. The guess is based on the content of a
* buffer of length "bufLen" bytes that contains the first bytes (minimum 25
* bytes; 200 bytes is a good value) of the file to be parsed. The
* XMLNode::openFileHelper function is using this function to automatically
* compute the value of the "characterEncoding" global parameter. There are
* several heuristics used to do the guess. One of the heuristic is based on
* the "encoding" attribute. The original XML specifications forbids to use
* this attribute to do the guess but you can still use it if you set
* "useXMLEncodingAttribute" to 1 (this is the default behavior and the
* behavior of most parsers).
* If an inconsistency in the encoding is detected, then the return value is
* "0". */
/** @} */
private:
// these are functions and structures used internally by the XMLNode class
// (don't bother about them):
typedef struct XMLNodeDataTag // to allow shallow copy and
// "intelligent/smart" pointers (automatic
// delete):
{
XMLCSTR lpszName; // Element name (=NULL if root)
int nChild, // Number of child nodes
nText, // Number of text fields
nClear, // Number of Clear fields (comments)
nAttribute; // Number of attributes
char isDeclaration; // Whether node is an XML declaration - ''
struct XMLNodeDataTag
*pParent; // Pointer to parent element (=NULL if root)
XMLNode *pChild; // Array of child nodes
XMLCSTR *pText; // Array of text fields
XMLClear *pClear; // Array of clear fields
XMLAttribute *pAttribute; // Array of attributes
int *pOrder; // order of the child_nodes,text_fields,clear_fields
int ref_count; // for garbage collection (smart pointers)
} XMLNodeData;
XMLNodeData *d;
char parseClearTag(void *px, void *pa);
char maybeAddTxT(void *pa, XMLCSTR tokenPStr);
int ParseXMLElement(void *pXML);
void *addToOrder(int memInc, int *_pos, int nc, void *p, int size,
XMLElementType xtype);
int indexText(XMLCSTR lpszValue) const;
int indexClear(XMLCSTR lpszValue) const;
XMLNode addChild_priv(int, XMLSTR, char, int);
XMLAttribute *addAttribute_priv(int, XMLSTR, XMLSTR);
XMLCSTR addText_priv(int, XMLSTR, int);
XMLClear *addClear_priv(int, XMLSTR, XMLCSTR, XMLCSTR, int);
void emptyTheNode(char force);
static inline XMLElementPosition findPosition(XMLNodeData *d, int index,
XMLElementType xtype);
static int CreateXMLStringR(XMLNodeData *pEntry, XMLSTR lpszMarker,
int nFormat);
static int removeOrderElement(XMLNodeData *d, XMLElementType t, int index);
static void exactMemory(XMLNodeData *d);
static int detachFromParent(XMLNodeData *d);
} XMLNode;
/// This structure is given by the function XMLNode::enumContents.
typedef struct XMLNodeContents {
/// This dictates what's the content of the XMLNodeContent
enum XMLElementType etype;
/**< should be an union to access the appropriate data. Compiler does not
* allow union of object with constructor... too bad. */
XMLNode child;
XMLAttribute attrib;
XMLCSTR text;
XMLClear clear;
} XMLNodeContents;
/** @defgroup StringAlloc String Allocation/Free functions
* @ingroup xmlModify
* @{ */
/// Duplicate (copy in a new allocated buffer) the source string.
XMLDLLENTRY XMLSTR stringDup(XMLCSTR source, int cbData = -1);
/**< This is
* a very handy function when used with all the "XMLNode::*_WOSD" functions
* (\link xmlWOSD \endlink).
* @param cbData If !=0 then cbData is the number of chars to duplicate. New
* strings allocated with this function should be free'd using the
* "freeXMLString" function. */
/// to free the string allocated inside the "stringDup" function or the
/// "createXMLString" function.
XMLDLLENTRY void freeXMLString(XMLSTR t); // {free(t);}
/** @} */
/** @defgroup atoX ato? like functions
* @ingroup XMLParserGeneral
* The "xmlto?" functions are equivalents to the atoi, atol, atof functions.
* The only difference is: If the variable "xmlString" is NULL, than the return
* value is "defautValue". These 6 functions are only here as "convenience"
* functions for the user (they are not used inside the XMLparser). If you don't
* need them, you can delete them without any trouble.
*
* @{ */
XMLDLLENTRY char xmltob(XMLCSTR xmlString, char defautValue = 0);
XMLDLLENTRY int xmltoi(XMLCSTR xmlString, int defautValue = 0);
XMLDLLENTRY long xmltol(XMLCSTR xmlString, long defautValue = 0);
XMLDLLENTRY double xmltof(XMLCSTR xmlString, double defautValue = .0);
XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString, XMLCSTR defautValue = _CXML(""));
XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,
XMLCHAR defautValue = _CXML('\0'));
/** @} */
/** @defgroup ToXMLStringTool Helper class to create XML files using "printf",
* "fprintf", "cout",... functions.
* @ingroup XMLParserGeneral
* @{ */
/// Helper class to create XML files using "printf", "fprintf", "cout",...
/// functions.
/** The ToXMLStringTool class helps you creating XML files using "printf",
* "fprintf", "cout",... functions. The "ToXMLStringTool" class is processing
* strings so that all the characters
* &,",',<,> are replaced by their XML equivalent:
* \verbatim &, ", ', <, > \endverbatim
* Using the "ToXMLStringTool class" and the "fprintf function" is THE most
* efficient way to produce VERY large XML documents VERY fast. \note If you are
* creating from scratch an XML file using the provided XMLNode class you must
* not use the "ToXMLStringTool" class (because the "XMLNode" class does the
* processing job for you during rendering).*/
typedef struct XMLDLLENTRY ToXMLStringTool {
public:
ToXMLStringTool() : buf(NULL), buflen(0) {}
~ToXMLStringTool();
void freeBuffer(); ///< call this function when you have finished using this
///< object to release memory used by the internal buffer.
XMLSTR toXML(XMLCSTR source); ///< returns a pointer to an internal buffer
///< that contains a XML-encoded string based
///< on the "source" parameter.
/** The "toXMLUnSafe" function is deprecated because there is a possibility of
* "destination-buffer-overflow". It converts the string
* "source" to the string "dest". */
static XMLSTR toXMLUnSafe(
XMLSTR dest, XMLCSTR source); ///< deprecated: use "toXML" instead
static int lengthXMLString(
XMLCSTR source); ///< deprecated: use "toXML" instead
private:
XMLSTR buf;
int buflen;
} ToXMLStringTool;
/** @} */
/** @defgroup XMLParserBase64Tool Helper class to include binary data inside XML
* strings using "Base64 encoding".
* @ingroup XMLParserGeneral
* @{ */
/// Helper class to include binary data inside XML strings using "Base64
/// encoding".
/** The "XMLParserBase64Tool" class allows you to include any binary data
* (images, sounds,...) into an XML document using "Base64 encoding". This class
* is completely separated from the rest of the xmlParser library and can be
* removed without any problem. To include some binary data into an XML file,
* you must convert the binary data into standard text (using "encode"). To
* retrieve the original binary data from the b64-encoded text included inside
* the XML file, use "decode". Alternatively, these functions can also be used
* to "encrypt/decrypt" some critical data contained inside
* the XML (it's not a strong encryption at all, but sometimes it can be
* useful). */
typedef struct XMLDLLENTRY XMLParserBase64Tool {
public:
XMLParserBase64Tool() : buf(NULL), buflen(0) {}
~XMLParserBase64Tool();
void freeBuffer(); ///< Call this function when you have finished using this
///< object to release memory used by the internal buffer.
/**
* @param formatted If "formatted"=true, some space will be reserved for a
* carriage-return every 72 chars. */
static int encodeLength(
int inBufLen,
char formatted = 0); ///< return the length of the base64 string that
///< encodes a data buffer of size inBufLen bytes.
/**
* The "base64Encode" function returns a string containing the base64 encoding
* of "inByteLen" bytes from "inByteBuf". If "formatted" parameter is true,
* then there will be a carriage-return every 72 chars. The string will be
* free'd when the XMLParserBase64Tool object is deleted.
* All returned strings are sharing the same memory space. */
XMLSTR encode(
unsigned char *inByteBuf, unsigned int inByteLen,
char formatted = 0); ///< returns a pointer to an internal buffer
///< containing the base64 string containing the
///< binary data encoded from "inByteBuf"
/// returns the number of bytes which will be decoded from "inString".
static unsigned int decodeSize(XMLCSTR inString, XMLError *xe = NULL);
/**
* The "decode" function returns a pointer to a buffer containing the binary
* data decoded from "inString" The output buffer will be free'd when the
* XMLParserBase64Tool object is deleted. All output buffer are sharing the
* same memory space.
* @param inString If "instring" is malformed, NULL will be returned */
unsigned char *decode(
XMLCSTR inString, int *outByteLen = NULL,
XMLError *xe =
NULL); ///< returns a pointer to an internal buffer containing the
///< binary data decoded from "inString"
/**
* decodes data from "inString" to "outByteBuf". You need to provide the size
* (in byte) of "outByteBuf" in "inMaxByteOutBuflen". If "outByteBuf" is not
* large enough or if data is malformed, then "FALSE" will be returned;
* otherwise "TRUE". */
static unsigned char decode(XMLCSTR inString, unsigned char *outByteBuf,
int inMaxByteOutBuflen,
XMLError *xe = NULL); ///< deprecated.
private:
void *buf;
int buflen;
void alloc(int newsize);
} XMLParserBase64Tool;
/** @} */
#undef XMLDLLENTRY
#endif