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