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