1 /*
2 Original code by Lee Thomason (www.grinninglizard.com)
3
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any
6 damages arising from the use of this software.
7
8 Permission is granted to anyone to use this software for any
9 purpose, including commercial applications, and to alter it and
10 redistribute it freely, subject to the following restrictions:
11
12 1. The origin of this software must not be misrepresented; you must
13 not claim that you wrote the original software. If you use this
14 software in a product, an acknowledgment in the product documentation
15 would be appreciated but is not required.
16
17 2. Altered source versions must be plainly marked as such, and
18 must not be misrepresented as being the original software.
19
20 3. This notice may not be removed or altered from any source
21 distribution.
22 */
23
24 #ifndef TINYXML2_INCLUDED
25 #define TINYXML2_INCLUDED
26
27 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
28 #include <ctype.h>
29 #include <limits.h>
30 #include <stdio.h>
31 #include <stdlib.h>
32 #include <string.h>
33 #if defined(__PS3__)
34 #include <stddef.h>
35 #endif
36 #else
37 #include <cctype>
38 #include <climits>
39 #include <cstdio>
40 #include <cstdlib>
41 #include <cstring>
42 #endif
43
44
45 #ifdef __GNUC__
46 #include <stdint.h>
47 typedef int32_t xml_Int32a_t;
48 typedef int64_t xml_Int64a_t;
49 typedef uint32_t xml_Uint32a_t;
50 typedef uint64_t xml_Uint64a_t;
51 #elif defined(_MSC_VER)
52 typedef __int32 xml_Int32a_t;
53 typedef __int64 xml_Int64a_t;
54 typedef unsigned __int32 xml_Uint32a_t;
55 typedef unsigned __int64 xml_Uint64a_t;
56 #else
57 typedef int xml_Int32a_t;
58 typedef long long int xml_Int64a_t;
59 typedef unsigned int xml_Uint32a_t;
60 typedef unsigned long long int xml_Uint64a_t;
61 #endif
62
63
64
65 /*
66 TODO: intern strings instead of allocation.
67 */
68 /*
69 gcc:
70 g++ -Wall -DTINYXML2_DEBUG tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
71
72 Formatting, Artistic Style:
73 AStyle.exe --style=1tbs --indent-switches --break-closing-brackets --indent-preprocessor tinyxml2.cpp tinyxml2.h
74 */
75
76 #if defined(_DEBUG) || defined(__DEBUG__)
77 #ifndef TINYXML2_DEBUG
78 #define TINYXML2_DEBUG
79 #endif
80 #endif
81
82 #ifdef _MSC_VER
83 #pragma warning(push)
84 #pragma warning(disable : 4251)
85 #endif
86
87 #ifdef _WIN32
88 #ifdef TINYXML2_EXPORT
89 #define TINYXML2_LIB __declspec(dllexport)
90 #elif defined(TINYXML2_IMPORT)
91 #define TINYXML2_LIB __declspec(dllimport)
92 #else
93 #define TINYXML2_LIB
94 #endif
95 #elif __GNUC__ >= 4
96 #define TINYXML2_LIB __attribute__((visibility("default")))
97 #else
98 #define TINYXML2_LIB
99 #endif
100
101 #if defined(TINYXML2_DEBUG)
102 #if defined(_MSC_VER)
103 #// "(void)0," is for suppressing C4127 warning in "assert(false)", "assert(true)" and the like
104 #define TIXMLASSERT(x) \
105 if (!((void)0, (x))) \
106 { \
107 __debugbreak(); \
108 }
109 #elif defined(ANDROID_NDK)
110 #include <android/log.h>
111 #define TIXMLASSERT(x) \
112 if (!(x)) \
113 { \
114 __android_log_assert("assert", "grinliz", "ASSERT in '%s' at %d.", __FILE__, __LINE__); \
115 }
116 #else
117 #include <assert.h>
118 #define TIXMLASSERT assert
119 #endif
120 #else
121 #define TIXMLASSERT(x) \
122 { \
123 }
124 #endif
125
126 /* Versioning, past 1.0.14:
127 http://semver.org/
128 */
129 static const int TIXML2_MAJOR_VERSION = 6;
130 static const int TIXML2_MINOR_VERSION = 2;
131 static const int TIXML2_PATCH_VERSION = 0;
132
133 #define TINYXML2_MAJOR_VERSION 6
134 #define TINYXML2_MINOR_VERSION 2
135 #define TINYXML2_PATCH_VERSION 0
136
137 // A fixed element depth limit is problematic. There needs to be a
138 // limit to avoid a stack overflow. However, that limit varies per
139 // system, and the capacity of the stack. On the other hand, it's a trivial
140 // attack that can result from ill, malicious, or even correctly formed XML,
141 // so there needs to be a limit in place.
142 static const int TINYXML2_MAX_ELEMENT_DEPTH = 100;
143
144 namespace tinyxml2
145 {
146 class XMLDocument;
147 class XMLElement;
148 class XMLAttribute;
149 class XMLComment;
150 class XMLText;
151 class XMLDeclaration;
152 class XMLUnknown;
153 class XMLPrinter;
154
155 /*
156 A class that wraps strings. Normally stores the start and end
157 pointers into the XML file itself, and will apply normalization
158 and entity translation if actually read. Can also store (and memory
159 manage) a traditional char[]
160 */
161 class StrPair
162 {
163 public:
164 enum
165 {
166 NEEDS_ENTITY_PROCESSING = 0x01,
167 NEEDS_NEWLINE_NORMALIZATION = 0x02,
168 NEEDS_WHITESPACE_COLLAPSING = 0x04,
169
170 TEXT_ELEMENT = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
171 TEXT_ELEMENT_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
172 ATTRIBUTE_NAME = 0,
173 ATTRIBUTE_VALUE = NEEDS_ENTITY_PROCESSING | NEEDS_NEWLINE_NORMALIZATION,
174 ATTRIBUTE_VALUE_LEAVE_ENTITIES = NEEDS_NEWLINE_NORMALIZATION,
175 COMMENT = NEEDS_NEWLINE_NORMALIZATION
176 };
177
StrPair()178 StrPair() : _flags(0), _start(0), _end(0) {}
179 ~StrPair();
180
Set(char * start,char * end,int flags)181 void Set(char* start, char* end, int flags)
182 {
183 TIXMLASSERT(start);
184 TIXMLASSERT(end);
185 Reset();
186 _start = start;
187 _end = end;
188 _flags = flags | NEEDS_FLUSH;
189 }
190
191 const char* GetStr();
192
Empty()193 bool Empty() const
194 {
195 return _start == _end;
196 }
197
SetInternedStr(const char * str)198 void SetInternedStr(const char* str)
199 {
200 Reset();
201 _start = const_cast<char*>(str);
202 }
203
204 void SetStr(const char* str, int flags = 0);
205
206 char* ParseText(char* in, const char* endTag, int strFlags, int* curLineNumPtr);
207 char* ParseName(char* in);
208
209 void TransferTo(StrPair* other);
210 void Reset();
211
212 private:
213 void CollapseWhitespace();
214
215 enum
216 {
217 NEEDS_FLUSH = 0x100,
218 NEEDS_DELETE = 0x200
219 };
220
221 int _flags;
222 char* _start;
223 char* _end;
224
225 StrPair(const StrPair& other); // not supported
226 void operator=(StrPair& other); // not supported, use TransferTo()
227 };
228
229 /*
230 A dynamic array of Plain Old Data. Doesn't support constructors, etc.
231 Has a small initial memory pool, so that low or no usage will not
232 cause a call to new/delete
233 */
234 template <class T, int INITIAL_SIZE>
235 class DynArray
236 {
237 public:
DynArray()238 DynArray() : _mem(_pool),
239 _allocated(INITIAL_SIZE),
240 _size(0)
241 {
242 }
243
~DynArray()244 ~DynArray()
245 {
246 if (_mem != _pool)
247 {
248 delete[] _mem;
249 }
250 }
251
Clear()252 void Clear()
253 {
254 _size = 0;
255 }
256
Push(T t)257 void Push(T t)
258 {
259 TIXMLASSERT(_size < INT_MAX);
260 EnsureCapacity(_size + 1);
261 _mem[_size] = t;
262 ++_size;
263 }
264
PushArr(int count)265 T* PushArr(int count)
266 {
267 TIXMLASSERT(count >= 0);
268 TIXMLASSERT(_size <= INT_MAX - count);
269 EnsureCapacity(_size + count);
270 T* ret = &_mem[_size];
271 _size += count;
272 return ret;
273 }
274
Pop()275 T Pop()
276 {
277 TIXMLASSERT(_size > 0);
278 --_size;
279 return _mem[_size];
280 }
281
PopArr(int count)282 void PopArr(int count)
283 {
284 TIXMLASSERT(_size >= count);
285 _size -= count;
286 }
287
Empty()288 bool Empty() const
289 {
290 return _size == 0;
291 }
292
293 T& operator[](int i)
294 {
295 TIXMLASSERT(i >= 0 && i < _size);
296 return _mem[i];
297 }
298
299 const T& operator[](int i) const
300 {
301 TIXMLASSERT(i >= 0 && i < _size);
302 return _mem[i];
303 }
304
PeekTop()305 const T& PeekTop() const
306 {
307 TIXMLASSERT(_size > 0);
308 return _mem[_size - 1];
309 }
310
Size()311 int Size() const
312 {
313 TIXMLASSERT(_size >= 0);
314 return _size;
315 }
316
Capacity()317 int Capacity() const
318 {
319 TIXMLASSERT(_allocated >= INITIAL_SIZE);
320 return _allocated;
321 }
322
SwapRemove(int i)323 void SwapRemove(int i)
324 {
325 TIXMLASSERT(i >= 0 && i < _size);
326 TIXMLASSERT(_size > 0);
327 _mem[i] = _mem[_size - 1];
328 --_size;
329 }
330
Mem()331 const T* Mem() const
332 {
333 TIXMLASSERT(_mem);
334 return _mem;
335 }
336
Mem()337 T* Mem()
338 {
339 TIXMLASSERT(_mem);
340 return _mem;
341 }
342
343 private:
344 DynArray(const DynArray&); // not supported
345 void operator=(const DynArray&); // not supported
346
EnsureCapacity(int cap)347 void EnsureCapacity(int cap)
348 {
349 TIXMLASSERT(cap > 0);
350 if (cap > _allocated)
351 {
352 TIXMLASSERT(cap <= INT_MAX / 2);
353 int newAllocated = cap * 2;
354 T* newMem = new T[newAllocated];
355 TIXMLASSERT(newAllocated >= _size);
356 memcpy(newMem, _mem, sizeof(T) * _size); // warning: not using constructors, only works for PODs
357 if (_mem != _pool)
358 {
359 delete[] _mem;
360 }
361 _mem = newMem;
362 _allocated = newAllocated;
363 }
364 }
365
366 T* _mem;
367 T _pool[INITIAL_SIZE];
368 int _allocated; // objects allocated
369 int _size; // number objects in use
370 };
371
372 /*
373 Parent virtual class of a pool for fast allocation
374 and deallocation of objects.
375 */
376 class MemPool
377 {
378 public:
MemPool()379 MemPool() {}
~MemPool()380 virtual ~MemPool() {}
381
382 virtual int ItemSize() const = 0;
383 virtual void* Alloc() = 0;
384 virtual void Free(void*) = 0;
385 virtual void SetTracked() = 0;
386 virtual void Clear() = 0;
387 };
388
389 /*
390 Template child class to create pools of the correct type.
391 */
392 template <int ITEM_SIZE>
393 class MemPoolT : public MemPool
394 {
395 public:
MemPoolT()396 MemPoolT() : _blockPtrs(), _root(0), _currentAllocs(0), _nAllocs(0), _maxAllocs(0), _nUntracked(0) {}
~MemPoolT()397 ~MemPoolT()
398 {
399 Clear();
400 }
401
Clear()402 void Clear()
403 {
404 // Delete the blocks.
405 while (!_blockPtrs.Empty())
406 {
407 Block* lastBlock = _blockPtrs.Pop();
408 delete lastBlock;
409 }
410 _root = 0;
411 _currentAllocs = 0;
412 _nAllocs = 0;
413 _maxAllocs = 0;
414 _nUntracked = 0;
415 }
416
ItemSize()417 virtual int ItemSize() const
418 {
419 return ITEM_SIZE;
420 }
CurrentAllocs()421 int CurrentAllocs() const
422 {
423 return _currentAllocs;
424 }
425
Alloc()426 virtual void* Alloc()
427 {
428 if (!_root)
429 {
430 // Need a new block.
431 Block* block = new Block();
432 _blockPtrs.Push(block);
433
434 Item* blockItems = block->items;
435 for (int i = 0; i < ITEMS_PER_BLOCK - 1; ++i)
436 {
437 blockItems[i].next = &(blockItems[i + 1]);
438 }
439 blockItems[ITEMS_PER_BLOCK - 1].next = 0;
440 _root = blockItems;
441 }
442 Item* const result = _root;
443 TIXMLASSERT(result != 0);
444 _root = _root->next;
445
446 ++_currentAllocs;
447 if (_currentAllocs > _maxAllocs)
448 {
449 _maxAllocs = _currentAllocs;
450 }
451 ++_nAllocs;
452 ++_nUntracked;
453 return result;
454 }
455
Free(void * mem)456 virtual void Free(void* mem)
457 {
458 if (!mem)
459 {
460 return;
461 }
462 --_currentAllocs;
463 Item* item = static_cast<Item*>(mem);
464 #ifdef TINYXML2_DEBUG
465 memset(item, 0xfe, sizeof(*item));
466 #endif
467 item->next = _root;
468 _root = item;
469 }
Trace(const char * name)470 void Trace(const char* name)
471 {
472 printf("Mempool %s watermark=%d [%dk] current=%d size=%d nAlloc=%d blocks=%d\n",
473 name, _maxAllocs, _maxAllocs * ITEM_SIZE / 1024, _currentAllocs,
474 ITEM_SIZE, _nAllocs, _blockPtrs.Size());
475 }
476
SetTracked()477 void SetTracked()
478 {
479 --_nUntracked;
480 }
481
Untracked()482 int Untracked() const
483 {
484 return _nUntracked;
485 }
486
487 // This number is perf sensitive. 4k seems like a good tradeoff on my machine.
488 // The test file is large, 170k.
489 // Release: VS2010 gcc(no opt)
490 // 1k: 4000
491 // 2k: 4000
492 // 4k: 3900 21000
493 // 16k: 5200
494 // 32k: 4300
495 // 64k: 4000 21000
496 // Declared public because some compilers do not accept to use ITEMS_PER_BLOCK
497 // in private part if ITEMS_PER_BLOCK is private
498 enum
499 {
500 ITEMS_PER_BLOCK = (4 * 1024) / ITEM_SIZE
501 };
502
503 private:
504 MemPoolT(const MemPoolT&); // not supported
505 void operator=(const MemPoolT&); // not supported
506
507 union Item {
508 Item* next;
509 char itemData[ITEM_SIZE];
510 };
511 struct Block
512 {
513 Item items[ITEMS_PER_BLOCK];
514 };
515 DynArray<Block*, 10> _blockPtrs;
516 Item* _root;
517
518 int _currentAllocs;
519 int _nAllocs;
520 int _maxAllocs;
521 int _nUntracked;
522 };
523
524 /**
525 Implements the interface to the "Visitor pattern" (see the Accept() method.)
526 If you call the Accept() method, it requires being passed a XMLVisitor
527 class to handle callbacks. For nodes that contain other nodes (Document, Element)
528 you will get called with a VisitEnter/VisitExit pair. Nodes that are always leafs
529 are simply called with Visit().
530
531 If you return 'true' from a Visit method, recursive parsing will continue. If you return
532 false, <b>no children of this node or its siblings</b> will be visited.
533
534 All flavors of Visit methods have a default implementation that returns 'true' (continue
535 visiting). You need to only override methods that are interesting to you.
536
537 Generally Accept() is called on the XMLDocument, although all nodes support visiting.
538
539 You should never change the document from a callback.
540
541 @sa XMLNode::Accept()
542 */
543 class TINYXML2_LIB XMLVisitor
544 {
545 public:
~XMLVisitor()546 virtual ~XMLVisitor() {}
547
548 /// Visit a document.
VisitEnter(const XMLDocument &)549 virtual bool VisitEnter(const XMLDocument& /*doc*/)
550 {
551 return true;
552 }
553 /// Visit a document.
VisitExit(const XMLDocument &)554 virtual bool VisitExit(const XMLDocument& /*doc*/)
555 {
556 return true;
557 }
558
559 /// Visit an element.
VisitEnter(const XMLElement &,const XMLAttribute *)560 virtual bool VisitEnter(const XMLElement& /*element*/, const XMLAttribute* /*firstAttribute*/)
561 {
562 return true;
563 }
564 /// Visit an element.
VisitExit(const XMLElement &)565 virtual bool VisitExit(const XMLElement& /*element*/)
566 {
567 return true;
568 }
569
570 /// Visit a declaration.
Visit(const XMLDeclaration &)571 virtual bool Visit(const XMLDeclaration& /*declaration*/)
572 {
573 return true;
574 }
575 /// Visit a text node.
Visit(const XMLText &)576 virtual bool Visit(const XMLText& /*text*/)
577 {
578 return true;
579 }
580 /// Visit a comment node.
Visit(const XMLComment &)581 virtual bool Visit(const XMLComment& /*comment*/)
582 {
583 return true;
584 }
585 /// Visit an unknown node.
Visit(const XMLUnknown &)586 virtual bool Visit(const XMLUnknown& /*unknown*/)
587 {
588 return true;
589 }
590 };
591
592 // WARNING: must match XMLDocument::_errorNames[]
593 enum XMLError
594 {
595 XML_SUCCESS = 0,
596 XML_NO_ATTRIBUTE,
597 XML_WRONG_ATTRIBUTE_TYPE,
598 XML_ERROR_FILE_NOT_FOUND,
599 XML_ERROR_FILE_COULD_NOT_BE_OPENED,
600 XML_ERROR_FILE_READ_ERROR,
601 UNUSED_XML_ERROR_ELEMENT_MISMATCH, // remove at next major version
602 XML_ERROR_PARSING_ELEMENT,
603 XML_ERROR_PARSING_ATTRIBUTE,
604 UNUSED_XML_ERROR_IDENTIFYING_TAG, // remove at next major version
605 XML_ERROR_PARSING_TEXT,
606 XML_ERROR_PARSING_CDATA,
607 XML_ERROR_PARSING_COMMENT,
608 XML_ERROR_PARSING_DECLARATION,
609 XML_ERROR_PARSING_UNKNOWN,
610 XML_ERROR_EMPTY_DOCUMENT,
611 XML_ERROR_MISMATCHED_ELEMENT,
612 XML_ERROR_PARSING,
613 XML_CAN_NOT_CONVERT_TEXT,
614 XML_NO_TEXT_NODE,
615 XML_ELEMENT_DEPTH_EXCEEDED,
616
617 XML_ERROR_COUNT
618 };
619
620 /*
621 Utility functionality.
622 */
623 class TINYXML2_LIB XMLUtil
624 {
625 public:
SkipWhiteSpace(const char * p,int * curLineNumPtr)626 static const char* SkipWhiteSpace(const char* p, int* curLineNumPtr)
627 {
628 TIXMLASSERT(p);
629
630 while (IsWhiteSpace(*p))
631 {
632 if (curLineNumPtr && *p == '\n')
633 {
634 ++(*curLineNumPtr);
635 }
636 ++p;
637 }
638 TIXMLASSERT(p);
639 return p;
640 }
SkipWhiteSpace(char * p,int * curLineNumPtr)641 static char* SkipWhiteSpace(char* p, int* curLineNumPtr)
642 {
643 return const_cast<char*>(SkipWhiteSpace(const_cast<const char*>(p), curLineNumPtr));
644 }
645
646 // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
647 // correct, but simple, and usually works.
IsWhiteSpace(char p)648 static bool IsWhiteSpace(char p)
649 {
650 return !IsUTF8Continuation(p) && isspace(static_cast<unsigned char>(p));
651 }
652
IsNameStartChar(unsigned char ch)653 inline static bool IsNameStartChar(unsigned char ch)
654 {
655 if (ch >= 128)
656 {
657 // This is a heuristic guess in attempt to not implement Unicode-aware isalpha()
658 return true;
659 }
660 if (isalpha(ch))
661 {
662 return true;
663 }
664 return ch == ':' || ch == '_';
665 }
666
IsNameChar(unsigned char ch)667 inline static bool IsNameChar(unsigned char ch)
668 {
669 return IsNameStartChar(ch) || isdigit(ch) || ch == '.' || ch == '-';
670 }
671
672 inline static bool StringEqual(const char* p, const char* q, int nChar = INT_MAX)
673 {
674 if (p == q)
675 {
676 return true;
677 }
678 TIXMLASSERT(p);
679 TIXMLASSERT(q);
680 TIXMLASSERT(nChar >= 0);
681 return strncmp(p, q, nChar) == 0;
682 }
683
IsUTF8Continuation(char p)684 inline static bool IsUTF8Continuation(char p)
685 {
686 return (p & 0x80) != 0;
687 }
688
689 static const char* ReadBOM(const char* p, bool* hasBOM);
690 // p is the starting location,
691 // the UTF-8 value of the entity will be placed in value, and length filled in.
692 static const char* GetCharacterRef(const char* p, char* value, int* length);
693 static void ConvertUTF32ToUTF8(unsigned long input, char* output, int* length);
694
695 // converts primitive types to strings
696 static void ToStr(int v, char* buffer, int bufferSize);
697 static void ToStr(unsigned v, char* buffer, int bufferSize);
698 static void ToStr(bool v, char* buffer, int bufferSize);
699 static void ToStr(float v, char* buffer, int bufferSize);
700 static void ToStr(double v, char* buffer, int bufferSize);
701 static void ToStr(xml_Int64a_t v, char* buffer, int bufferSize);
702
703 // converts strings to primitive types
704 static bool ToInt(const char* str, int* value);
705 static bool ToUnsigned(const char* str, unsigned* value);
706 static bool ToBool(const char* str, bool* value);
707 static bool ToFloat(const char* str, float* value);
708 static bool ToDouble(const char* str, double* value);
709 static bool ToInt64(const char* str, xml_Int64a_t* value);
710
711 // Changes what is serialized for a boolean value.
712 // Default to "true" and "false". Shouldn't be changed
713 // unless you have a special testing or compatibility need.
714 // Be careful: static, global, & not thread safe.
715 // Be sure to set static const memory as parameters.
716 static void SetBoolSerialization(const char* writeTrue, const char* writeFalse);
717
718 private:
719 static const char* writeBoolTrue;
720 static const char* writeBoolFalse;
721 };
722
723 /** XMLNode is a base class for every object that is in the
724 XML Document Object Model (DOM), except XMLAttributes.
725 Nodes have siblings, a parent, and children which can
726 be navigated. A node is always in a XMLDocument.
727 The type of a XMLNode can be queried, and it can
728 be cast to its more defined type.
729
730 A XMLDocument allocates memory for all its Nodes.
731 When the XMLDocument gets deleted, all its Nodes
732 will also be deleted.
733
734 @verbatim
735 A Document can contain: Element (container or leaf)
736 Comment (leaf)
737 Unknown (leaf)
738 Declaration( leaf )
739
740 An Element can contain: Element (container or leaf)
741 Text (leaf)
742 Attributes (not on tree)
743 Comment (leaf)
744 Unknown (leaf)
745
746 @endverbatim
747 */
748 class TINYXML2_LIB XMLNode
749 {
750 friend class XMLDocument;
751 friend class XMLElement;
752
753 public:
754 /// Get the XMLDocument that owns this XMLNode.
GetDocument()755 const XMLDocument* GetDocument() const
756 {
757 TIXMLASSERT(_document);
758 return _document;
759 }
760 /// Get the XMLDocument that owns this XMLNode.
GetDocument()761 XMLDocument* GetDocument()
762 {
763 TIXMLASSERT(_document);
764 return _document;
765 }
766
767 /// Safely cast to an Element, or null.
ToElement()768 virtual XMLElement* ToElement()
769 {
770 return 0;
771 }
772 /// Safely cast to Text, or null.
ToText()773 virtual XMLText* ToText()
774 {
775 return 0;
776 }
777 /// Safely cast to a Comment, or null.
ToComment()778 virtual XMLComment* ToComment()
779 {
780 return 0;
781 }
782 /// Safely cast to a Document, or null.
ToDocument()783 virtual XMLDocument* ToDocument()
784 {
785 return 0;
786 }
787 /// Safely cast to a Declaration, or null.
ToDeclaration()788 virtual XMLDeclaration* ToDeclaration()
789 {
790 return 0;
791 }
792 /// Safely cast to an Unknown, or null.
ToUnknown()793 virtual XMLUnknown* ToUnknown()
794 {
795 return 0;
796 }
797
ToElement()798 virtual const XMLElement* ToElement() const
799 {
800 return 0;
801 }
ToText()802 virtual const XMLText* ToText() const
803 {
804 return 0;
805 }
ToComment()806 virtual const XMLComment* ToComment() const
807 {
808 return 0;
809 }
ToDocument()810 virtual const XMLDocument* ToDocument() const
811 {
812 return 0;
813 }
ToDeclaration()814 virtual const XMLDeclaration* ToDeclaration() const
815 {
816 return 0;
817 }
ToUnknown()818 virtual const XMLUnknown* ToUnknown() const
819 {
820 return 0;
821 }
822
823 /** The meaning of 'value' changes for the specific type.
824 @verbatim
825 Document: empty (NULL is returned, not an empty string)
826 Element: name of the element
827 Comment: the comment text
828 Unknown: the tag contents
829 Text: the text string
830 @endverbatim
831 */
832 const char* Value() const;
833
834 /** Set the Value of an XML node.
835 @sa Value()
836 */
837 void SetValue(const char* val, bool staticMem = false);
838
839 /// Gets the line number the node is in, if the document was parsed from a file.
GetLineNum()840 int GetLineNum() const { return _parseLineNum; }
841
842 /// Get the parent of this node on the DOM.
Parent()843 const XMLNode* Parent() const
844 {
845 return _parent;
846 }
847
Parent()848 XMLNode* Parent()
849 {
850 return _parent;
851 }
852
853 /// Returns true if this node has no children.
NoChildren()854 bool NoChildren() const
855 {
856 return !_firstChild;
857 }
858
859 /// Get the first child node, or null if none exists.
FirstChild()860 const XMLNode* FirstChild() const
861 {
862 return _firstChild;
863 }
864
FirstChild()865 XMLNode* FirstChild()
866 {
867 return _firstChild;
868 }
869
870 /** Get the first child element, or optionally the first child
871 element with the specified name.
872 */
873 const XMLElement* FirstChildElement(const char* name = 0) const;
874
875 XMLElement* FirstChildElement(const char* name = 0)
876 {
877 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->FirstChildElement(name));
878 }
879
880 /// Get the last child node, or null if none exists.
LastChild()881 const XMLNode* LastChild() const
882 {
883 return _lastChild;
884 }
885
LastChild()886 XMLNode* LastChild()
887 {
888 return _lastChild;
889 }
890
891 /** Get the last child element or optionally the last child
892 element with the specified name.
893 */
894 const XMLElement* LastChildElement(const char* name = 0) const;
895
896 XMLElement* LastChildElement(const char* name = 0)
897 {
898 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->LastChildElement(name));
899 }
900
901 /// Get the previous (left) sibling node of this node.
PreviousSibling()902 const XMLNode* PreviousSibling() const
903 {
904 return _prev;
905 }
906
PreviousSibling()907 XMLNode* PreviousSibling()
908 {
909 return _prev;
910 }
911
912 /// Get the previous (left) sibling element of this node, with an optionally supplied name.
913 const XMLElement* PreviousSiblingElement(const char* name = 0) const;
914
915 XMLElement* PreviousSiblingElement(const char* name = 0)
916 {
917 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement(name));
918 }
919
920 /// Get the next (right) sibling node of this node.
NextSibling()921 const XMLNode* NextSibling() const
922 {
923 return _next;
924 }
925
NextSibling()926 XMLNode* NextSibling()
927 {
928 return _next;
929 }
930
931 /// Get the next (right) sibling element of this node, with an optionally supplied name.
932 const XMLElement* NextSiblingElement(const char* name = 0) const;
933
934 XMLElement* NextSiblingElement(const char* name = 0)
935 {
936 return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement(name));
937 }
938
939 /**
940 Add a child node as the last (right) child.
941 If the child node is already part of the document,
942 it is moved from its old location to the new location.
943 Returns the addThis argument or 0 if the node does not
944 belong to the same document.
945 */
946 XMLNode* InsertEndChild(XMLNode* addThis);
947
LinkEndChild(XMLNode * addThis)948 XMLNode* LinkEndChild(XMLNode* addThis)
949 {
950 return InsertEndChild(addThis);
951 }
952 /**
953 Add a child node as the first (left) child.
954 If the child node is already part of the document,
955 it is moved from its old location to the new location.
956 Returns the addThis argument or 0 if the node does not
957 belong to the same document.
958 */
959 XMLNode* InsertFirstChild(XMLNode* addThis);
960 /**
961 Add a node after the specified child node.
962 If the child node is already part of the document,
963 it is moved from its old location to the new location.
964 Returns the addThis argument or 0 if the afterThis node
965 is not a child of this node, or if the node does not
966 belong to the same document.
967 */
968 XMLNode* InsertAfterChild(XMLNode* afterThis, XMLNode* addThis);
969
970 /**
971 Delete all the children of this node.
972 */
973 void DeleteChildren();
974
975 /**
976 Delete a child of this node.
977 */
978 void DeleteChild(XMLNode* node);
979
980 /**
981 Make a copy of this node, but not its children.
982 You may pass in a Document pointer that will be
983 the owner of the new Node. If the 'document' is
984 null, then the node returned will be allocated
985 from the current Document. (this->GetDocument())
986
987 Note: if called on a XMLDocument, this will return null.
988 */
989 virtual XMLNode* ShallowClone(XMLDocument* document) const = 0;
990
991 /**
992 Make a copy of this node and all its children.
993
994 If the 'target' is null, then the nodes will
995 be allocated in the current document. If 'target'
996 is specified, the memory will be allocated is the
997 specified XMLDocument.
998
999 NOTE: This is probably not the correct tool to
1000 copy a document, since XMLDocuments can have multiple
1001 top level XMLNodes. You probably want to use
1002 XMLDocument::DeepCopy()
1003 */
1004 XMLNode* DeepClone(XMLDocument* target) const;
1005
1006 /**
1007 Test if 2 nodes are the same, but don't test children.
1008 The 2 nodes do not need to be in the same Document.
1009
1010 Note: if called on a XMLDocument, this will return false.
1011 */
1012 virtual bool ShallowEqual(const XMLNode* compare) const = 0;
1013
1014 /** Accept a hierarchical visit of the nodes in the TinyXML-2 DOM. Every node in the
1015 XML tree will be conditionally visited and the host will be called back
1016 via the XMLVisitor interface.
1017
1018 This is essentially a SAX interface for TinyXML-2. (Note however it doesn't re-parse
1019 the XML for the callbacks, so the performance of TinyXML-2 is unchanged by using this
1020 interface versus any other.)
1021
1022 The interface has been based on ideas from:
1023
1024 - http://www.saxproject.org/
1025 - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
1026
1027 Which are both good references for "visiting".
1028
1029 An example of using Accept():
1030 @verbatim
1031 XMLPrinter printer;
1032 tinyxmlDoc.Accept( &printer );
1033 const char* xmlcstr = printer.CStr();
1034 @endverbatim
1035 */
1036 virtual bool Accept(XMLVisitor* visitor) const = 0;
1037
1038 /**
1039 Set user data into the XMLNode. TinyXML-2 in
1040 no way processes or interprets user data.
1041 It is initially 0.
1042 */
SetUserData(void * userData)1043 void SetUserData(void* userData) { _userData = userData; }
1044
1045 /**
1046 Get user data set into the XMLNode. TinyXML-2 in
1047 no way processes or interprets user data.
1048 It is initially 0.
1049 */
GetUserData()1050 void* GetUserData() const { return _userData; }
1051
1052 protected:
1053 XMLNode(XMLDocument*);
1054 virtual ~XMLNode();
1055
1056 virtual char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);
1057
1058 XMLDocument* _document;
1059 XMLNode* _parent;
1060 mutable StrPair _value;
1061 int _parseLineNum;
1062
1063 XMLNode* _firstChild;
1064 XMLNode* _lastChild;
1065
1066 XMLNode* _prev;
1067 XMLNode* _next;
1068
1069 void* _userData;
1070
1071 private:
1072 MemPool* _memPool;
1073 void Unlink(XMLNode* child);
1074 static void DeleteNode(XMLNode* node);
1075 void InsertChildPreamble(XMLNode* insertThis) const;
1076 const XMLElement* ToElementWithName(const char* name) const;
1077
1078 XMLNode(const XMLNode&); // not supported
1079 XMLNode& operator=(const XMLNode&); // not supported
1080 };
1081
1082 /** XML text.
1083
1084 Note that a text node can have child element nodes, for example:
1085 @verbatim
1086 <root>This is <b>bold</b></root>
1087 @endverbatim
1088
1089 A text node can have 2 ways to output the next. "normal" output
1090 and CDATA. It will default to the mode it was parsed from the XML file and
1091 you generally want to leave it alone, but you can change the output mode with
1092 SetCData() and query it with CData().
1093 */
1094 class TINYXML2_LIB XMLText : public XMLNode
1095 {
1096 friend class XMLDocument;
1097
1098 public:
1099 virtual bool Accept(XMLVisitor* visitor) const;
1100
ToText()1101 virtual XMLText* ToText()
1102 {
1103 return this;
1104 }
ToText()1105 virtual const XMLText* ToText() const
1106 {
1107 return this;
1108 }
1109
1110 /// Declare whether this should be CDATA or standard text.
SetCData(bool isCData)1111 void SetCData(bool isCData)
1112 {
1113 _isCData = isCData;
1114 }
1115 /// Returns true if this is a CDATA text element.
CData()1116 bool CData() const
1117 {
1118 return _isCData;
1119 }
1120
1121 virtual XMLNode* ShallowClone(XMLDocument* document) const;
1122 virtual bool ShallowEqual(const XMLNode* compare) const;
1123
1124 protected:
XMLText(XMLDocument * doc)1125 XMLText(XMLDocument* doc) : XMLNode(doc), _isCData(false) {}
~XMLText()1126 virtual ~XMLText() {}
1127
1128 char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);
1129
1130 private:
1131 bool _isCData;
1132
1133 XMLText(const XMLText&); // not supported
1134 XMLText& operator=(const XMLText&); // not supported
1135 };
1136
1137 /** An XML Comment. */
1138 class TINYXML2_LIB XMLComment : public XMLNode
1139 {
1140 friend class XMLDocument;
1141
1142 public:
ToComment()1143 virtual XMLComment* ToComment()
1144 {
1145 return this;
1146 }
ToComment()1147 virtual const XMLComment* ToComment() const
1148 {
1149 return this;
1150 }
1151
1152 virtual bool Accept(XMLVisitor* visitor) const;
1153
1154 virtual XMLNode* ShallowClone(XMLDocument* document) const;
1155 virtual bool ShallowEqual(const XMLNode* compare) const;
1156
1157 protected:
1158 XMLComment(XMLDocument* doc);
1159 virtual ~XMLComment();
1160
1161 char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);
1162
1163 private:
1164 XMLComment(const XMLComment&); // not supported
1165 XMLComment& operator=(const XMLComment&); // not supported
1166 };
1167
1168 /** In correct XML the declaration is the first entry in the file.
1169 @verbatim
1170 <?xml version="1.0" standalone="yes"?>
1171 @endverbatim
1172
1173 TinyXML-2 will happily read or write files without a declaration,
1174 however.
1175
1176 The text of the declaration isn't interpreted. It is parsed
1177 and written as a string.
1178 */
1179 class TINYXML2_LIB XMLDeclaration : public XMLNode
1180 {
1181 friend class XMLDocument;
1182
1183 public:
ToDeclaration()1184 virtual XMLDeclaration* ToDeclaration()
1185 {
1186 return this;
1187 }
ToDeclaration()1188 virtual const XMLDeclaration* ToDeclaration() const
1189 {
1190 return this;
1191 }
1192
1193 virtual bool Accept(XMLVisitor* visitor) const;
1194
1195 virtual XMLNode* ShallowClone(XMLDocument* document) const;
1196 virtual bool ShallowEqual(const XMLNode* compare) const;
1197
1198 protected:
1199 XMLDeclaration(XMLDocument* doc);
1200 virtual ~XMLDeclaration();
1201
1202 char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);
1203
1204 private:
1205 XMLDeclaration(const XMLDeclaration&); // not supported
1206 XMLDeclaration& operator=(const XMLDeclaration&); // not supported
1207 };
1208
1209 /** Any tag that TinyXML-2 doesn't recognize is saved as an
1210 unknown. It is a tag of text, but should not be modified.
1211 It will be written back to the XML, unchanged, when the file
1212 is saved.
1213
1214 DTD tags get thrown into XMLUnknowns.
1215 */
1216 class TINYXML2_LIB XMLUnknown : public XMLNode
1217 {
1218 friend class XMLDocument;
1219
1220 public:
ToUnknown()1221 virtual XMLUnknown* ToUnknown()
1222 {
1223 return this;
1224 }
ToUnknown()1225 virtual const XMLUnknown* ToUnknown() const
1226 {
1227 return this;
1228 }
1229
1230 virtual bool Accept(XMLVisitor* visitor) const;
1231
1232 virtual XMLNode* ShallowClone(XMLDocument* document) const;
1233 virtual bool ShallowEqual(const XMLNode* compare) const;
1234
1235 protected:
1236 XMLUnknown(XMLDocument* doc);
1237 virtual ~XMLUnknown();
1238
1239 char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);
1240
1241 private:
1242 XMLUnknown(const XMLUnknown&); // not supported
1243 XMLUnknown& operator=(const XMLUnknown&); // not supported
1244 };
1245
1246 /** An attribute is a name-value pair. Elements have an arbitrary
1247 number of attributes, each with a unique name.
1248
1249 @note The attributes are not XMLNodes. You may only query the
1250 Next() attribute in a list.
1251 */
1252 class TINYXML2_LIB XMLAttribute
1253 {
1254 friend class XMLElement;
1255
1256 public:
1257 /// The name of the attribute.
1258 const char* Name() const;
1259
1260 /// The value of the attribute.
1261 const char* Value() const;
1262
1263 /// Gets the line number the attribute is in, if the document was parsed from a file.
GetLineNum()1264 int GetLineNum() const { return _parseLineNum; }
1265
1266 /// The next attribute in the list.
Next()1267 const XMLAttribute* Next() const
1268 {
1269 return _next;
1270 }
1271
1272 /** IntValue interprets the attribute as an integer, and returns the value.
1273 If the value isn't an integer, 0 will be returned. There is no error checking;
1274 use QueryIntValue() if you need error checking.
1275 */
IntValue()1276 int IntValue() const
1277 {
1278 int i = 0;
1279 QueryIntValue(&i);
1280 return i;
1281 }
1282
Int64Value()1283 xml_Int64a_t Int64Value() const
1284 {
1285 xml_Int64a_t i = 0;
1286 QueryInt64Value(&i);
1287 return i;
1288 }
1289
1290 /// Query as an unsigned integer. See IntValue()
UnsignedValue()1291 unsigned UnsignedValue() const
1292 {
1293 unsigned i = 0;
1294 QueryUnsignedValue(&i);
1295 return i;
1296 }
1297 /// Query as a boolean. See IntValue()
BoolValue()1298 bool BoolValue() const
1299 {
1300 bool b = false;
1301 QueryBoolValue(&b);
1302 return b;
1303 }
1304 /// Query as a double. See IntValue()
DoubleValue()1305 double DoubleValue() const
1306 {
1307 double d = 0;
1308 QueryDoubleValue(&d);
1309 return d;
1310 }
1311 /// Query as a float. See IntValue()
FloatValue()1312 float FloatValue() const
1313 {
1314 float f = 0;
1315 QueryFloatValue(&f);
1316 return f;
1317 }
1318
1319 /** QueryIntValue interprets the attribute as an integer, and returns the value
1320 in the provided parameter. The function will return XML_SUCCESS on success,
1321 and XML_WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
1322 */
1323 XMLError QueryIntValue(int* value) const;
1324 /// See QueryIntValue
1325 XMLError QueryUnsignedValue(unsigned int* value) const;
1326 /// See QueryIntValue
1327 XMLError QueryInt64Value(xml_Int64a_t* value) const;
1328 /// See QueryIntValue
1329 XMLError QueryBoolValue(bool* value) const;
1330 /// See QueryIntValue
1331 XMLError QueryDoubleValue(double* value) const;
1332 /// See QueryIntValue
1333 XMLError QueryFloatValue(float* value) const;
1334
1335 /// Set the attribute to a string value.
1336 void SetAttribute(const char* value);
1337 /// Set the attribute to value.
1338 void SetAttribute(int value);
1339 /// Set the attribute to value.
1340 void SetAttribute(unsigned value);
1341 /// Set the attribute to value.
1342 void SetAttribute(xml_Int64a_t value);
1343 /// Set the attribute to value.
1344 void SetAttribute(bool value);
1345 /// Set the attribute to value.
1346 void SetAttribute(double value);
1347 /// Set the attribute to value.
1348 void SetAttribute(float value);
1349
1350 private:
1351 enum
1352 {
1353 BUF_SIZE = 200
1354 };
1355
XMLAttribute()1356 XMLAttribute() : _name(), _value(), _parseLineNum(0), _next(0), _memPool(0) {}
~XMLAttribute()1357 virtual ~XMLAttribute() {}
1358
1359 XMLAttribute(const XMLAttribute&); // not supported
1360 void operator=(const XMLAttribute&); // not supported
1361 void SetName(const char* name);
1362
1363 char* ParseDeep(char* p, bool processEntities, int* curLineNumPtr);
1364
1365 mutable StrPair _name;
1366 mutable StrPair _value;
1367 int _parseLineNum;
1368 XMLAttribute* _next;
1369 MemPool* _memPool;
1370 };
1371
1372 /** The element is a container class. It has a value, the element name,
1373 and can contain other elements, text, comments, and unknowns.
1374 Elements also contain an arbitrary number of attributes.
1375 */
1376 class TINYXML2_LIB XMLElement : public XMLNode
1377 {
1378 friend class XMLDocument;
1379
1380 public:
1381 /// Get the name of an element (which is the Value() of the node.)
Name()1382 const char* Name() const
1383 {
1384 return Value();
1385 }
1386 /// Set the name of the element.
1387 void SetName(const char* str, bool staticMem = false)
1388 {
1389 SetValue(str, staticMem);
1390 }
1391
ToElement()1392 virtual XMLElement* ToElement()
1393 {
1394 return this;
1395 }
ToElement()1396 virtual const XMLElement* ToElement() const
1397 {
1398 return this;
1399 }
1400 virtual bool Accept(XMLVisitor* visitor) const;
1401
1402 /** Given an attribute name, Attribute() returns the value
1403 for the attribute of that name, or null if none
1404 exists. For example:
1405
1406 @verbatim
1407 const char* value = ele->Attribute( "foo" );
1408 @endverbatim
1409
1410 The 'value' parameter is normally null. However, if specified,
1411 the attribute will only be returned if the 'name' and 'value'
1412 match. This allow you to write code:
1413
1414 @verbatim
1415 if ( ele->Attribute( "foo", "bar" ) ) callFooIsBar();
1416 @endverbatim
1417
1418 rather than:
1419 @verbatim
1420 if ( ele->Attribute( "foo" ) ) {
1421 if ( strcmp( ele->Attribute( "foo" ), "bar" ) == 0 ) callFooIsBar();
1422 }
1423 @endverbatim
1424 */
1425 const char* Attribute(const char* name, const char* value = 0) const;
1426
1427 /** Given an attribute name, IntAttribute() returns the value
1428 of the attribute interpreted as an integer. The default
1429 value will be returned if the attribute isn't present,
1430 or if there is an error. (For a method with error
1431 checking, see QueryIntAttribute()).
1432 */
1433 int IntAttribute(const char* name, int defaultValue = 0) const;
1434 /// See IntAttribute()
1435 unsigned UnsignedAttribute(const char* name, unsigned defaultValue = 0) const;
1436 /// See IntAttribute()
1437 xml_Int64a_t Int64Attribute(const char* name, xml_Int64a_t defaultValue = 0) const;
1438 /// See IntAttribute()
1439 bool BoolAttribute(const char* name, bool defaultValue = false) const;
1440 /// See IntAttribute()
1441 double DoubleAttribute(const char* name, double defaultValue = 0) const;
1442 /// See IntAttribute()
1443 float FloatAttribute(const char* name, float defaultValue = 0) const;
1444
1445 /** Given an attribute name, QueryIntAttribute() returns
1446 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1447 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1448 doesn't exist. If successful, the result of the conversion
1449 will be written to 'value'. If not successful, nothing will
1450 be written to 'value'. This allows you to provide default
1451 value:
1452
1453 @verbatim
1454 int value = 10;
1455 QueryIntAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1456 @endverbatim
1457 */
QueryIntAttribute(const char * name,int * value)1458 XMLError QueryIntAttribute(const char* name, int* value) const
1459 {
1460 const XMLAttribute* a = FindAttribute(name);
1461 if (!a)
1462 {
1463 return XML_NO_ATTRIBUTE;
1464 }
1465 return a->QueryIntValue(value);
1466 }
1467
1468 /// See QueryIntAttribute()
QueryUnsignedAttribute(const char * name,unsigned int * value)1469 XMLError QueryUnsignedAttribute(const char* name, unsigned int* value) const
1470 {
1471 const XMLAttribute* a = FindAttribute(name);
1472 if (!a)
1473 {
1474 return XML_NO_ATTRIBUTE;
1475 }
1476 return a->QueryUnsignedValue(value);
1477 }
1478
1479 /// See QueryIntAttribute()
QueryInt64Attribute(const char * name,xml_Int64a_t * value)1480 XMLError QueryInt64Attribute(const char* name, xml_Int64a_t* value) const
1481 {
1482 const XMLAttribute* a = FindAttribute(name);
1483 if (!a)
1484 {
1485 return XML_NO_ATTRIBUTE;
1486 }
1487 return a->QueryInt64Value(value);
1488 }
1489
1490 /// See QueryIntAttribute()
QueryBoolAttribute(const char * name,bool * value)1491 XMLError QueryBoolAttribute(const char* name, bool* value) const
1492 {
1493 const XMLAttribute* a = FindAttribute(name);
1494 if (!a)
1495 {
1496 return XML_NO_ATTRIBUTE;
1497 }
1498 return a->QueryBoolValue(value);
1499 }
1500 /// See QueryIntAttribute()
QueryDoubleAttribute(const char * name,double * value)1501 XMLError QueryDoubleAttribute(const char* name, double* value) const
1502 {
1503 const XMLAttribute* a = FindAttribute(name);
1504 if (!a)
1505 {
1506 return XML_NO_ATTRIBUTE;
1507 }
1508 return a->QueryDoubleValue(value);
1509 }
1510 /// See QueryIntAttribute()
QueryFloatAttribute(const char * name,float * value)1511 XMLError QueryFloatAttribute(const char* name, float* value) const
1512 {
1513 const XMLAttribute* a = FindAttribute(name);
1514 if (!a)
1515 {
1516 return XML_NO_ATTRIBUTE;
1517 }
1518 return a->QueryFloatValue(value);
1519 }
1520
1521 /// See QueryIntAttribute()
QueryStringAttribute(const char * name,const char ** value)1522 XMLError QueryStringAttribute(const char* name, const char** value) const
1523 {
1524 const XMLAttribute* a = FindAttribute(name);
1525 if (!a)
1526 {
1527 return XML_NO_ATTRIBUTE;
1528 }
1529 *value = a->Value();
1530 return XML_SUCCESS;
1531 }
1532
1533 /** Given an attribute name, QueryAttribute() returns
1534 XML_SUCCESS, XML_WRONG_ATTRIBUTE_TYPE if the conversion
1535 can't be performed, or XML_NO_ATTRIBUTE if the attribute
1536 doesn't exist. It is overloaded for the primitive types,
1537 and is a generally more convenient replacement of
1538 QueryIntAttribute() and related functions.
1539
1540 If successful, the result of the conversion
1541 will be written to 'value'. If not successful, nothing will
1542 be written to 'value'. This allows you to provide default
1543 value:
1544
1545 @verbatim
1546 int value = 10;
1547 QueryAttribute( "foo", &value ); // if "foo" isn't found, value will still be 10
1548 @endverbatim
1549 */
QueryAttribute(const char * name,int * value)1550 int QueryAttribute(const char* name, int* value) const
1551 {
1552 return QueryIntAttribute(name, value);
1553 }
1554
QueryAttribute(const char * name,unsigned int * value)1555 int QueryAttribute(const char* name, unsigned int* value) const
1556 {
1557 return QueryUnsignedAttribute(name, value);
1558 }
1559
QueryAttribute(const char * name,xml_Int64a_t * value)1560 int QueryAttribute(const char* name, xml_Int64a_t* value) const
1561 {
1562 return QueryInt64Attribute(name, value);
1563 }
1564
QueryAttribute(const char * name,bool * value)1565 int QueryAttribute(const char* name, bool* value) const
1566 {
1567 return QueryBoolAttribute(name, value);
1568 }
1569
QueryAttribute(const char * name,double * value)1570 int QueryAttribute(const char* name, double* value) const
1571 {
1572 return QueryDoubleAttribute(name, value);
1573 }
1574
QueryAttribute(const char * name,float * value)1575 int QueryAttribute(const char* name, float* value) const
1576 {
1577 return QueryFloatAttribute(name, value);
1578 }
1579
1580 /// Sets the named attribute to value.
SetAttribute(const char * name,const char * value)1581 void SetAttribute(const char* name, const char* value)
1582 {
1583 XMLAttribute* a = FindOrCreateAttribute(name);
1584 a->SetAttribute(value);
1585 }
1586 /// Sets the named attribute to value.
SetAttribute(const char * name,int value)1587 void SetAttribute(const char* name, int value)
1588 {
1589 XMLAttribute* a = FindOrCreateAttribute(name);
1590 a->SetAttribute(value);
1591 }
1592 /// Sets the named attribute to value.
SetAttribute(const char * name,unsigned value)1593 void SetAttribute(const char* name, unsigned value)
1594 {
1595 XMLAttribute* a = FindOrCreateAttribute(name);
1596 a->SetAttribute(value);
1597 }
1598
1599 /// Sets the named attribute to value.
SetAttribute(const char * name,xml_Int64a_t value)1600 void SetAttribute(const char* name, xml_Int64a_t value)
1601 {
1602 XMLAttribute* a = FindOrCreateAttribute(name);
1603 a->SetAttribute(value);
1604 }
1605
1606 /// Sets the named attribute to value.
SetAttribute(const char * name,bool value)1607 void SetAttribute(const char* name, bool value)
1608 {
1609 XMLAttribute* a = FindOrCreateAttribute(name);
1610 a->SetAttribute(value);
1611 }
1612 /// Sets the named attribute to value.
SetAttribute(const char * name,double value)1613 void SetAttribute(const char* name, double value)
1614 {
1615 XMLAttribute* a = FindOrCreateAttribute(name);
1616 a->SetAttribute(value);
1617 }
1618 /// Sets the named attribute to value.
SetAttribute(const char * name,float value)1619 void SetAttribute(const char* name, float value)
1620 {
1621 XMLAttribute* a = FindOrCreateAttribute(name);
1622 a->SetAttribute(value);
1623 }
1624
1625 /**
1626 Delete an attribute.
1627 */
1628 void DeleteAttribute(const char* name);
1629
1630 /// Return the first attribute in the list.
FirstAttribute()1631 const XMLAttribute* FirstAttribute() const
1632 {
1633 return _rootAttribute;
1634 }
1635 /// Query a specific attribute in the list.
1636 const XMLAttribute* FindAttribute(const char* name) const;
1637
1638 /** Convenience function for easy access to the text inside an element. Although easy
1639 and concise, GetText() is limited compared to getting the XMLText child
1640 and accessing it directly.
1641
1642 If the first child of 'this' is a XMLText, the GetText()
1643 returns the character string of the Text node, else null is returned.
1644
1645 This is a convenient method for getting the text of simple contained text:
1646 @verbatim
1647 <foo>This is text</foo>
1648 const char* str = fooElement->GetText();
1649 @endverbatim
1650
1651 'str' will be a pointer to "This is text".
1652
1653 Note that this function can be misleading. If the element foo was created from
1654 this XML:
1655 @verbatim
1656 <foo><b>This is text</b></foo>
1657 @endverbatim
1658
1659 then the value of str would be null. The first child node isn't a text node, it is
1660 another element. From this XML:
1661 @verbatim
1662 <foo>This is <b>text</b></foo>
1663 @endverbatim
1664 GetText() will return "This is ".
1665 */
1666 const char* GetText() const;
1667
1668 /** Convenience function for easy access to the text inside an element. Although easy
1669 and concise, SetText() is limited compared to creating an XMLText child
1670 and mutating it directly.
1671
1672 If the first child of 'this' is a XMLText, SetText() sets its value to
1673 the given string, otherwise it will create a first child that is an XMLText.
1674
1675 This is a convenient method for setting the text of simple contained text:
1676 @verbatim
1677 <foo>This is text</foo>
1678 fooElement->SetText( "Hullaballoo!" );
1679 <foo>Hullaballoo!</foo>
1680 @endverbatim
1681
1682 Note that this function can be misleading. If the element foo was created from
1683 this XML:
1684 @verbatim
1685 <foo><b>This is text</b></foo>
1686 @endverbatim
1687
1688 then it will not change "This is text", but rather prefix it with a text element:
1689 @verbatim
1690 <foo>Hullaballoo!<b>This is text</b></foo>
1691 @endverbatim
1692
1693 For this XML:
1694 @verbatim
1695 <foo />
1696 @endverbatim
1697 SetText() will generate
1698 @verbatim
1699 <foo>Hullaballoo!</foo>
1700 @endverbatim
1701 */
1702 void SetText(const char* inText);
1703 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1704 void SetText(int value);
1705 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1706 void SetText(unsigned value);
1707 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1708 void SetText(xml_Int64a_t value);
1709 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1710 void SetText(bool value);
1711 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1712 void SetText(double value);
1713 /// Convenience method for setting text inside an element. See SetText() for important limitations.
1714 void SetText(float value);
1715
1716 /**
1717 Convenience method to query the value of a child text node. This is probably best
1718 shown by example. Given you have a document is this form:
1719 @verbatim
1720 <point>
1721 <x>1</x>
1722 <y>1.4</y>
1723 </point>
1724 @endverbatim
1725
1726 The QueryIntText() and similar functions provide a safe and easier way to get to the
1727 "value" of x and y.
1728
1729 @verbatim
1730 int x = 0;
1731 float y = 0; // types of x and y are contrived for example
1732 const XMLElement* xElement = pointElement->FirstChildElement( "x" );
1733 const XMLElement* yElement = pointElement->FirstChildElement( "y" );
1734 xElement->QueryIntText( &x );
1735 yElement->QueryFloatText( &y );
1736 @endverbatim
1737
1738 @returns XML_SUCCESS (0) on success, XML_CAN_NOT_CONVERT_TEXT if the text cannot be converted
1739 to the requested type, and XML_NO_TEXT_NODE if there is no child text to query.
1740
1741 */
1742 XMLError QueryIntText(int* ival) const;
1743 /// See QueryIntText()
1744 XMLError QueryUnsignedText(unsigned* uval) const;
1745 /// See QueryIntText()
1746 XMLError QueryInt64Text(xml_Int64a_t* uval) const;
1747 /// See QueryIntText()
1748 XMLError QueryBoolText(bool* bval) const;
1749 /// See QueryIntText()
1750 XMLError QueryDoubleText(double* dval) const;
1751 /// See QueryIntText()
1752 XMLError QueryFloatText(float* fval) const;
1753
1754 int IntText(int defaultValue = 0) const;
1755
1756 /// See QueryIntText()
1757 unsigned UnsignedText(unsigned defaultValue = 0) const;
1758 /// See QueryIntText()
1759 xml_Int64a_t Int64Text(xml_Int64a_t defaultValue = 0) const;
1760 /// See QueryIntText()
1761 bool BoolText(bool defaultValue = false) const;
1762 /// See QueryIntText()
1763 double DoubleText(double defaultValue = 0) const;
1764 /// See QueryIntText()
1765 float FloatText(float defaultValue = 0) const;
1766
1767 // internal:
1768 enum ElementClosingType
1769 {
1770 OPEN, // <foo>
1771 CLOSED, // <foo/>
1772 CLOSING // </foo>
1773 };
ClosingType()1774 ElementClosingType ClosingType() const
1775 {
1776 return _closingType;
1777 }
1778 virtual XMLNode* ShallowClone(XMLDocument* document) const;
1779 virtual bool ShallowEqual(const XMLNode* compare) const;
1780
1781 protected:
1782 char* ParseDeep(char* p, StrPair* parentEndTag, int* curLineNumPtr);
1783
1784 private:
1785 XMLElement(XMLDocument* doc);
1786 virtual ~XMLElement();
1787 XMLElement(const XMLElement&); // not supported
1788 void operator=(const XMLElement&); // not supported
1789
FindAttribute(const char * name)1790 XMLAttribute* FindAttribute(const char* name)
1791 {
1792 return const_cast<XMLAttribute*>(const_cast<const XMLElement*>(this)->FindAttribute(name));
1793 }
1794 XMLAttribute* FindOrCreateAttribute(const char* name);
1795 //void LinkAttribute( XMLAttribute* attrib );
1796 char* ParseAttributes(char* p, int* curLineNumPtr);
1797 static void DeleteAttribute(XMLAttribute* attribute);
1798 XMLAttribute* CreateAttribute();
1799
1800 enum
1801 {
1802 BUF_SIZE = 200
1803 };
1804 ElementClosingType _closingType;
1805 // The attribute list is ordered; there is no 'lastAttribute'
1806 // because the list needs to be scanned for dupes before adding
1807 // a new attribute.
1808 XMLAttribute* _rootAttribute;
1809 };
1810
1811 enum Whitespace
1812 {
1813 PRESERVE_WHITESPACE,
1814 COLLAPSE_WHITESPACE
1815 };
1816
1817 /** A Document binds together all the functionality.
1818 It can be saved, loaded, and printed to the screen.
1819 All Nodes are connected and allocated to a Document.
1820 If the Document is deleted, all its Nodes are also deleted.
1821 */
1822 class TINYXML2_LIB XMLDocument : public XMLNode
1823 {
1824 friend class XMLElement;
1825 // Gives access to SetError and Push/PopDepth, but over-access for everything else.
1826 // Wishing C++ had "internal" scope.
1827 friend class XMLNode;
1828 friend class XMLText;
1829 friend class XMLComment;
1830 friend class XMLDeclaration;
1831 friend class XMLUnknown;
1832
1833 public:
1834 /// constructor
1835 XMLDocument(bool processEntities = true, Whitespace whitespaceMode = PRESERVE_WHITESPACE);
1836 ~XMLDocument();
1837
ToDocument()1838 virtual XMLDocument* ToDocument()
1839 {
1840 TIXMLASSERT(this == _document);
1841 return this;
1842 }
ToDocument()1843 virtual const XMLDocument* ToDocument() const
1844 {
1845 TIXMLASSERT(this == _document);
1846 return this;
1847 }
1848
1849 /**
1850 Parse an XML file from a character string.
1851 Returns XML_SUCCESS (0) on success, or
1852 an errorID.
1853
1854 You may optionally pass in the 'nBytes', which is
1855 the number of bytes which will be parsed. If not
1856 specified, TinyXML-2 will assume 'xml' points to a
1857 null terminated string.
1858 */
1859 XMLError Parse(const char* xml, size_t nBytes = (size_t)(-1));
1860
1861 /**
1862 Load an XML file from disk.
1863 Returns XML_SUCCESS (0) on success, or
1864 an errorID.
1865 */
1866 XMLError LoadFile(const char* filename);
1867
1868 /**
1869 Load an XML file from disk. You are responsible
1870 for providing and closing the FILE*.
1871
1872 NOTE: The file should be opened as binary ("rb")
1873 not text in order for TinyXML-2 to correctly
1874 do newline normalization.
1875
1876 Returns XML_SUCCESS (0) on success, or
1877 an errorID.
1878 */
1879 XMLError LoadFile(FILE*);
1880
1881 /**
1882 Save the XML file to disk.
1883 Returns XML_SUCCESS (0) on success, or
1884 an errorID.
1885 */
1886 XMLError SaveFile(const char* filename, bool compact = false);
1887
1888 /**
1889 Save the XML file to disk. You are responsible
1890 for providing and closing the FILE*.
1891
1892 Returns XML_SUCCESS (0) on success, or
1893 an errorID.
1894 */
1895 XMLError SaveFile(FILE* fp, bool compact = false);
1896
ProcessEntities()1897 bool ProcessEntities() const
1898 {
1899 return _processEntities;
1900 }
WhitespaceMode()1901 Whitespace WhitespaceMode() const
1902 {
1903 return _whitespaceMode;
1904 }
1905
1906 /**
1907 Returns true if this document has a leading Byte Order Mark of UTF8.
1908 */
HasBOM()1909 bool HasBOM() const
1910 {
1911 return _writeBOM;
1912 }
1913 /** Sets whether to write the BOM when writing the file.
1914 */
SetBOM(bool useBOM)1915 void SetBOM(bool useBOM)
1916 {
1917 _writeBOM = useBOM;
1918 }
1919
1920 /** Return the root element of DOM. Equivalent to FirstChildElement().
1921 To get the first node, use FirstChild().
1922 */
RootElement()1923 XMLElement* RootElement()
1924 {
1925 return FirstChildElement();
1926 }
RootElement()1927 const XMLElement* RootElement() const
1928 {
1929 return FirstChildElement();
1930 }
1931
1932 /** Print the Document. If the Printer is not provided, it will
1933 print to stdout. If you provide Printer, this can print to a file:
1934 @verbatim
1935 XMLPrinter printer( fp );
1936 doc.Print( &printer );
1937 @endverbatim
1938
1939 Or you can use a printer to print to memory:
1940 @verbatim
1941 XMLPrinter printer;
1942 doc.Print( &printer );
1943 // printer.CStr() has a const char* to the XML
1944 @endverbatim
1945 */
1946 void Print(XMLPrinter* streamer = 0) const;
1947 virtual bool Accept(XMLVisitor* visitor) const;
1948
1949 /**
1950 Create a new Element associated with
1951 this Document. The memory for the Element
1952 is managed by the Document.
1953 */
1954 XMLElement* NewElement(const char* name);
1955 /**
1956 Create a new Comment associated with
1957 this Document. The memory for the Comment
1958 is managed by the Document.
1959 */
1960 XMLComment* NewComment(const char* comment);
1961 /**
1962 Create a new Text associated with
1963 this Document. The memory for the Text
1964 is managed by the Document.
1965 */
1966 XMLText* NewText(const char* text);
1967 /**
1968 Create a new Declaration associated with
1969 this Document. The memory for the object
1970 is managed by the Document.
1971
1972 If the 'text' param is null, the standard
1973 declaration is used.:
1974 @verbatim
1975 <?xml version="1.0" encoding="UTF-8"?>
1976 @endverbatim
1977 */
1978 XMLDeclaration* NewDeclaration(const char* text = 0);
1979 /**
1980 Create a new Unknown associated with
1981 this Document. The memory for the object
1982 is managed by the Document.
1983 */
1984 XMLUnknown* NewUnknown(const char* text);
1985
1986 /**
1987 Delete a node associated with this document.
1988 It will be unlinked from the DOM.
1989 */
1990 void DeleteNode(XMLNode* node);
1991
ClearError()1992 void ClearError()
1993 {
1994 SetError(XML_SUCCESS, 0, 0);
1995 }
1996
1997 /// Return true if there was an error parsing the document.
Error()1998 bool Error() const
1999 {
2000 return _errorID != XML_SUCCESS;
2001 }
2002 /// Return the errorID.
ErrorID()2003 XMLError ErrorID() const
2004 {
2005 return _errorID;
2006 }
2007 const char* ErrorName() const;
2008 static const char* ErrorIDToName(XMLError errorID);
2009
2010 /** Returns a "long form" error description. A hopefully helpful
2011 diagnostic with location, line number, and/or additional info.
2012 */
2013 const char* ErrorStr() const;
2014
2015 /// A (trivial) utility function that prints the ErrorStr() to stdout.
2016 void PrintError() const;
2017
2018 /// Return the line where the error occured, or zero if unknown.
ErrorLineNum()2019 int ErrorLineNum() const
2020 {
2021 return _errorLineNum;
2022 }
2023
2024 /// Clear the document, resetting it to the initial state.
2025 void Clear();
2026
2027 /**
2028 Copies this document to a target document.
2029 The target will be completely cleared before the copy.
2030 If you want to copy a sub-tree, see XMLNode::DeepClone().
2031
2032 NOTE: that the 'target' must be non-null.
2033 */
2034 void DeepCopy(XMLDocument* target) const;
2035
2036 // internal
2037 char* Identify(char* p, XMLNode** node);
2038
2039 // internal
2040 void MarkInUse(XMLNode*);
2041
ShallowClone(XMLDocument *)2042 virtual XMLNode* ShallowClone(XMLDocument* /*document*/) const
2043 {
2044 return 0;
2045 }
ShallowEqual(const XMLNode *)2046 virtual bool ShallowEqual(const XMLNode* /*compare*/) const
2047 {
2048 return false;
2049 }
2050
2051 private:
2052 XMLDocument(const XMLDocument&); // not supported
2053 void operator=(const XMLDocument&); // not supported
2054
2055 bool _writeBOM;
2056 bool _processEntities;
2057 XMLError _errorID;
2058 Whitespace _whitespaceMode;
2059 mutable StrPair _errorStr;
2060 int _errorLineNum;
2061 char* _charBuffer;
2062 int _parseCurLineNum;
2063 int _parsingDepth;
2064 // Memory tracking does add some overhead.
2065 // However, the code assumes that you don't
2066 // have a bunch of unlinked nodes around.
2067 // Therefore it takes less memory to track
2068 // in the document vs. a linked list in the XMLNode,
2069 // and the performance is the same.
2070 DynArray<XMLNode*, 10> _unlinked;
2071
2072 MemPoolT<sizeof(XMLElement)> _elementPool;
2073 MemPoolT<sizeof(XMLAttribute)> _attributePool;
2074 MemPoolT<sizeof(XMLText)> _textPool;
2075 MemPoolT<sizeof(XMLComment)> _commentPool;
2076
2077 static const char* _errorNames[XML_ERROR_COUNT];
2078
2079 void Parse();
2080
2081 void SetError(XMLError error, int lineNum, const char* format, ...);
2082
2083 // Something of an obvious security hole, once it was discovered.
2084 // Either an ill-formed XML or an excessively deep one can overflow
2085 // the stack. Track stack depth, and error out if needed.
2086 class DepthTracker
2087 {
2088 public:
DepthTracker(XMLDocument * document)2089 DepthTracker(XMLDocument* document)
2090 {
2091 this->_document = document;
2092 document->PushDepth();
2093 }
~DepthTracker()2094 ~DepthTracker()
2095 {
2096 _document->PopDepth();
2097 }
2098
2099 private:
2100 XMLDocument* _document;
2101 };
2102 void PushDepth();
2103 void PopDepth();
2104
2105 template <class NodeType, int PoolElementSize>
2106 NodeType* CreateUnlinkedNode(MemPoolT<PoolElementSize>& pool);
2107 };
2108
2109 template <class NodeType, int PoolElementSize>
CreateUnlinkedNode(MemPoolT<PoolElementSize> & pool)2110 inline NodeType* XMLDocument::CreateUnlinkedNode(MemPoolT<PoolElementSize>& pool)
2111 {
2112 TIXMLASSERT(sizeof(NodeType) == PoolElementSize);
2113 TIXMLASSERT(sizeof(NodeType) == pool.ItemSize());
2114 NodeType* returnNode = new (pool.Alloc()) NodeType(this);
2115 TIXMLASSERT(returnNode);
2116 returnNode->_memPool = &pool;
2117
2118 _unlinked.Push(returnNode);
2119 return returnNode;
2120 }
2121
2122 /**
2123 A XMLHandle is a class that wraps a node pointer with null checks; this is
2124 an incredibly useful thing. Note that XMLHandle is not part of the TinyXML-2
2125 DOM structure. It is a separate utility class.
2126
2127 Take an example:
2128 @verbatim
2129 <Document>
2130 <Element attributeA = "valueA">
2131 <Child attributeB = "value1" />
2132 <Child attributeB = "value2" />
2133 </Element>
2134 </Document>
2135 @endverbatim
2136
2137 Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
2138 easy to write a *lot* of code that looks like:
2139
2140 @verbatim
2141 XMLElement* root = document.FirstChildElement( "Document" );
2142 if ( root )
2143 {
2144 XMLElement* element = root->FirstChildElement( "Element" );
2145 if ( element )
2146 {
2147 XMLElement* child = element->FirstChildElement( "Child" );
2148 if ( child )
2149 {
2150 XMLElement* child2 = child->NextSiblingElement( "Child" );
2151 if ( child2 )
2152 {
2153 // Finally do something useful.
2154 @endverbatim
2155
2156 And that doesn't even cover "else" cases. XMLHandle addresses the verbosity
2157 of such code. A XMLHandle checks for null pointers so it is perfectly safe
2158 and correct to use:
2159
2160 @verbatim
2161 XMLHandle docHandle( &document );
2162 XMLElement* child2 = docHandle.FirstChildElement( "Document" ).FirstChildElement( "Element" ).FirstChildElement().NextSiblingElement();
2163 if ( child2 )
2164 {
2165 // do something useful
2166 @endverbatim
2167
2168 Which is MUCH more concise and useful.
2169
2170 It is also safe to copy handles - internally they are nothing more than node pointers.
2171 @verbatim
2172 XMLHandle handleCopy = handle;
2173 @endverbatim
2174
2175 See also XMLConstHandle, which is the same as XMLHandle, but operates on const objects.
2176 */
2177 class TINYXML2_LIB XMLHandle
2178 {
2179 public:
2180 /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
XMLHandle(XMLNode * node)2181 XMLHandle(XMLNode* node) : _node(node)
2182 {
2183 }
2184 /// Create a handle from a node.
XMLHandle(XMLNode & node)2185 XMLHandle(XMLNode& node) : _node(&node)
2186 {
2187 }
2188 /// Copy constructor
XMLHandle(const XMLHandle & ref)2189 XMLHandle(const XMLHandle& ref) : _node(ref._node)
2190 {
2191 }
2192 /// Assignment
2193 XMLHandle& operator=(const XMLHandle& ref)
2194 {
2195 _node = ref._node;
2196 return *this;
2197 }
2198
2199 /// Get the first child of this handle.
FirstChild()2200 XMLHandle FirstChild()
2201 {
2202 return XMLHandle(_node ? _node->FirstChild() : 0);
2203 }
2204 /// Get the first child element of this handle.
2205 XMLHandle FirstChildElement(const char* name = 0)
2206 {
2207 return XMLHandle(_node ? _node->FirstChildElement(name) : 0);
2208 }
2209 /// Get the last child of this handle.
LastChild()2210 XMLHandle LastChild()
2211 {
2212 return XMLHandle(_node ? _node->LastChild() : 0);
2213 }
2214 /// Get the last child element of this handle.
2215 XMLHandle LastChildElement(const char* name = 0)
2216 {
2217 return XMLHandle(_node ? _node->LastChildElement(name) : 0);
2218 }
2219 /// Get the previous sibling of this handle.
PreviousSibling()2220 XMLHandle PreviousSibling()
2221 {
2222 return XMLHandle(_node ? _node->PreviousSibling() : 0);
2223 }
2224 /// Get the previous sibling element of this handle.
2225 XMLHandle PreviousSiblingElement(const char* name = 0)
2226 {
2227 return XMLHandle(_node ? _node->PreviousSiblingElement(name) : 0);
2228 }
2229 /// Get the next sibling of this handle.
NextSibling()2230 XMLHandle NextSibling()
2231 {
2232 return XMLHandle(_node ? _node->NextSibling() : 0);
2233 }
2234 /// Get the next sibling element of this handle.
2235 XMLHandle NextSiblingElement(const char* name = 0)
2236 {
2237 return XMLHandle(_node ? _node->NextSiblingElement(name) : 0);
2238 }
2239
2240 /// Safe cast to XMLNode. This can return null.
ToNode()2241 XMLNode* ToNode()
2242 {
2243 return _node;
2244 }
2245 /// Safe cast to XMLElement. This can return null.
ToElement()2246 XMLElement* ToElement()
2247 {
2248 return (_node ? _node->ToElement() : 0);
2249 }
2250 /// Safe cast to XMLText. This can return null.
ToText()2251 XMLText* ToText()
2252 {
2253 return (_node ? _node->ToText() : 0);
2254 }
2255 /// Safe cast to XMLUnknown. This can return null.
ToUnknown()2256 XMLUnknown* ToUnknown()
2257 {
2258 return (_node ? _node->ToUnknown() : 0);
2259 }
2260 /// Safe cast to XMLDeclaration. This can return null.
ToDeclaration()2261 XMLDeclaration* ToDeclaration()
2262 {
2263 return (_node ? _node->ToDeclaration() : 0);
2264 }
2265
2266 private:
2267 XMLNode* _node;
2268 };
2269
2270 /**
2271 A variant of the XMLHandle class for working with const XMLNodes and Documents. It is the
2272 same in all regards, except for the 'const' qualifiers. See XMLHandle for API.
2273 */
2274 class TINYXML2_LIB XMLConstHandle
2275 {
2276 public:
XMLConstHandle(const XMLNode * node)2277 XMLConstHandle(const XMLNode* node) : _node(node)
2278 {
2279 }
XMLConstHandle(const XMLNode & node)2280 XMLConstHandle(const XMLNode& node) : _node(&node)
2281 {
2282 }
XMLConstHandle(const XMLConstHandle & ref)2283 XMLConstHandle(const XMLConstHandle& ref) : _node(ref._node)
2284 {
2285 }
2286
2287 XMLConstHandle& operator=(const XMLConstHandle& ref)
2288 {
2289 _node = ref._node;
2290 return *this;
2291 }
2292
FirstChild()2293 const XMLConstHandle FirstChild() const
2294 {
2295 return XMLConstHandle(_node ? _node->FirstChild() : 0);
2296 }
2297 const XMLConstHandle FirstChildElement(const char* name = 0) const
2298 {
2299 return XMLConstHandle(_node ? _node->FirstChildElement(name) : 0);
2300 }
LastChild()2301 const XMLConstHandle LastChild() const
2302 {
2303 return XMLConstHandle(_node ? _node->LastChild() : 0);
2304 }
2305 const XMLConstHandle LastChildElement(const char* name = 0) const
2306 {
2307 return XMLConstHandle(_node ? _node->LastChildElement(name) : 0);
2308 }
PreviousSibling()2309 const XMLConstHandle PreviousSibling() const
2310 {
2311 return XMLConstHandle(_node ? _node->PreviousSibling() : 0);
2312 }
2313 const XMLConstHandle PreviousSiblingElement(const char* name = 0) const
2314 {
2315 return XMLConstHandle(_node ? _node->PreviousSiblingElement(name) : 0);
2316 }
NextSibling()2317 const XMLConstHandle NextSibling() const
2318 {
2319 return XMLConstHandle(_node ? _node->NextSibling() : 0);
2320 }
2321 const XMLConstHandle NextSiblingElement(const char* name = 0) const
2322 {
2323 return XMLConstHandle(_node ? _node->NextSiblingElement(name) : 0);
2324 }
2325
ToNode()2326 const XMLNode* ToNode() const
2327 {
2328 return _node;
2329 }
ToElement()2330 const XMLElement* ToElement() const
2331 {
2332 return (_node ? _node->ToElement() : 0);
2333 }
ToText()2334 const XMLText* ToText() const
2335 {
2336 return (_node ? _node->ToText() : 0);
2337 }
ToUnknown()2338 const XMLUnknown* ToUnknown() const
2339 {
2340 return (_node ? _node->ToUnknown() : 0);
2341 }
ToDeclaration()2342 const XMLDeclaration* ToDeclaration() const
2343 {
2344 return (_node ? _node->ToDeclaration() : 0);
2345 }
2346
2347 private:
2348 const XMLNode* _node;
2349 };
2350
2351 /**
2352 Printing functionality. The XMLPrinter gives you more
2353 options than the XMLDocument::Print() method.
2354
2355 It can:
2356 -# Print to memory.
2357 -# Print to a file you provide.
2358 -# Print XML without a XMLDocument.
2359
2360 Print to Memory
2361
2362 @verbatim
2363 XMLPrinter printer;
2364 doc.Print( &printer );
2365 SomeFunction( printer.CStr() );
2366 @endverbatim
2367
2368 Print to a File
2369
2370 You provide the file pointer.
2371 @verbatim
2372 XMLPrinter printer( fp );
2373 doc.Print( &printer );
2374 @endverbatim
2375
2376 Print without a XMLDocument
2377
2378 When loading, an XML parser is very useful. However, sometimes
2379 when saving, it just gets in the way. The code is often set up
2380 for streaming, and constructing the DOM is just overhead.
2381
2382 The Printer supports the streaming case. The following code
2383 prints out a trivially simple XML file without ever creating
2384 an XML document.
2385
2386 @verbatim
2387 XMLPrinter printer( fp );
2388 printer.OpenElement( "foo" );
2389 printer.PushAttribute( "foo", "bar" );
2390 printer.CloseElement();
2391 @endverbatim
2392 */
2393 class TINYXML2_LIB XMLPrinter : public XMLVisitor
2394 {
2395 public:
2396 /** Construct the printer. If the FILE* is specified,
2397 this will print to the FILE. Else it will print
2398 to memory, and the result is available in CStr().
2399 If 'compact' is set to true, then output is created
2400 with only required whitespace and newlines.
2401 */
2402 XMLPrinter(FILE* file = 0, bool compact = false, int depth = 0);
~XMLPrinter()2403 virtual ~XMLPrinter() {}
2404
2405 /** If streaming, write the BOM and declaration. */
2406 void PushHeader(bool writeBOM, bool writeDeclaration);
2407 /** If streaming, start writing an element.
2408 The element must be closed with CloseElement()
2409 */
2410 void OpenElement(const char* name, bool compactMode = false);
2411 /// If streaming, add an attribute to an open element.
2412 void PushAttribute(const char* name, const char* value);
2413 void PushAttribute(const char* name, int value);
2414 void PushAttribute(const char* name, unsigned value);
2415 void PushAttribute(const char* name, xml_Int64a_t value);
2416 void PushAttribute(const char* name, bool value);
2417 void PushAttribute(const char* name, double value);
2418 /// If streaming, close the Element.
2419 virtual void CloseElement(bool compactMode = false);
2420
2421 /// Add a text node.
2422 void PushText(const char* text, bool cdata = false);
2423 /// Add a text node from an integer.
2424 void PushText(int value);
2425 /// Add a text node from an unsigned.
2426 void PushText(unsigned value);
2427 /// Add a text node from an unsigned.
2428 void PushText(xml_Int64a_t value);
2429 /// Add a text node from a bool.
2430 void PushText(bool value);
2431 /// Add a text node from a float.
2432 void PushText(float value);
2433 /// Add a text node from a double.
2434 void PushText(double value);
2435
2436 /// Add a comment
2437 void PushComment(const char* comment);
2438
2439 void PushDeclaration(const char* value);
2440 void PushUnknown(const char* value);
2441
2442 virtual bool VisitEnter(const XMLDocument& /*doc*/);
VisitExit(const XMLDocument &)2443 virtual bool VisitExit(const XMLDocument& /*doc*/)
2444 {
2445 return true;
2446 }
2447
2448 virtual bool VisitEnter(const XMLElement& element, const XMLAttribute* attribute);
2449 virtual bool VisitExit(const XMLElement& element);
2450
2451 virtual bool Visit(const XMLText& text);
2452 virtual bool Visit(const XMLComment& comment);
2453 virtual bool Visit(const XMLDeclaration& declaration);
2454 virtual bool Visit(const XMLUnknown& unknown);
2455
2456 /**
2457 If in print to memory mode, return a pointer to
2458 the XML file in memory.
2459 */
CStr()2460 const char* CStr() const
2461 {
2462 return _buffer.Mem();
2463 }
2464 /**
2465 If in print to memory mode, return the size
2466 of the XML file in memory. (Note the size returned
2467 includes the terminating null.)
2468 */
CStrSize()2469 int CStrSize() const
2470 {
2471 return _buffer.Size();
2472 }
2473 /**
2474 If in print to memory mode, reset the buffer to the
2475 beginning.
2476 */
ClearBuffer()2477 void ClearBuffer()
2478 {
2479 _buffer.Clear();
2480 _buffer.Push(0);
2481 _firstElement = true;
2482 }
2483
2484 protected:
CompactMode(const XMLElement &)2485 virtual bool CompactMode(const XMLElement&) { return _compactMode; }
2486
2487 /** Prints out the space before an element. You may override to change
2488 the space and tabs used. A PrintSpace() override should call Print().
2489 */
2490 virtual void PrintSpace(int depth);
2491 void Print(const char* format, ...);
2492 void Write(const char* data, size_t size);
Write(const char * data)2493 inline void Write(const char* data) { Write(data, strlen(data)); }
2494 void Putc(char ch);
2495
2496 void SealElementIfJustOpened();
2497 bool _elementJustOpened;
2498 DynArray<const char*, 10> _stack;
2499
2500 private:
2501 void PrintString(const char*, bool restrictedEntitySet); // prints out, after detecting entities.
2502
2503 bool _firstElement;
2504 FILE* _fp;
2505 int _depth;
2506 int _textDepth;
2507 bool _processEntities;
2508 bool _compactMode;
2509
2510 enum
2511 {
2512 ENTITY_RANGE = 64,
2513 BUF_SIZE = 200
2514 };
2515 bool _entityFlag[ENTITY_RANGE];
2516 bool _restrictedEntityFlag[ENTITY_RANGE];
2517
2518 DynArray<char, 20> _buffer;
2519
2520 // Prohibit cloning, intentionally not implemented
2521 XMLPrinter(const XMLPrinter&);
2522 XMLPrinter& operator=(const XMLPrinter&);
2523 };
2524
2525 } // namespace tinyxml2
2526
2527 #if defined(_MSC_VER)
2528 #pragma warning(pop)
2529 #endif
2530
2531 #endif // TINYXML2_INCLUDED
2532