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