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