libcrn  3.9.5
A document image processing library
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
tinyxml2.cpp
Go to the documentation of this file.
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 #include "tinyxml2.h"
25 
26 #include <new> // yes, this one new style header, is in the Android SDK.
27 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
28 # include <stddef.h>
29 # include <stdarg.h>
30 #else
31 # include <cstddef>
32 # include <cstdarg>
33 #endif
34 
35 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
36  // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
37  /*int _snprintf_s(
38  char *buffer,
39  size_t sizeOfBuffer,
40  size_t count,
41  const char *format [,
42  argument] ...
43  );*/
44  static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
45  {
46  va_list va;
47  va_start( va, format );
48  int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49  va_end( va );
50  return result;
51  }
52 
53  static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
54  {
55  int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56  return result;
57  }
58 
59  #define TIXML_VSCPRINTF _vscprintf
60  #define TIXML_SSCANF sscanf_s
61 #elif defined _MSC_VER
62  // Microsoft Visual Studio 2003 and earlier or WinCE
63  #define TIXML_SNPRINTF _snprintf
64  #define TIXML_VSNPRINTF _vsnprintf
65  #define TIXML_SSCANF sscanf
66  #if (_MSC_VER < 1400 ) && (!defined WINCE)
67  // Microsoft Visual Studio 2003 and not WinCE.
68  #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69  #else
70  // Microsoft Visual Studio 2003 and earlier or WinCE.
71  static inline int TIXML_VSCPRINTF( const char* format, va_list va )
72  {
73  int len = 512;
74  for (;;) {
75  len = len*2;
76  char* str = new char[len]();
77  const int required = _vsnprintf(str, len, format, va);
78  delete[] str;
79  if ( required != -1 ) {
80  TIXMLASSERT( required >= 0 );
81  len = required;
82  break;
83  }
84  }
85  TIXMLASSERT( len >= 0 );
86  return len;
87  }
88  #endif
89 #else
90  // GCC version 3 and higher
91  //#warning( "Using sn* functions." )
92  #define TIXML_SNPRINTF snprintf
93  #define TIXML_VSNPRINTF vsnprintf
94  static inline int TIXML_VSCPRINTF( const char* format, va_list va )
95  {
96  int len = vsnprintf( 0, 0, format, va );
97  TIXMLASSERT( len >= 0 );
98  return len;
99  }
100  #define TIXML_SSCANF sscanf
101 #endif
102 
103 
104 static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
105 static const char LF = LINE_FEED;
106 static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
107 static const char CR = CARRIAGE_RETURN;
108 static const char SINGLE_QUOTE = '\'';
109 static const char DOUBLE_QUOTE = '\"';
110 
111 // Bunch of unicode info at:
112 // http://www.unicode.org/faq/utf_bom.html
113 // ef bb bf (Microsoft "lead bytes") - designates UTF-8
114 
115 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
116 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
117 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
118 
119 namespace tinyxml2
120 {
121 
122 struct Entity {
123  const char* pattern;
124  int length;
125  char value;
126 };
127 
128 static const int NUM_ENTITIES = 5;
129 static const Entity entities[NUM_ENTITIES] = {
130  { "quot", 4, DOUBLE_QUOTE },
131  { "amp", 3, '&' },
132  { "apos", 4, SINGLE_QUOTE },
133  { "lt", 2, '<' },
134  { "gt", 2, '>' }
135 };
136 
137 
139 {
140  Reset();
141 }
142 
143 
145 {
146  if ( this == other ) {
147  return;
148  }
149  // This in effect implements the assignment operator by "moving"
150  // ownership (as in auto_ptr).
151 
152  TIXMLASSERT( other->_flags == 0 );
153  TIXMLASSERT( other->_start == 0 );
154  TIXMLASSERT( other->_end == 0 );
155 
156  other->Reset();
157 
158  other->_flags = _flags;
159  other->_start = _start;
160  other->_end = _end;
161 
162  _flags = 0;
163  _start = 0;
164  _end = 0;
165 }
166 
167 void StrPair::Reset()
168 {
169  if ( _flags & NEEDS_DELETE ) {
170  delete [] _start;
171  }
172  _flags = 0;
173  _start = 0;
174  _end = 0;
175 }
176 
177 
178 void StrPair::SetStr( const char* str, int flags )
179 {
180  TIXMLASSERT( str );
181  Reset();
182  size_t len = strlen( str );
183  TIXMLASSERT( _start == 0 );
184  _start = new char[ len+1 ];
185  memcpy( _start, str, len+1 );
186  _end = _start + len;
187  _flags = flags | NEEDS_DELETE;
188 }
189 
190 
191 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
192 {
193  TIXMLASSERT( endTag && *endTag );
194 
195  char* start = p;
196  char endChar = *endTag;
197  size_t length = strlen( endTag );
198 
199  // Inner loop of text parsing.
200  while ( *p ) {
201  if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
202  Set( start, p, strFlags );
203  return p + length;
204  }
205  ++p;
206  }
207  return 0;
208 }
209 
210 
211 char* StrPair::ParseName( char* p )
212 {
213  if ( !p || !(*p) ) {
214  return 0;
215  }
216  if ( !XMLUtil::IsNameStartChar( *p ) ) {
217  return 0;
218  }
219 
220  char* const start = p;
221  ++p;
222  while ( *p && XMLUtil::IsNameChar( *p ) ) {
223  ++p;
224  }
225 
226  Set( start, p, 0 );
227  return p;
228 }
229 
230 
231 void StrPair::CollapseWhitespace()
232 {
233  // Adjusting _start would cause undefined behavior on delete[]
234  TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
235  // Trim leading space.
236  _start = XMLUtil::SkipWhiteSpace( _start );
237 
238  if ( *_start ) {
239  char* p = _start; // the read pointer
240  char* q = _start; // the write pointer
241 
242  while( *p ) {
243  if ( XMLUtil::IsWhiteSpace( *p )) {
244  p = XMLUtil::SkipWhiteSpace( p );
245  if ( *p == 0 ) {
246  break; // don't write to q; this trims the trailing space.
247  }
248  *q = ' ';
249  ++q;
250  }
251  *q = *p;
252  ++q;
253  ++p;
254  }
255  *q = 0;
256  }
257 }
258 
259 
260 const char* StrPair::GetStr()
261 {
262  TIXMLASSERT( _start );
263  TIXMLASSERT( _end );
264  if ( _flags & NEEDS_FLUSH ) {
265  *_end = 0;
266  _flags ^= NEEDS_FLUSH;
267 
268  if ( _flags ) {
269  char* p = _start; // the read pointer
270  char* q = _start; // the write pointer
271 
272  while( p < _end ) {
273  if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
274  // CR-LF pair becomes LF
275  // CR alone becomes LF
276  // LF-CR becomes LF
277  if ( *(p+1) == LF ) {
278  p += 2;
279  }
280  else {
281  ++p;
282  }
283  *q++ = LF;
284  }
285  else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
286  if ( *(p+1) == CR ) {
287  p += 2;
288  }
289  else {
290  ++p;
291  }
292  *q++ = LF;
293  }
294  else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
295  // Entities handled by tinyXML2:
296  // - special entities in the entity table [in/out]
297  // - numeric character reference [in]
298  // &#20013; or &#x4e2d;
299 
300  if ( *(p+1) == '#' ) {
301  const int buflen = 10;
302  char buf[buflen] = { 0 };
303  int len = 0;
304  char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
305  if ( adjusted == 0 ) {
306  *q = *p;
307  ++p;
308  ++q;
309  }
310  else {
311  TIXMLASSERT( 0 <= len && len <= buflen );
312  TIXMLASSERT( q + len <= adjusted );
313  p = adjusted;
314  memcpy( q, buf, len );
315  q += len;
316  }
317  }
318  else {
319  bool entityFound = false;
320  for( int i = 0; i < NUM_ENTITIES; ++i ) {
321  const Entity& entity = entities[i];
322  if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
323  && *( p + entity.length + 1 ) == ';' ) {
324  // Found an entity - convert.
325  *q = entity.value;
326  ++q;
327  p += entity.length + 2;
328  entityFound = true;
329  break;
330  }
331  }
332  if ( !entityFound ) {
333  // fixme: treat as error?
334  ++p;
335  ++q;
336  }
337  }
338  }
339  else {
340  *q = *p;
341  ++p;
342  ++q;
343  }
344  }
345  *q = 0;
346  }
347  // The loop below has plenty going on, and this
348  // is a less useful mode. Break it out.
349  if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
350  CollapseWhitespace();
351  }
352  _flags = (_flags & NEEDS_DELETE);
353  }
354  TIXMLASSERT( _start );
355  return _start;
356 }
357 
358 
359 
360 
361 // --------- XMLUtil ----------- //
362 
363 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
364 {
365  TIXMLASSERT( p );
366  TIXMLASSERT( bom );
367  *bom = false;
368  const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
369  // Check for BOM:
370  if ( *(pu+0) == TIXML_UTF_LEAD_0
371  && *(pu+1) == TIXML_UTF_LEAD_1
372  && *(pu+2) == TIXML_UTF_LEAD_2 ) {
373  *bom = true;
374  p += 3;
375  }
376  TIXMLASSERT( p );
377  return p;
378 }
379 
380 
381 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
382 {
383  const unsigned long BYTE_MASK = 0xBF;
384  const unsigned long BYTE_MARK = 0x80;
385  const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
386 
387  if (input < 0x80) {
388  *length = 1;
389  }
390  else if ( input < 0x800 ) {
391  *length = 2;
392  }
393  else if ( input < 0x10000 ) {
394  *length = 3;
395  }
396  else if ( input < 0x200000 ) {
397  *length = 4;
398  }
399  else {
400  *length = 0; // This code won't convert this correctly anyway.
401  return;
402  }
403 
404  output += *length;
405 
406  // Scary scary fall throughs.
407  switch (*length) {
408  case 4:
409  --output;
410  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
411  input >>= 6;
412  case 3:
413  --output;
414  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
415  input >>= 6;
416  case 2:
417  --output;
418  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
419  input >>= 6;
420  case 1:
421  --output;
422  *output = (char)(input | FIRST_BYTE_MARK[*length]);
423  break;
424  default:
425  TIXMLASSERT( false );
426  }
427 }
428 
429 
430 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
431 {
432  // Presume an entity, and pull it out.
433  *length = 0;
434 
435  if ( *(p+1) == '#' && *(p+2) ) {
436  unsigned long ucs = 0;
437  TIXMLASSERT( sizeof( ucs ) >= 4 );
438  ptrdiff_t delta = 0;
439  unsigned mult = 1;
440  static const char SEMICOLON = ';';
441 
442  if ( *(p+2) == 'x' ) {
443  // Hexadecimal.
444  const char* q = p+3;
445  if ( !(*q) ) {
446  return 0;
447  }
448 
449  q = strchr( q, SEMICOLON );
450 
451  if ( !q ) {
452  return 0;
453  }
454  TIXMLASSERT( *q == SEMICOLON );
455 
456  delta = q-p;
457  --q;
458 
459  while ( *q != 'x' ) {
460  unsigned int digit = 0;
461 
462  if ( *q >= '0' && *q <= '9' ) {
463  digit = *q - '0';
464  }
465  else if ( *q >= 'a' && *q <= 'f' ) {
466  digit = *q - 'a' + 10;
467  }
468  else if ( *q >= 'A' && *q <= 'F' ) {
469  digit = *q - 'A' + 10;
470  }
471  else {
472  return 0;
473  }
474  TIXMLASSERT( digit < 16 );
475  TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
476  const unsigned int digitScaled = mult * digit;
477  TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
478  ucs += digitScaled;
479  TIXMLASSERT( mult <= UINT_MAX / 16 );
480  mult *= 16;
481  --q;
482  }
483  }
484  else {
485  // Decimal.
486  const char* q = p+2;
487  if ( !(*q) ) {
488  return 0;
489  }
490 
491  q = strchr( q, SEMICOLON );
492 
493  if ( !q ) {
494  return 0;
495  }
496  TIXMLASSERT( *q == SEMICOLON );
497 
498  delta = q-p;
499  --q;
500 
501  while ( *q != '#' ) {
502  if ( *q >= '0' && *q <= '9' ) {
503  const unsigned int digit = *q - '0';
504  TIXMLASSERT( digit < 10 );
505  TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
506  const unsigned int digitScaled = mult * digit;
507  TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
508  ucs += digitScaled;
509  }
510  else {
511  return 0;
512  }
513  TIXMLASSERT( mult <= UINT_MAX / 10 );
514  mult *= 10;
515  --q;
516  }
517  }
518  // convert the UCS to UTF-8
519  ConvertUTF32ToUTF8( ucs, value, length );
520  return p + delta + 1;
521  }
522  return p+1;
523 }
524 
525 
526 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
527 {
528  TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
529 }
530 
531 
532 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
533 {
534  TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
535 }
536 
537 
538 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
539 {
540  TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
541 }
542 
543 /*
544  ToStr() of a number is a very tricky topic.
545  https://github.com/leethomason/tinyxml2/issues/106
546 */
547 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
548 {
549  TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
550 }
551 
552 
553 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
554 {
555  TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
556 }
557 
558 
559 bool XMLUtil::ToInt( const char* str, int* value )
560 {
561  if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
562  return true;
563  }
564  return false;
565 }
566 
567 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
568 {
569  if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
570  return true;
571  }
572  return false;
573 }
574 
575 bool XMLUtil::ToBool( const char* str, bool* value )
576 {
577  int ival = 0;
578  if ( ToInt( str, &ival )) {
579  *value = (ival==0) ? false : true;
580  return true;
581  }
582  if ( StringEqual( str, "true" ) ) {
583  *value = true;
584  return true;
585  }
586  else if ( StringEqual( str, "false" ) ) {
587  *value = false;
588  return true;
589  }
590  return false;
591 }
592 
593 
594 bool XMLUtil::ToFloat( const char* str, float* value )
595 {
596  if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
597  return true;
598  }
599  return false;
600 }
601 
602 bool XMLUtil::ToDouble( const char* str, double* value )
603 {
604  if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
605  return true;
606  }
607  return false;
608 }
609 
610 
611 char* XMLDocument::Identify( char* p, XMLNode** node )
612 {
613  TIXMLASSERT( node );
614  TIXMLASSERT( p );
615  char* const start = p;
616  p = XMLUtil::SkipWhiteSpace( p );
617  if( !*p ) {
618  *node = 0;
619  TIXMLASSERT( p );
620  return p;
621  }
622 
623  // These strings define the matching patterns:
624  static const char* xmlHeader = { "<?" };
625  static const char* commentHeader = { "<!--" };
626  static const char* cdataHeader = { "<![CDATA[" };
627  static const char* dtdHeader = { "<!" };
628  static const char* elementHeader = { "<" }; // and a header for everything else; check last.
629 
630  static const int xmlHeaderLen = 2;
631  static const int commentHeaderLen = 4;
632  static const int cdataHeaderLen = 9;
633  static const int dtdHeaderLen = 2;
634  static const int elementHeaderLen = 1;
635 
636  TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
637  TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
638  XMLNode* returnNode = 0;
639  if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
640  TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
641  returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
642  returnNode->_memPool = &_commentPool;
643  p += xmlHeaderLen;
644  }
645  else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
646  TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
647  returnNode = new (_commentPool.Alloc()) XMLComment( this );
648  returnNode->_memPool = &_commentPool;
649  p += commentHeaderLen;
650  }
651  else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
652  TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
653  XMLText* text = new (_textPool.Alloc()) XMLText( this );
654  returnNode = text;
655  returnNode->_memPool = &_textPool;
656  p += cdataHeaderLen;
657  text->SetCData( true );
658  }
659  else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
660  TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
661  returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
662  returnNode->_memPool = &_commentPool;
663  p += dtdHeaderLen;
664  }
665  else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
666  TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
667  returnNode = new (_elementPool.Alloc()) XMLElement( this );
668  returnNode->_memPool = &_elementPool;
669  p += elementHeaderLen;
670  }
671  else {
672  TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
673  returnNode = new (_textPool.Alloc()) XMLText( this );
674  returnNode->_memPool = &_textPool;
675  p = start; // Back it up, all the text counts.
676  }
677 
678  TIXMLASSERT( returnNode );
679  TIXMLASSERT( p );
680  *node = returnNode;
681  return p;
682 }
683 
684 
685 bool XMLDocument::Accept( XMLVisitor* visitor ) const
686 {
687  TIXMLASSERT( visitor );
688  if ( visitor->VisitEnter( *this ) ) {
689  for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
690  if ( !node->Accept( visitor ) ) {
691  break;
692  }
693  }
694  }
695  return visitor->VisitExit( *this );
696 }
697 
698 
699 // --------- XMLNode ----------- //
700 
702  _document( doc ),
703  _parent( 0 ),
704  _firstChild( 0 ), _lastChild( 0 ),
705  _prev( 0 ), _next( 0 ),
706  _memPool( 0 )
707 {
708 }
709 
710 
712 {
713  DeleteChildren();
714  if ( _parent ) {
715  _parent->Unlink( this );
716  }
717 }
718 
719 const char* XMLNode::Value() const
720 {
721  // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
722  if ( this->ToDocument() )
723  return 0;
724  return _value.GetStr();
725 }
726 
727 void XMLNode::SetValue( const char* str, bool staticMem )
728 {
729  if ( staticMem ) {
730  _value.SetInternedStr( str );
731  }
732  else {
733  _value.SetStr( str );
734  }
735 }
736 
737 
739 {
740  while( _firstChild ) {
743  XMLNode* node = _firstChild;
744  Unlink( node );
745 
746  DeleteNode( node );
747  }
748  _firstChild = _lastChild = 0;
749 }
750 
751 
752 void XMLNode::Unlink( XMLNode* child )
753 {
754  TIXMLASSERT( child );
755  TIXMLASSERT( child->_document == _document );
756  TIXMLASSERT( child->_parent == this );
757  if ( child == _firstChild ) {
759  }
760  if ( child == _lastChild ) {
762  }
763 
764  if ( child->_prev ) {
765  child->_prev->_next = child->_next;
766  }
767  if ( child->_next ) {
768  child->_next->_prev = child->_prev;
769  }
770  child->_parent = 0;
771 }
772 
773 
775 {
776  TIXMLASSERT( node );
777  TIXMLASSERT( node->_document == _document );
778  TIXMLASSERT( node->_parent == this );
779  Unlink( node );
780  DeleteNode( node );
781 }
782 
783 
785 {
786  TIXMLASSERT( addThis );
787  if ( addThis->_document != _document ) {
788  TIXMLASSERT( false );
789  return 0;
790  }
791  InsertChildPreamble( addThis );
792 
793  if ( _lastChild ) {
795  TIXMLASSERT( _lastChild->_next == 0 );
796  _lastChild->_next = addThis;
797  addThis->_prev = _lastChild;
798  _lastChild = addThis;
799 
800  addThis->_next = 0;
801  }
802  else {
803  TIXMLASSERT( _firstChild == 0 );
804  _firstChild = _lastChild = addThis;
805 
806  addThis->_prev = 0;
807  addThis->_next = 0;
808  }
809  addThis->_parent = this;
810  return addThis;
811 }
812 
813 
815 {
816  TIXMLASSERT( addThis );
817  if ( addThis->_document != _document ) {
818  TIXMLASSERT( false );
819  return 0;
820  }
821  InsertChildPreamble( addThis );
822 
823  if ( _firstChild ) {
825  TIXMLASSERT( _firstChild->_prev == 0 );
826 
827  _firstChild->_prev = addThis;
828  addThis->_next = _firstChild;
829  _firstChild = addThis;
830 
831  addThis->_prev = 0;
832  }
833  else {
834  TIXMLASSERT( _lastChild == 0 );
835  _firstChild = _lastChild = addThis;
836 
837  addThis->_prev = 0;
838  addThis->_next = 0;
839  }
840  addThis->_parent = this;
841  return addThis;
842 }
843 
844 
846 {
847  TIXMLASSERT( addThis );
848  if ( addThis->_document != _document ) {
849  TIXMLASSERT( false );
850  return 0;
851  }
852 
853  TIXMLASSERT( afterThis );
854 
855  if ( afterThis->_parent != this ) {
856  TIXMLASSERT( false );
857  return 0;
858  }
859 
860  if ( afterThis->_next == 0 ) {
861  // The last node or the only node.
862  return InsertEndChild( addThis );
863  }
864  InsertChildPreamble( addThis );
865  addThis->_prev = afterThis;
866  addThis->_next = afterThis->_next;
867  afterThis->_next->_prev = addThis;
868  afterThis->_next = addThis;
869  addThis->_parent = this;
870  return addThis;
871 }
872 
873 
874 
875 
876 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
877 {
878  for( const XMLNode* node = _firstChild; node; node = node->_next ) {
879  const XMLElement* element = node->ToElement();
880  if ( element ) {
881  if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
882  return element;
883  }
884  }
885  }
886  return 0;
887 }
888 
889 
890 const XMLElement* XMLNode::LastChildElement( const char* name ) const
891 {
892  for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
893  const XMLElement* element = node->ToElement();
894  if ( element ) {
895  if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
896  return element;
897  }
898  }
899  }
900  return 0;
901 }
902 
903 
904 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
905 {
906  for( const XMLNode* node = _next; node; node = node->_next ) {
907  const XMLElement* element = node->ToElement();
908  if ( element
909  && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
910  return element;
911  }
912  }
913  return 0;
914 }
915 
916 
917 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
918 {
919  for( const XMLNode* node = _prev; node; node = node->_prev ) {
920  const XMLElement* element = node->ToElement();
921  if ( element
922  && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
923  return element;
924  }
925  }
926  return 0;
927 }
928 
929 
930 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
931 {
932  // This is a recursive method, but thinking about it "at the current level"
933  // it is a pretty simple flat list:
934  // <foo/>
935  // <!-- comment -->
936  //
937  // With a special case:
938  // <foo>
939  // </foo>
940  // <!-- comment -->
941  //
942  // Where the closing element (/foo) *must* be the next thing after the opening
943  // element, and the names must match. BUT the tricky bit is that the closing
944  // element will be read by the child.
945  //
946  // 'endTag' is the end tag for this node, it is returned by a call to a child.
947  // 'parentEnd' is the end tag for the parent, which is filled in and returned.
948 
949  while( p && *p ) {
950  XMLNode* node = 0;
951 
952  p = _document->Identify( p, &node );
953  if ( node == 0 ) {
954  break;
955  }
956 
957  StrPair endTag;
958  p = node->ParseDeep( p, &endTag );
959  if ( !p ) {
960  DeleteNode( node );
961  if ( !_document->Error() ) {
963  }
964  break;
965  }
966 
967  XMLDeclaration* decl = node->ToDeclaration();
968  if ( decl ) {
969  // A declaration can only be the first child of a document.
970  // Set error, if document already has children.
971  if ( !_document->NoChildren() ) {
973  DeleteNode( decl );
974  break;
975  }
976  }
977 
978  XMLElement* ele = node->ToElement();
979  if ( ele ) {
980  // We read the end tag. Return it to the parent.
981  if ( ele->ClosingType() == XMLElement::CLOSING ) {
982  if ( parentEnd ) {
983  ele->_value.TransferTo( parentEnd );
984  }
985  node->_memPool->SetTracked(); // created and then immediately deleted.
986  DeleteNode( node );
987  return p;
988  }
989 
990  // Handle an end tag returned to this level.
991  // And handle a bunch of annoying errors.
992  bool mismatch = false;
993  if ( endTag.Empty() ) {
994  if ( ele->ClosingType() == XMLElement::OPEN ) {
995  mismatch = true;
996  }
997  }
998  else {
999  if ( ele->ClosingType() != XMLElement::OPEN ) {
1000  mismatch = true;
1001  }
1002  else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1003  mismatch = true;
1004  }
1005  }
1006  if ( mismatch ) {
1008  DeleteNode( node );
1009  break;
1010  }
1011  }
1012  InsertEndChild( node );
1013  }
1014  return 0;
1015 }
1016 
1017 void XMLNode::DeleteNode( XMLNode* node )
1018 {
1019  if ( node == 0 ) {
1020  return;
1021  }
1022  MemPool* pool = node->_memPool;
1023  node->~XMLNode();
1024  pool->Free( node );
1025 }
1026 
1027 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1028 {
1029  TIXMLASSERT( insertThis );
1030  TIXMLASSERT( insertThis->_document == _document );
1031 
1032  if ( insertThis->_parent )
1033  insertThis->_parent->Unlink( insertThis );
1034  else
1035  insertThis->_memPool->SetTracked();
1036 }
1037 
1038 // --------- XMLText ---------- //
1039 char* XMLText::ParseDeep( char* p, StrPair* )
1040 {
1041  const char* start = p;
1042  if ( this->CData() ) {
1044  if ( !p ) {
1046  }
1047  return p;
1048  }
1049  else {
1053  }
1054 
1055  p = _value.ParseText( p, "<", flags );
1056  if ( p && *p ) {
1057  return p-1;
1058  }
1059  if ( !p ) {
1061  }
1062  }
1063  return 0;
1064 }
1065 
1066 
1068 {
1069  if ( !doc ) {
1070  doc = _document;
1071  }
1072  XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
1073  text->SetCData( this->CData() );
1074  return text;
1075 }
1076 
1077 
1078 bool XMLText::ShallowEqual( const XMLNode* compare ) const
1079 {
1080  const XMLText* text = compare->ToText();
1081  return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1082 }
1083 
1084 
1085 bool XMLText::Accept( XMLVisitor* visitor ) const
1086 {
1087  TIXMLASSERT( visitor );
1088  return visitor->Visit( *this );
1089 }
1090 
1091 
1092 // --------- XMLComment ---------- //
1093 
1095 {
1096 }
1097 
1098 
1100 {
1101 }
1102 
1103 
1104 char* XMLComment::ParseDeep( char* p, StrPair* )
1105 {
1106  // Comment parses as text.
1107  const char* start = p;
1108  p = _value.ParseText( p, "-->", StrPair::COMMENT );
1109  if ( p == 0 ) {
1111  }
1112  return p;
1113 }
1114 
1115 
1117 {
1118  if ( !doc ) {
1119  doc = _document;
1120  }
1121  XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
1122  return comment;
1123 }
1124 
1125 
1126 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1127 {
1128  TIXMLASSERT( compare );
1129  const XMLComment* comment = compare->ToComment();
1130  return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1131 }
1132 
1133 
1134 bool XMLComment::Accept( XMLVisitor* visitor ) const
1135 {
1136  TIXMLASSERT( visitor );
1137  return visitor->Visit( *this );
1138 }
1139 
1140 
1141 // --------- XMLDeclaration ---------- //
1142 
1144 {
1145 }
1146 
1147 
1149 {
1150  //printf( "~XMLDeclaration\n" );
1151 }
1152 
1153 
1155 {
1156  // Declaration parses as text.
1157  const char* start = p;
1159  if ( p == 0 ) {
1161  }
1162  return p;
1163 }
1164 
1165 
1167 {
1168  if ( !doc ) {
1169  doc = _document;
1170  }
1171  XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1172  return dec;
1173 }
1174 
1175 
1176 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1177 {
1178  TIXMLASSERT( compare );
1179  const XMLDeclaration* declaration = compare->ToDeclaration();
1180  return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1181 }
1182 
1183 
1184 
1185 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1186 {
1187  TIXMLASSERT( visitor );
1188  return visitor->Visit( *this );
1189 }
1190 
1191 // --------- XMLUnknown ---------- //
1192 
1194 {
1195 }
1196 
1197 
1199 {
1200 }
1201 
1202 
1203 char* XMLUnknown::ParseDeep( char* p, StrPair* )
1204 {
1205  // Unknown parses as text.
1206  const char* start = p;
1207 
1209  if ( !p ) {
1211  }
1212  return p;
1213 }
1214 
1215 
1217 {
1218  if ( !doc ) {
1219  doc = _document;
1220  }
1221  XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1222  return text;
1223 }
1224 
1225 
1226 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1227 {
1228  TIXMLASSERT( compare );
1229  const XMLUnknown* unknown = compare->ToUnknown();
1230  return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1231 }
1232 
1233 
1234 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1235 {
1236  TIXMLASSERT( visitor );
1237  return visitor->Visit( *this );
1238 }
1239 
1240 // --------- XMLAttribute ---------- //
1241 
1242 const char* XMLAttribute::Name() const
1243 {
1244  return _name.GetStr();
1245 }
1246 
1247 const char* XMLAttribute::Value() const
1248 {
1249  return _value.GetStr();
1250 }
1251 
1252 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
1253 {
1254  // Parse using the name rules: bug fix, was using ParseText before
1255  p = _name.ParseName( p );
1256  if ( !p || !*p ) {
1257  return 0;
1258  }
1259 
1260  // Skip white space before =
1261  p = XMLUtil::SkipWhiteSpace( p );
1262  if ( *p != '=' ) {
1263  return 0;
1264  }
1265 
1266  ++p; // move up to opening quote
1267  p = XMLUtil::SkipWhiteSpace( p );
1268  if ( *p != '\"' && *p != '\'' ) {
1269  return 0;
1270  }
1271 
1272  char endTag[2] = { *p, 0 };
1273  ++p; // move past opening quote
1274 
1275  p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
1276  return p;
1277 }
1278 
1279 
1280 void XMLAttribute::SetName( const char* n )
1281 {
1282  _name.SetStr( n );
1283 }
1284 
1285 
1287 {
1288  if ( XMLUtil::ToInt( Value(), value )) {
1289  return XML_NO_ERROR;
1290  }
1291  return XML_WRONG_ATTRIBUTE_TYPE;
1292 }
1293 
1294 
1295 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1296 {
1297  if ( XMLUtil::ToUnsigned( Value(), value )) {
1298  return XML_NO_ERROR;
1299  }
1300  return XML_WRONG_ATTRIBUTE_TYPE;
1301 }
1302 
1303 
1305 {
1306  if ( XMLUtil::ToBool( Value(), value )) {
1307  return XML_NO_ERROR;
1308  }
1309  return XML_WRONG_ATTRIBUTE_TYPE;
1310 }
1311 
1312 
1314 {
1315  if ( XMLUtil::ToFloat( Value(), value )) {
1316  return XML_NO_ERROR;
1317  }
1318  return XML_WRONG_ATTRIBUTE_TYPE;
1319 }
1320 
1321 
1323 {
1324  if ( XMLUtil::ToDouble( Value(), value )) {
1325  return XML_NO_ERROR;
1326  }
1327  return XML_WRONG_ATTRIBUTE_TYPE;
1328 }
1329 
1330 
1331 void XMLAttribute::SetAttribute( const char* v )
1332 {
1333  _value.SetStr( v );
1334 }
1335 
1336 
1338 {
1339  char buf[BUF_SIZE];
1340  XMLUtil::ToStr( v, buf, BUF_SIZE );
1341  _value.SetStr( buf );
1342 }
1343 
1344 
1345 void XMLAttribute::SetAttribute( unsigned v )
1346 {
1347  char buf[BUF_SIZE];
1348  XMLUtil::ToStr( v, buf, BUF_SIZE );
1349  _value.SetStr( buf );
1350 }
1351 
1352 
1354 {
1355  char buf[BUF_SIZE];
1356  XMLUtil::ToStr( v, buf, BUF_SIZE );
1357  _value.SetStr( buf );
1358 }
1359 
1361 {
1362  char buf[BUF_SIZE];
1363  XMLUtil::ToStr( v, buf, BUF_SIZE );
1364  _value.SetStr( buf );
1365 }
1366 
1368 {
1369  char buf[BUF_SIZE];
1370  XMLUtil::ToStr( v, buf, BUF_SIZE );
1371  _value.SetStr( buf );
1372 }
1373 
1374 
1375 // --------- XMLElement ---------- //
1376 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1377  _closingType( 0 ),
1378  _rootAttribute( 0 )
1379 {
1380 }
1381 
1382 
1383 XMLElement::~XMLElement()
1384 {
1385  while( _rootAttribute ) {
1386  XMLAttribute* next = _rootAttribute->_next;
1387  DeleteAttribute( _rootAttribute );
1388  _rootAttribute = next;
1389  }
1390 }
1391 
1392 
1393 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1394 {
1395  for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1396  if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1397  return a;
1398  }
1399  }
1400  return 0;
1401 }
1402 
1403 
1404 const char* XMLElement::Attribute( const char* name, const char* value ) const
1405 {
1406  const XMLAttribute* a = FindAttribute( name );
1407  if ( !a ) {
1408  return 0;
1409  }
1410  if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1411  return a->Value();
1412  }
1413  return 0;
1414 }
1415 
1416 
1417 const char* XMLElement::GetText() const
1418 {
1419  if ( FirstChild() && FirstChild()->ToText() ) {
1420  return FirstChild()->Value();
1421  }
1422  return 0;
1423 }
1424 
1425 
1426 void XMLElement::SetText( const char* inText )
1427 {
1428  if ( FirstChild() && FirstChild()->ToText() )
1429  FirstChild()->SetValue( inText );
1430  else {
1431  XMLText* theText = GetDocument()->NewText( inText );
1432  InsertFirstChild( theText );
1433  }
1434 }
1435 
1436 
1437 void XMLElement::SetText( int v )
1438 {
1439  char buf[BUF_SIZE];
1440  XMLUtil::ToStr( v, buf, BUF_SIZE );
1441  SetText( buf );
1442 }
1443 
1444 
1445 void XMLElement::SetText( unsigned v )
1446 {
1447  char buf[BUF_SIZE];
1448  XMLUtil::ToStr( v, buf, BUF_SIZE );
1449  SetText( buf );
1450 }
1451 
1452 
1453 void XMLElement::SetText( bool v )
1454 {
1455  char buf[BUF_SIZE];
1456  XMLUtil::ToStr( v, buf, BUF_SIZE );
1457  SetText( buf );
1458 }
1459 
1460 
1461 void XMLElement::SetText( float v )
1462 {
1463  char buf[BUF_SIZE];
1464  XMLUtil::ToStr( v, buf, BUF_SIZE );
1465  SetText( buf );
1466 }
1467 
1468 
1469 void XMLElement::SetText( double v )
1470 {
1471  char buf[BUF_SIZE];
1472  XMLUtil::ToStr( v, buf, BUF_SIZE );
1473  SetText( buf );
1474 }
1475 
1476 
1478 {
1479  if ( FirstChild() && FirstChild()->ToText() ) {
1480  const char* t = FirstChild()->Value();
1481  if ( XMLUtil::ToInt( t, ival ) ) {
1482  return XML_SUCCESS;
1483  }
1484  return XML_CAN_NOT_CONVERT_TEXT;
1485  }
1486  return XML_NO_TEXT_NODE;
1487 }
1488 
1489 
1491 {
1492  if ( FirstChild() && FirstChild()->ToText() ) {
1493  const char* t = FirstChild()->Value();
1494  if ( XMLUtil::ToUnsigned( t, uval ) ) {
1495  return XML_SUCCESS;
1496  }
1497  return XML_CAN_NOT_CONVERT_TEXT;
1498  }
1499  return XML_NO_TEXT_NODE;
1500 }
1501 
1502 
1504 {
1505  if ( FirstChild() && FirstChild()->ToText() ) {
1506  const char* t = FirstChild()->Value();
1507  if ( XMLUtil::ToBool( t, bval ) ) {
1508  return XML_SUCCESS;
1509  }
1510  return XML_CAN_NOT_CONVERT_TEXT;
1511  }
1512  return XML_NO_TEXT_NODE;
1513 }
1514 
1515 
1517 {
1518  if ( FirstChild() && FirstChild()->ToText() ) {
1519  const char* t = FirstChild()->Value();
1520  if ( XMLUtil::ToDouble( t, dval ) ) {
1521  return XML_SUCCESS;
1522  }
1523  return XML_CAN_NOT_CONVERT_TEXT;
1524  }
1525  return XML_NO_TEXT_NODE;
1526 }
1527 
1528 
1530 {
1531  if ( FirstChild() && FirstChild()->ToText() ) {
1532  const char* t = FirstChild()->Value();
1533  if ( XMLUtil::ToFloat( t, fval ) ) {
1534  return XML_SUCCESS;
1535  }
1536  return XML_CAN_NOT_CONVERT_TEXT;
1537  }
1538  return XML_NO_TEXT_NODE;
1539 }
1540 
1541 
1542 
1543 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1544 {
1545  XMLAttribute* last = 0;
1546  XMLAttribute* attrib = 0;
1547  for( attrib = _rootAttribute;
1548  attrib;
1549  last = attrib, attrib = attrib->_next ) {
1550  if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1551  break;
1552  }
1553  }
1554  if ( !attrib ) {
1555  TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1556  attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1557  attrib->_memPool = &_document->_attributePool;
1558  if ( last ) {
1559  last->_next = attrib;
1560  }
1561  else {
1562  _rootAttribute = attrib;
1563  }
1564  attrib->SetName( name );
1565  attrib->_memPool->SetTracked(); // always created and linked.
1566  }
1567  return attrib;
1568 }
1569 
1570 
1571 void XMLElement::DeleteAttribute( const char* name )
1572 {
1573  XMLAttribute* prev = 0;
1574  for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1575  if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1576  if ( prev ) {
1577  prev->_next = a->_next;
1578  }
1579  else {
1580  _rootAttribute = a->_next;
1581  }
1582  DeleteAttribute( a );
1583  break;
1584  }
1585  prev = a;
1586  }
1587 }
1588 
1589 
1590 char* XMLElement::ParseAttributes( char* p )
1591 {
1592  const char* start = p;
1593  XMLAttribute* prevAttribute = 0;
1594 
1595  // Read the attributes.
1596  while( p ) {
1597  p = XMLUtil::SkipWhiteSpace( p );
1598  if ( !(*p) ) {
1600  return 0;
1601  }
1602 
1603  // attribute.
1604  if (XMLUtil::IsNameStartChar( *p ) ) {
1605  TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
1606  XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
1607  attrib->_memPool = &_document->_attributePool;
1608  attrib->_memPool->SetTracked();
1609 
1610  p = attrib->ParseDeep( p, _document->ProcessEntities() );
1611  if ( !p || Attribute( attrib->Name() ) ) {
1612  DeleteAttribute( attrib );
1614  return 0;
1615  }
1616  // There is a minor bug here: if the attribute in the source xml
1617  // document is duplicated, it will not be detected and the
1618  // attribute will be doubly added. However, tracking the 'prevAttribute'
1619  // avoids re-scanning the attribute list. Preferring performance for
1620  // now, may reconsider in the future.
1621  if ( prevAttribute ) {
1622  prevAttribute->_next = attrib;
1623  }
1624  else {
1625  _rootAttribute = attrib;
1626  }
1627  prevAttribute = attrib;
1628  }
1629  // end of the tag
1630  else if ( *p == '>' ) {
1631  ++p;
1632  break;
1633  }
1634  // end of the tag
1635  else if ( *p == '/' && *(p+1) == '>' ) {
1636  _closingType = CLOSED;
1637  return p+2; // done; sealed element.
1638  }
1639  else {
1641  return 0;
1642  }
1643  }
1644  return p;
1645 }
1646 
1647 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1648 {
1649  if ( attribute == 0 ) {
1650  return;
1651  }
1652  MemPool* pool = attribute->_memPool;
1653  attribute->~XMLAttribute();
1654  pool->Free( attribute );
1655 }
1656 
1657 //
1658 // <ele></ele>
1659 // <ele>foo<b>bar</b></ele>
1660 //
1661 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
1662 {
1663  // Read the element name.
1664  p = XMLUtil::SkipWhiteSpace( p );
1665 
1666  // The closing element is the </element> form. It is
1667  // parsed just like a regular element then deleted from
1668  // the DOM.
1669  if ( *p == '/' ) {
1670  _closingType = CLOSING;
1671  ++p;
1672  }
1673 
1674  p = _value.ParseName( p );
1675  if ( _value.Empty() ) {
1676  return 0;
1677  }
1678 
1679  p = ParseAttributes( p );
1680  if ( !p || !*p || _closingType ) {
1681  return p;
1682  }
1683 
1684  p = XMLNode::ParseDeep( p, strPair );
1685  return p;
1686 }
1687 
1688 
1689 
1691 {
1692  if ( !doc ) {
1693  doc = _document;
1694  }
1695  XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1696  for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1697  element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1698  }
1699  return element;
1700 }
1701 
1702 
1703 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1704 {
1705  TIXMLASSERT( compare );
1706  const XMLElement* other = compare->ToElement();
1707  if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
1708 
1709  const XMLAttribute* a=FirstAttribute();
1710  const XMLAttribute* b=other->FirstAttribute();
1711 
1712  while ( a && b ) {
1713  if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1714  return false;
1715  }
1716  a = a->Next();
1717  b = b->Next();
1718  }
1719  if ( a || b ) {
1720  // different count
1721  return false;
1722  }
1723  return true;
1724  }
1725  return false;
1726 }
1727 
1728 
1729 bool XMLElement::Accept( XMLVisitor* visitor ) const
1730 {
1731  TIXMLASSERT( visitor );
1732  if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
1733  for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
1734  if ( !node->Accept( visitor ) ) {
1735  break;
1736  }
1737  }
1738  }
1739  return visitor->VisitExit( *this );
1740 }
1741 
1742 
1743 // --------- XMLDocument ----------- //
1744 
1745 // Warning: List must match 'enum XMLError'
1746 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
1747  "XML_SUCCESS",
1748  "XML_NO_ATTRIBUTE",
1749  "XML_WRONG_ATTRIBUTE_TYPE",
1750  "XML_ERROR_FILE_NOT_FOUND",
1751  "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
1752  "XML_ERROR_FILE_READ_ERROR",
1753  "XML_ERROR_ELEMENT_MISMATCH",
1754  "XML_ERROR_PARSING_ELEMENT",
1755  "XML_ERROR_PARSING_ATTRIBUTE",
1756  "XML_ERROR_IDENTIFYING_TAG",
1757  "XML_ERROR_PARSING_TEXT",
1758  "XML_ERROR_PARSING_CDATA",
1759  "XML_ERROR_PARSING_COMMENT",
1760  "XML_ERROR_PARSING_DECLARATION",
1761  "XML_ERROR_PARSING_UNKNOWN",
1762  "XML_ERROR_EMPTY_DOCUMENT",
1763  "XML_ERROR_MISMATCHED_ELEMENT",
1764  "XML_ERROR_PARSING",
1765  "XML_CAN_NOT_CONVERT_TEXT",
1766  "XML_NO_TEXT_NODE"
1767 };
1768 
1769 
1770 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
1771  XMLNode( 0 ),
1772  _writeBOM( false ),
1773  _processEntities( processEntities ),
1774  _errorID( XML_NO_ERROR ),
1775  _whitespace( whitespace ),
1776  _errorStr1( 0 ),
1777  _errorStr2( 0 ),
1778  _charBuffer( 0 )
1779 {
1780  // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
1781  _document = this;
1782 }
1783 
1784 
1786 {
1787  Clear();
1788 }
1789 
1790 
1792 {
1793  DeleteChildren();
1794 
1795 #ifdef DEBUG
1796  const bool hadError = Error();
1797 #endif
1798  _errorID = XML_NO_ERROR;
1799  _errorStr1 = 0;
1800  _errorStr2 = 0;
1801 
1802  delete [] _charBuffer;
1803  _charBuffer = 0;
1804 
1805 #if 0
1806  _textPool.Trace( "text" );
1807  _elementPool.Trace( "element" );
1808  _commentPool.Trace( "comment" );
1809  _attributePool.Trace( "attribute" );
1810 #endif
1811 
1812 #ifdef DEBUG
1813  if ( !hadError ) {
1814  TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
1815  TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
1816  TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
1817  TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
1818  }
1819 #endif
1820 }
1821 
1822 
1824 {
1825  TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
1826  XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
1827  ele->_memPool = &_elementPool;
1828  ele->SetName( name );
1829  return ele;
1830 }
1831 
1832 
1834 {
1835  TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
1836  XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
1837  comment->_memPool = &_commentPool;
1838  comment->SetValue( str );
1839  return comment;
1840 }
1841 
1842 
1843 XMLText* XMLDocument::NewText( const char* str )
1844 {
1845  TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
1846  XMLText* text = new (_textPool.Alloc()) XMLText( this );
1847  text->_memPool = &_textPool;
1848  text->SetValue( str );
1849  return text;
1850 }
1851 
1852 
1854 {
1855  TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
1856  XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
1857  dec->_memPool = &_commentPool;
1858  dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1859  return dec;
1860 }
1861 
1862 
1864 {
1865  TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
1866  XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
1867  unk->_memPool = &_commentPool;
1868  unk->SetValue( str );
1869  return unk;
1870 }
1871 
1872 static FILE* callfopen( const char* filepath, const char* mode )
1873 {
1874  TIXMLASSERT( filepath );
1875  TIXMLASSERT( mode );
1876 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
1877  FILE* fp = 0;
1878  errno_t err = fopen_s( &fp, filepath, mode );
1879  if ( err ) {
1880  return 0;
1881  }
1882 #else
1883  FILE* fp = fopen( filepath, mode );
1884 #endif
1885  return fp;
1886 }
1887 
1889  TIXMLASSERT( node );
1890  TIXMLASSERT(node->_document == this );
1891  if (node->_parent) {
1892  node->_parent->DeleteChild( node );
1893  }
1894  else {
1895  // Isn't in the tree.
1896  // Use the parent delete.
1897  // Also, we need to mark it tracked: we 'know'
1898  // it was never used.
1899  node->_memPool->SetTracked();
1900  // Call the static XMLNode version:
1901  XMLNode::DeleteNode(node);
1902  }
1903 }
1904 
1905 
1906 XMLError XMLDocument::LoadFile( const char* filename )
1907 {
1908  Clear();
1909  FILE* fp = callfopen( filename, "rb" );
1910  if ( !fp ) {
1911  SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
1912  return _errorID;
1913  }
1914  LoadFile( fp );
1915  fclose( fp );
1916  return _errorID;
1917 }
1918 
1919 // This is likely overengineered template art to have a check that unsigned long value incremented
1920 // by one still fits into size_t. If size_t type is larger than unsigned long type
1921 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
1922 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check
1923 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long
1924 // types sizes relate to each other.
1925 template
1926 <bool = (sizeof(unsigned long) >= sizeof(size_t))>
1928  static bool Fits( unsigned long value )
1929  {
1930  return value < (size_t)-1;
1931  }
1932 };
1933 
1934 template <>
1935 bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
1936 {
1937  return true;
1938 }
1939 
1941 {
1942  Clear();
1943 
1944  fseek( fp, 0, SEEK_SET );
1945  if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
1947  return _errorID;
1948  }
1949 
1950  fseek( fp, 0, SEEK_END );
1951  const long filelength = ftell( fp );
1952  fseek( fp, 0, SEEK_SET );
1953  if ( filelength == -1L ) {
1955  return _errorID;
1956  }
1957  TIXMLASSERT( filelength >= 0 );
1958 
1959  if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
1960  // Cannot handle files which won't fit in buffer together with null terminator
1962  return _errorID;
1963  }
1964 
1965  if ( filelength == 0 ) {
1967  return _errorID;
1968  }
1969 
1970  const size_t size = filelength;
1971  TIXMLASSERT( _charBuffer == 0 );
1972  _charBuffer = new char[size+1];
1973  size_t read = fread( _charBuffer, 1, size, fp );
1974  if ( read != size ) {
1976  return _errorID;
1977  }
1978 
1979  _charBuffer[size] = 0;
1980 
1981  Parse();
1982  return _errorID;
1983 }
1984 
1985 
1986 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
1987 {
1988  FILE* fp = callfopen( filename, "w" );
1989  if ( !fp ) {
1991  return _errorID;
1992  }
1993  SaveFile(fp, compact);
1994  fclose( fp );
1995  return _errorID;
1996 }
1997 
1998 
1999 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2000 {
2001  // Clear any error from the last save, otherwise it will get reported
2002  // for *this* call.
2003  SetError( XML_NO_ERROR, 0, 0 );
2004  XMLPrinter stream( fp, compact );
2005  Print( &stream );
2006  return _errorID;
2007 }
2008 
2009 
2010 XMLError XMLDocument::Parse( const char* p, size_t len )
2011 {
2012  Clear();
2013 
2014  if ( len == 0 || !p || !*p ) {
2016  return _errorID;
2017  }
2018  if ( len == (size_t)(-1) ) {
2019  len = strlen( p );
2020  }
2021  TIXMLASSERT( _charBuffer == 0 );
2022  _charBuffer = new char[ len+1 ];
2023  memcpy( _charBuffer, p, len );
2024  _charBuffer[len] = 0;
2025 
2026  Parse();
2027  if ( Error() ) {
2028  // clean up now essentially dangling memory.
2029  // and the parse fail can put objects in the
2030  // pools that are dead and inaccessible.
2031  DeleteChildren();
2032  _elementPool.Clear();
2033  _attributePool.Clear();
2034  _textPool.Clear();
2035  _commentPool.Clear();
2036  }
2037  return _errorID;
2038 }
2039 
2040 
2041 void XMLDocument::Print( XMLPrinter* streamer ) const
2042 {
2043  if ( streamer ) {
2044  Accept( streamer );
2045  }
2046  else {
2047  XMLPrinter stdoutStreamer( stdout );
2048  Accept( &stdoutStreamer );
2049  }
2050 }
2051 
2052 
2053 void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
2054 {
2055  TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2056  _errorID = error;
2057  _errorStr1 = str1;
2058  _errorStr2 = str2;
2059 }
2060 
2061 const char* XMLDocument::ErrorName() const
2062 {
2063  TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
2064  const char* errorName = _errorNames[_errorID];
2065  TIXMLASSERT( errorName && errorName[0] );
2066  return errorName;
2067 }
2068 
2070 {
2071  if ( Error() ) {
2072  static const int LEN = 20;
2073  char buf1[LEN] = { 0 };
2074  char buf2[LEN] = { 0 };
2075 
2076  if ( _errorStr1 ) {
2077  TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
2078  }
2079  if ( _errorStr2 ) {
2080  TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
2081  }
2082 
2083  // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
2084  // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
2085  TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
2086  printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
2087  static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
2088  }
2089 }
2090 
2091 void XMLDocument::Parse()
2092 {
2093  TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2094  TIXMLASSERT( _charBuffer );
2095  char* p = _charBuffer;
2096  p = XMLUtil::SkipWhiteSpace( p );
2097  p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2098  if ( !*p ) {
2100  return;
2101  }
2102  ParseDeep(p, 0 );
2103 }
2104 
2105 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2106  _elementJustOpened( false ),
2107  _firstElement( true ),
2108  _fp( file ),
2109  _depth( depth ),
2110  _textDepth( -1 ),
2111  _processEntities( true ),
2112  _compactMode( compact )
2113 {
2114  for( int i=0; i<ENTITY_RANGE; ++i ) {
2115  _entityFlag[i] = false;
2116  _restrictedEntityFlag[i] = false;
2117  }
2118  for( int i=0; i<NUM_ENTITIES; ++i ) {
2119  const char entityValue = entities[i].value;
2120  TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
2121  _entityFlag[ (unsigned char)entityValue ] = true;
2122  }
2123  _restrictedEntityFlag[(unsigned char)'&'] = true;
2124  _restrictedEntityFlag[(unsigned char)'<'] = true;
2125  _restrictedEntityFlag[(unsigned char)'>'] = true; // not required, but consistency is nice
2126  _buffer.Push( 0 );
2127 }
2128 
2129 
2130 void XMLPrinter::Print( const char* format, ... )
2131 {
2132  va_list va;
2133  va_start( va, format );
2134 
2135  if ( _fp ) {
2136  vfprintf( _fp, format, va );
2137  }
2138  else {
2139  const int len = TIXML_VSCPRINTF( format, va );
2140  // Close out and re-start the va-args
2141  va_end( va );
2142  TIXMLASSERT( len >= 0 );
2143  va_start( va, format );
2144  TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2145  char* p = _buffer.PushArr( len ) - 1; // back up over the null terminator.
2146  TIXML_VSNPRINTF( p, len+1, format, va );
2147  }
2148  va_end( va );
2149 }
2150 
2151 
2152 void XMLPrinter::PrintSpace( int depth )
2153 {
2154  for( int i=0; i<depth; ++i ) {
2155  Print( " " );
2156  }
2157 }
2158 
2159 
2160 void XMLPrinter::PrintString( const char* p, bool restricted )
2161 {
2162  // Look for runs of bytes between entities to print.
2163  const char* q = p;
2164 
2165  if ( _processEntities ) {
2166  const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2167  while ( *q ) {
2168  TIXMLASSERT( p <= q );
2169  // Remember, char is sometimes signed. (How many times has that bitten me?)
2170  if ( *q > 0 && *q < ENTITY_RANGE ) {
2171  // Check for entities. If one is found, flush
2172  // the stream up until the entity, write the
2173  // entity, and keep looking.
2174  if ( flag[(unsigned char)(*q)] ) {
2175  while ( p < q ) {
2176  const size_t delta = q - p;
2177  // %.*s accepts type int as "precision"
2178  const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
2179  Print( "%.*s", toPrint, p );
2180  p += toPrint;
2181  }
2182  bool entityPatternPrinted = false;
2183  for( int i=0; i<NUM_ENTITIES; ++i ) {
2184  if ( entities[i].value == *q ) {
2185  Print( "&%s;", entities[i].pattern );
2186  entityPatternPrinted = true;
2187  break;
2188  }
2189  }
2190  if ( !entityPatternPrinted ) {
2191  // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2192  TIXMLASSERT( false );
2193  }
2194  ++p;
2195  }
2196  }
2197  ++q;
2198  TIXMLASSERT( p <= q );
2199  }
2200  }
2201  // Flush the remaining string. This will be the entire
2202  // string if an entity wasn't found.
2203  TIXMLASSERT( p <= q );
2204  if ( !_processEntities || ( p < q ) ) {
2205  Print( "%s", p );
2206  }
2207 }
2208 
2209 
2210 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2211 {
2212  if ( writeBOM ) {
2213  static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2214  Print( "%s", bom );
2215  }
2216  if ( writeDec ) {
2217  PushDeclaration( "xml version=\"1.0\"" );
2218  }
2219 }
2220 
2221 
2222 void XMLPrinter::OpenElement( const char* name, bool compactMode )
2223 {
2225  _stack.Push( name );
2226 
2227  if ( _textDepth < 0 && !_firstElement && !compactMode ) {
2228  Print( "\n" );
2229  }
2230  if ( !compactMode ) {
2231  PrintSpace( _depth );
2232  }
2233 
2234  Print( "<%s", name );
2235  _elementJustOpened = true;
2236  _firstElement = false;
2237  ++_depth;
2238 }
2239 
2240 
2241 void XMLPrinter::PushAttribute( const char* name, const char* value )
2242 {
2244  Print( " %s=\"", name );
2245  PrintString( value, false );
2246  Print( "\"" );
2247 }
2248 
2249 
2250 void XMLPrinter::PushAttribute( const char* name, int v )
2251 {
2252  char buf[BUF_SIZE];
2253  XMLUtil::ToStr( v, buf, BUF_SIZE );
2254  PushAttribute( name, buf );
2255 }
2256 
2257 
2258 void XMLPrinter::PushAttribute( const char* name, unsigned v )
2259 {
2260  char buf[BUF_SIZE];
2261  XMLUtil::ToStr( v, buf, BUF_SIZE );
2262  PushAttribute( name, buf );
2263 }
2264 
2265 
2266 void XMLPrinter::PushAttribute( const char* name, bool v )
2267 {
2268  char buf[BUF_SIZE];
2269  XMLUtil::ToStr( v, buf, BUF_SIZE );
2270  PushAttribute( name, buf );
2271 }
2272 
2273 
2274 void XMLPrinter::PushAttribute( const char* name, double v )
2275 {
2276  char buf[BUF_SIZE];
2277  XMLUtil::ToStr( v, buf, BUF_SIZE );
2278  PushAttribute( name, buf );
2279 }
2280 
2281 
2282 void XMLPrinter::CloseElement( bool compactMode )
2283 {
2284  --_depth;
2285  const char* name = _stack.Pop();
2286 
2287  if ( _elementJustOpened ) {
2288  Print( "/>" );
2289  }
2290  else {
2291  if ( _textDepth < 0 && !compactMode) {
2292  Print( "\n" );
2293  PrintSpace( _depth );
2294  }
2295  Print( "</%s>", name );
2296  }
2297 
2298  if ( _textDepth == _depth ) {
2299  _textDepth = -1;
2300  }
2301  if ( _depth == 0 && !compactMode) {
2302  Print( "\n" );
2303  }
2304  _elementJustOpened = false;
2305 }
2306 
2307 
2309 {
2310  if ( !_elementJustOpened ) {
2311  return;
2312  }
2313  _elementJustOpened = false;
2314  Print( ">" );
2315 }
2316 
2317 
2318 void XMLPrinter::PushText( const char* text, bool cdata )
2319 {
2320  _textDepth = _depth-1;
2321 
2323  if ( cdata ) {
2324  Print( "<![CDATA[%s]]>", text );
2325  }
2326  else {
2327  PrintString( text, true );
2328  }
2329 }
2330 
2331 void XMLPrinter::PushText( int value )
2332 {
2333  char buf[BUF_SIZE];
2334  XMLUtil::ToStr( value, buf, BUF_SIZE );
2335  PushText( buf, false );
2336 }
2337 
2338 
2339 void XMLPrinter::PushText( unsigned value )
2340 {
2341  char buf[BUF_SIZE];
2342  XMLUtil::ToStr( value, buf, BUF_SIZE );
2343  PushText( buf, false );
2344 }
2345 
2346 
2347 void XMLPrinter::PushText( bool value )
2348 {
2349  char buf[BUF_SIZE];
2350  XMLUtil::ToStr( value, buf, BUF_SIZE );
2351  PushText( buf, false );
2352 }
2353 
2354 
2355 void XMLPrinter::PushText( float value )
2356 {
2357  char buf[BUF_SIZE];
2358  XMLUtil::ToStr( value, buf, BUF_SIZE );
2359  PushText( buf, false );
2360 }
2361 
2362 
2363 void XMLPrinter::PushText( double value )
2364 {
2365  char buf[BUF_SIZE];
2366  XMLUtil::ToStr( value, buf, BUF_SIZE );
2367  PushText( buf, false );
2368 }
2369 
2370 
2371 void XMLPrinter::PushComment( const char* comment )
2372 {
2374  if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2375  Print( "\n" );
2376  PrintSpace( _depth );
2377  }
2378  _firstElement = false;
2379  Print( "<!--%s-->", comment );
2380 }
2381 
2382 
2383 void XMLPrinter::PushDeclaration( const char* value )
2384 {
2386  if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2387  Print( "\n" );
2388  PrintSpace( _depth );
2389  }
2390  _firstElement = false;
2391  Print( "<?%s?>", value );
2392 }
2393 
2394 
2395 void XMLPrinter::PushUnknown( const char* value )
2396 {
2398  if ( _textDepth < 0 && !_firstElement && !_compactMode) {
2399  Print( "\n" );
2400  PrintSpace( _depth );
2401  }
2402  _firstElement = false;
2403  Print( "<!%s>", value );
2404 }
2405 
2406 
2408 {
2409  _processEntities = doc.ProcessEntities();
2410  if ( doc.HasBOM() ) {
2411  PushHeader( true, false );
2412  }
2413  return true;
2414 }
2415 
2416 
2417 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2418 {
2419  const XMLElement* parentElem = 0;
2420  if ( element.Parent() ) {
2421  parentElem = element.Parent()->ToElement();
2422  }
2423  const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2424  OpenElement( element.Name(), compactMode );
2425  while ( attribute ) {
2426  PushAttribute( attribute->Name(), attribute->Value() );
2427  attribute = attribute->Next();
2428  }
2429  return true;
2430 }
2431 
2432 
2433 bool XMLPrinter::VisitExit( const XMLElement& element )
2434 {
2435  CloseElement( CompactMode(element) );
2436  return true;
2437 }
2438 
2439 
2440 bool XMLPrinter::Visit( const XMLText& text )
2441 {
2442  PushText( text.Value(), text.CData() );
2443  return true;
2444 }
2445 
2446 
2447 bool XMLPrinter::Visit( const XMLComment& comment )
2448 {
2449  PushComment( comment.Value() );
2450  return true;
2451 }
2452 
2453 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2454 {
2455  PushDeclaration( declaration.Value() );
2456  return true;
2457 }
2458 
2459 
2460 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2461 {
2462  PushUnknown( unknown.Value() );
2463  return true;
2464 }
2465 
2466 } // namespace tinyxml2
2467 
void SetValue(const char *val, bool staticMem=false)
Definition: tinyxml2.cpp:727
static const char * GetCharacterRef(const char *p, char *value, int *length)
Definition: tinyxml2.cpp:430
XMLComment(XMLDocument *doc)
Definition: tinyxml2.cpp:1094
bool CData() const
Returns true if this is a CDATA text element.
Definition: tinyxml2.h:913
const XMLNode * Parent() const
Get the parent of this node on the DOM.
Definition: tinyxml2.h:691
virtual bool VisitExit(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:454
void PushAttribute(const char *name, const char *value)
If streaming, add an attribute to an open element.
Definition: tinyxml2.cpp:2241
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2.cpp:1729
void SetInternedStr(const char *str)
Definition: tinyxml2.h:148
XMLNode * InsertEndChild(XMLNode *addThis)
Definition: tinyxml2.cpp:784
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2.cpp:1185
XMLNode * _next
Definition: tinyxml2.h:869
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2.cpp:685
virtual void CloseElement(bool compactMode=false)
If streaming, close the Element.
Definition: tinyxml2.cpp:2282
static bool ToInt(const char *str, int *value)
Definition: tinyxml2.cpp:559
const char * pattern
Definition: tinyxml2.cpp:123
XMLError QueryBoolText(bool *bval) const
See QueryIntText()
Definition: tinyxml2.cpp:1503
virtual bool Visit(const XMLText &text)
Visit a text node.
Definition: tinyxml2.cpp:2440
virtual bool CompactMode(const XMLElement &)
Definition: tinyxml2.h:2063
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:631
virtual XMLText * ToText()
Safely cast to Text, or null.
Definition: tinyxml2.h:635
virtual ~XMLNode()
Definition: tinyxml2.cpp:711
bool NoChildren() const
Returns true if this node has no children.
Definition: tinyxml2.h:700
bool Empty() const
Definition: tinyxml2.h:144
const char * Value() const
Definition: tinyxml2.cpp:719
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2.cpp:1126
XMLText * NewText(const char *text)
Definition: tinyxml2.cpp:1843
void PushHeader(bool writeBOM, bool writeDeclaration)
Definition: tinyxml2.cpp:2210
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2.cpp:1116
void DeleteChildren()
Definition: tinyxml2.cpp:738
XMLComment * NewComment(const char *comment)
Definition: tinyxml2.cpp:1833
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2.cpp:1039
int ClosingType() const
Definition: tinyxml2.h:1477
virtual char * ParseDeep(char *, StrPair *)
Definition: tinyxml2.cpp:930
void SetCData(bool isCData)
Declare whether this should be CDATA or standard text.
Definition: tinyxml2.h:909
void SetError(XMLError error, const char *str1, const char *str2)
Definition: tinyxml2.cpp:2053
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2.cpp:1067
XMLDocument * _document
Definition: tinyxml2.h:861
static bool StringEqual(const char *p, const char *q, int nChar=INT_MAX)
Definition: tinyxml2.h:555
static bool ToUnsigned(const char *str, unsigned *value)
Definition: tinyxml2.cpp:567
virtual void SetTracked()=0
const char * ErrorName() const
Definition: tinyxml2.cpp:2061
static void ToStr(int v, char *buffer, int bufferSize)
Definition: tinyxml2.cpp:526
const char * Name() const
Get the name of an element (which is the Value() of the node.)
Definition: tinyxml2.h:1149
static const char * ReadBOM(const char *p, bool *hasBOM)
Definition: tinyxml2.cpp:363
XMLUnknown(XMLDocument *doc)
Definition: tinyxml2.cpp:1193
static const char * SkipWhiteSpace(const char *p)
Definition: tinyxml2.h:519
char * ParseText(char *in, const char *endTag, int strFlags)
Definition: tinyxml2.cpp:191
XMLError QueryIntValue(int *value) const
Definition: tinyxml2.cpp:1286
void OpenElement(const char *name, bool compactMode=false)
Definition: tinyxml2.cpp:2222
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:1157
bool HasBOM() const
Definition: tinyxml2.h:1595
static bool IsNameChar(unsigned char ch)
Definition: tinyxml2.h:548
bool ProcessEntities() const
Definition: tinyxml2.h:1585
friend class XMLElement
Definition: tinyxml2.h:1522
XMLNode(XMLDocument *)
Definition: tinyxml2.cpp:701
void DeleteNode(XMLNode *node)
Definition: tinyxml2.cpp:1888
const char * Attribute(const char *name, const char *value=0) const
Definition: tinyxml2.cpp:1404
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2.cpp:1085
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2.cpp:1703
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2.cpp:1104
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2.cpp:1690
void DeleteChild(XMLNode *node)
Definition: tinyxml2.cpp:774
void PushComment(const char *comment)
Add a comment.
Definition: tinyxml2.cpp:2371
virtual bool Visit(const XMLDeclaration &)
Visit a declaration.
Definition: tinyxml2.h:468
virtual void PrintSpace(int depth)
Definition: tinyxml2.cpp:2152
void Push(T t)
Definition: tinyxml2.h:203
DynArray< const char *, 10 > _stack
Definition: tinyxml2.h:2073
XMLError QueryUnsignedText(unsigned *uval) const
See QueryIntText()
Definition: tinyxml2.cpp:1490
virtual bool VisitEnter(const XMLDocument &)
Visit a document.
Definition: tinyxml2.cpp:2407
const char * GetStr()
Definition: tinyxml2.cpp:260
char * Identify(char *p, XMLNode **node)
Definition: tinyxml2.cpp:611
#define false
Definition: ConvertUTF.cpp:56
XMLError QueryUnsignedValue(unsigned int *value) const
See QueryIntValue.
Definition: tinyxml2.cpp:1295
const XMLElement * NextSiblingElement(const char *name=0) const
Get the next (right) sibling element of this node, with an optionally supplied name.
Definition: tinyxml2.cpp:904
XMLNode * _firstChild
Definition: tinyxml2.h:865
void Set(char *start, char *end, int flags)
Definition: tinyxml2.h:135
#define TIXML_VSNPRINTF
Definition: tinyxml2.cpp:93
XMLError QueryFloatValue(float *value) const
See QueryIntValue.
Definition: tinyxml2.cpp:1313
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2.cpp:1134
char * ParseDeep(char *p, StrPair *endTag)
Definition: tinyxml2.cpp:1661
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2.cpp:1234
virtual bool VisitExit(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:2026
char * ParseName(char *in)
Definition: tinyxml2.cpp:211
const XMLElement * PreviousSiblingElement(const char *name=0) const
Get the previous (left) sibling element of this node, with an optionally supplied name...
Definition: tinyxml2.cpp:917
int Size() const
Definition: tinyxml2.h:247
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2.cpp:1078
static bool ToFloat(const char *str, float *value)
Definition: tinyxml2.cpp:594
const XMLDocument * GetDocument() const
Get the XMLDocument that owns this XMLNode.
Definition: tinyxml2.h:620
#define TIXML_SNPRINTF
Definition: tinyxml2.cpp:92
XMLNode * _lastChild
Definition: tinyxml2.h:866
void PushText(const char *text, bool cdata=false)
Add a text node.
Definition: tinyxml2.cpp:2318
virtual bool VisitEnter(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:450
static bool Fits(unsigned long value)
Definition: tinyxml2.cpp:1928
#define true
Definition: ConvertUTF.cpp:57
void SealElementIfJustOpened()
Definition: tinyxml2.cpp:2308
const XMLNode * NextSibling() const
Get the next (right) sibling node of this node.
Definition: tinyxml2.h:757
virtual XMLDocument * ToDocument()
Safely cast to a Document, or null.
Definition: tinyxml2.h:643
static bool ToDouble(const char *str, double *value)
Definition: tinyxml2.cpp:602
T * PushArr(int count)
Definition: tinyxml2.h:209
const char * Value() const
The value of the attribute.
Definition: tinyxml2.cpp:1247
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2.cpp:1216
XMLElement * NewElement(const char *name)
Definition: tinyxml2.cpp:1823
const char * GetText() const
Definition: tinyxml2.cpp:1417
void PushUnknown(const char *value)
Definition: tinyxml2.cpp:2395
XMLError QueryDoubleText(double *dval) const
See QueryIntText()
Definition: tinyxml2.cpp:1516
void SetAttribute(const char *value)
Set the attribute to a string value.
Definition: tinyxml2.cpp:1331
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
Definition: tinyxml2.h:1317
static bool IsWhiteSpace(char p)
Definition: tinyxml2.h:533
XMLError SaveFile(const char *filename, bool compact=false)
Definition: tinyxml2.cpp:1986
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2.cpp:1166
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2.cpp:1154
XMLError QueryFloatText(float *fval) const
See QueryIntText()
Definition: tinyxml2.cpp:1529
XMLError QueryIntText(int *ival) const
Definition: tinyxml2.cpp:1477
static void ConvertUTF32ToUTF8(unsigned long input, char *output, int *length)
Definition: tinyxml2.cpp:381
void TransferTo(StrPair *other)
Definition: tinyxml2.cpp:144
void Clear()
Clear the document, resetting it to the initial state.
Definition: tinyxml2.cpp:1791
virtual bool Accept(XMLVisitor *visitor) const =0
const XMLAttribute * Next() const
The next attribute in the list.
Definition: tinyxml2.h:1055
static bool IsNameStartChar(unsigned char ch)
Definition: tinyxml2.h:537
#define TIXMLASSERT(x)
Definition: tinyxml2.h:88
void Print(XMLPrinter *streamer=0) const
Definition: tinyxml2.cpp:2041
const XMLElement * LastChildElement(const char *name=0) const
Definition: tinyxml2.cpp:890
XMLDeclaration * NewDeclaration(const char *text=0)
Definition: tinyxml2.cpp:1853
XMLError LoadFile(const char *filename)
Definition: tinyxml2.cpp:1906
XMLUnknown * NewUnknown(const char *text)
Definition: tinyxml2.cpp:1863
XMLError QueryDoubleValue(double *value) const
See QueryIntValue.
Definition: tinyxml2.cpp:1322
Whitespace WhitespaceMode() const
Definition: tinyxml2.h:1588
bool Error() const
Return true if there was an error parsing the document.
Definition: tinyxml2.h:1677
XMLError Parse(const char *xml, size_t nBytes=(size_t)(-1))
Definition: tinyxml2.cpp:2010
const XMLElement * FirstChildElement(const char *name=0) const
Definition: tinyxml2.cpp:876
XMLDeclaration(XMLDocument *doc)
Definition: tinyxml2.cpp:1143
void PrintError() const
If there is an error, print it to stdout.
Definition: tinyxml2.cpp:2069
XMLError QueryBoolValue(bool *value) const
See QueryIntValue.
Definition: tinyxml2.cpp:1304
void Print(const char *format,...)
Definition: tinyxml2.cpp:2130
XMLNode * InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)
Definition: tinyxml2.cpp:845
StrPair _value
Definition: tinyxml2.h:863
void DeleteAttribute(const char *name)
Definition: tinyxml2.cpp:1571
static bool ToBool(const char *str, bool *value)
Definition: tinyxml2.cpp:575
XMLPrinter(FILE *file=0, bool compact=false, int depth=0)
Definition: tinyxml2.cpp:2105
void SetText(const char *inText)
Definition: tinyxml2.cpp:1426
virtual XMLUnknown * ToUnknown()
Safely cast to an Unknown, or null.
Definition: tinyxml2.h:651
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:705
void PushDeclaration(const char *value)
Definition: tinyxml2.cpp:2383
#define TIXML_SSCANF
Definition: tinyxml2.cpp:100
virtual XMLDeclaration * ToDeclaration()
Safely cast to a Declaration, or null.
Definition: tinyxml2.h:647
const XMLAttribute * FirstAttribute() const
Return the first attribute in the list.
Definition: tinyxml2.h:1353
const char * Name() const
The name of the attribute.
Definition: tinyxml2.cpp:1242
const XMLAttribute * FindAttribute(const char *name) const
Query a specific attribute in the list.
Definition: tinyxml2.cpp:1393
XMLNode * _parent
Definition: tinyxml2.h:862
void SetStr(const char *str, int flags=0)
Definition: tinyxml2.cpp:178
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2.cpp:1203
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2.cpp:1176
XMLDocument(bool processEntities=true, Whitespace=PRESERVE_WHITESPACE)
constructor
Definition: tinyxml2.cpp:1770
XMLNode * InsertFirstChild(XMLNode *addThis)
Definition: tinyxml2.cpp:814
virtual XMLComment * ToComment()
Safely cast to a Comment, or null.
Definition: tinyxml2.h:639
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2.cpp:1226
XMLNode * _prev
Definition: tinyxml2.h:868