summaryrefslogtreecommitdiff
path: root/ext/mcpat/xmlParser.h
blob: e29136cb987caf2f443a6c72847c13796429981b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
/****************************************************************************/
/*! \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
 * <a href="http://www.Business-Insight.com">Business-Insight</a>
 * All rights reserved.
 *
 * \section tutorial First Tutorial
 * You can follow a simple <a href="../../xmlParser.html">Tutorial</a> to know the basics...
 *
 * \section usage General usage: How to include the XMLParser library inside your project.
 *
 * The library is composed of two files: <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
 * <a href="../../xmlParser.h">xmlParser.h</a>. 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
 * <a href="../../xmlParser.h">xmlParser.h</a>. 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
 * <a href="../../xmlParser.html">xmlParser.html</a>
 *
 * Some additional small examples are also inside the file <a href="../../xmlTest.cpp">xmlTest.cpp</a>
 * (for the "char*" version of the library) and inside the file
 * <a href="../../xmlTestUnicode.cpp">xmlTestUnicode.cpp</a> (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
 * <a href="../../xmlParser.cpp">xmlParser.cpp</a> and
 * <a href="../../xmlParser.h">xmlParser.h</a> files into the project).
 *
 * 	The file <a href="../../XMLNodeAutoexp.txt">XMLNodeAutoexp.txt</a> 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 <stdlib.h>

#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 <wchar.h> or <tchar.h> libraries anymore to compile)
//#define XML_NO_WIDE_CHAR

#ifdef XML_NO_WIDE_CHAR
#undef _XMLWINDOWS
#undef _XMLWIDECHAR
#endif

#ifdef _XMLWINDOWS
#include <tchar.h>
#else
#define XMLDLLENTRY
#ifndef XML_NO_WIDE_CHAR
#include <wchar.h> // 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:
 * <ul>
 *    <li> XMLNode::parseString </li>
 *    <li> XMLNode::parseFile </li>
 *    <li> XMLNode::openFileHelper </li>
 *    <li> XMLNode::createXMLTopNode (or XMLNode::createXMLTopNode_WOSD)</li>
 * </ul> */
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). <br>
     *
     *  REMARK: 0 <= pos < nChild()+nText()+nClear() <br>
     */

    /** @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 "<![CDATA["
     * @param lpszClose 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("<a>foo<!-- hello -->bar<!DOCTYPE world >chu</a>","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) --> "<!-- hello -->"
     *        x.getClear(1) --> "<!DOCTYPE world >"
     * \endcode
     *     If removeCommentsInMiddleOfText=1, then we will have:
     * \code
     *        x.getText(0) -> "foobar"
     *        x.getText(1) -> "chu"
     *        x.getClear(0) --> "<!DOCTYPE world >"
     * \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 - '<?xml ?>'
          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 &amp;, &quot;, &apos;, &lt;, &gt; \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