/****************************************************************************/ /*! \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.44 * @author Frank Vanden Berghen * * Copyright (c) 2002, Frank Vanden Berghen - All rights reserved.
* Commercialized by Business-Insight
* See the file AFPL-license.txt about the licensing terms * * \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 #if defined(UNICODE) || defined(_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 long xmltol(XMLCSTR xmlString,long long defautValue=0); XMLDLLENTRY double xmltof(XMLCSTR xmlString,double defautValue=.0); XMLDLLENTRY XMLCSTR xmltoa(XMLCSTR xmlString,XMLCSTR defautValue=_CXML("")); XMLDLLENTRY XMLCHAR xmltoc(XMLCSTR xmlString,const 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();///