antioch-0.4.0
tinyxml2_imp.h
Go to the documentation of this file.
1 /*
2 Original code by Lee Thomason (www.grinninglizard.com)
3 
4 This software is provided 'as-is', without any express or implied
5 warranty. In no event will the authors be held liable for any
6 damages arising from the use of this software.
7 
8 Permission is granted to anyone to use this software for any
9 purpose, including commercial applications, and to alter it and
10 redistribute it freely, subject to the following restrictions:
11 
12 1. The origin of this software must not be misrepresented; you must
13 not claim that you wrote the original software. If you use this
14 software in a product, an acknowledgment in the product documentation
15 would be appreciated but is not required.
16 
17 2. Altered source versions must be plainly marked as such, and
18 must not be misrepresented as being the original software.
19 
20 3. This notice may not be removed or altered from any source
21 distribution.
22 */
23 
24 /*
25 Modifications for header-only use, ANTIOCH compatibility, by the
26 ANTIOCH authors.
27 */
28 
29 #include "antioch/tinyxml2.h"
30 
31 #include <new> // yes, this one new style header, is in the Android SDK.
32 #ifdef ANDROID_NDK
33  #include <stddef.h>
34 #else
35  #include <cstddef>
36 #endif
37 
38 using namespace tinyxml2;
39 
40 static const char LINE_FEED = (char)0x0a; // all line endings are normalized to LF
41 static const char LF = LINE_FEED;
42 static const char CARRIAGE_RETURN = (char)0x0d; // CR gets filtered out
43 static const char CR = CARRIAGE_RETURN;
44 static const char SINGLE_QUOTE = '\'';
45 static const char DOUBLE_QUOTE = '\"';
46 
47 // Bunch of unicode info at:
48 // http://www.unicode.org/faq/utf_bom.html
49 // ef bb bf (Microsoft "lead bytes") - designates UTF-8
50 
51 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
52 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
53 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
54 
55 
56 #define DELETE_NODE( node ) { \
57  if ( node ) { \
58  MemPool* pool = node->memPool; \
59  node->~XMLNode(); \
60  pool->Free( node ); \
61  } \
62 }
63 #define DELETE_ATTRIBUTE( attrib ) { \
64  if ( attrib ) { \
65  MemPool* pool = attrib->memPool; \
66  attrib->~XMLAttribute(); \
67  pool->Free( attrib ); \
68  } \
69 }
70 
71 struct Entity {
72  const char* pattern;
73  int length;
74  char value;
75 };
76 
77 static const int NUM_ENTITIES = 5;
78 static const Entity entities[NUM_ENTITIES] =
79 {
80  { "quot", 4, DOUBLE_QUOTE },
81  { "amp", 3, '&' },
82  { "apos", 4, SINGLE_QUOTE },
83  { "lt", 2, '<' },
84  { "gt", 2, '>' }
85 };
86 
87 
88 inline
90 {
91  Reset();
92 }
93 
94 
95 inline
97 {
98  if ( flags & NEEDS_DELETE ) {
99  delete [] start;
100  }
101  flags = 0;
102  start = 0;
103  end = 0;
104 }
105 
106 
107 inline
108 void StrPair::SetStr( const char* str, int flags )
109 {
110  Reset();
111  size_t len = strlen( str );
112  start = new char[ len+1 ];
113  memcpy( start, str, len+1 );
114  end = start + len;
115  this->flags = flags | NEEDS_DELETE;
116 }
117 
118 
119 inline
120 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
121 {
122  TIXMLASSERT( endTag && *endTag );
123 
124  char* start = p; // fixme: hides a member
125  char endChar = *endTag;
126  size_t length = strlen( endTag );
127 
128  // Inner loop of text parsing.
129  while ( *p ) {
130  if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
131  Set( start, p, strFlags );
132  return p + length;
133  }
134  ++p;
135  }
136  return 0;
137 }
138 
139 
140 inline
141 char* StrPair::ParseName( char* p )
142 {
143  char* start = p;
144 
145  if ( !start || !(*start) ) {
146  return 0;
147  }
148 
149  while( *p && (
150  XMLUtil::IsAlphaNum( (unsigned char) *p )
151  || *p == '_'
152  || *p == ':'
153  || (*p == '-' && p>start ) // can be in a name, but not lead it.
154  || (*p == '.' && p>start ) )) // can be in a name, but not lead it.
155  {
156  ++p;
157  }
158 
159  if ( p > start ) {
160  Set( start, p, 0 );
161  return p;
162  }
163  return 0;
164 }
165 
166 
167 inline
169 {
170  // Trim leading space.
172 
173  if ( start && *start ) {
174  char* p = start; // the read pointer
175  char* q = start; // the write pointer
176 
177  while( *p ) {
178  if ( XMLUtil::IsWhiteSpace( *p )) {
179  p = XMLUtil::SkipWhiteSpace( p );
180  if ( *p == 0 )
181  break; // don't write to q; this trims the trailing space.
182  *q = ' ';
183  ++q;
184  }
185  *q = *p;
186  ++q;
187  ++p;
188  }
189  *q = 0;
190  }
191 }
192 
193 
194 inline
195 const char* StrPair::GetStr()
196 {
197  if ( flags & NEEDS_FLUSH ) {
198  *end = 0;
199  flags ^= NEEDS_FLUSH;
200 
201  if ( flags ) {
202  char* p = start; // the read pointer
203  char* q = start; // the write pointer
204 
205  while( p < end ) {
206  if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
207  // CR-LF pair becomes LF
208  // CR alone becomes LF
209  // LF-CR becomes LF
210  if ( *(p+1) == LF ) {
211  p += 2;
212  }
213  else {
214  ++p;
215  }
216  *q++ = LF;
217  }
218  else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
219  if ( *(p+1) == CR ) {
220  p += 2;
221  }
222  else {
223  ++p;
224  }
225  *q++ = LF;
226  }
227  else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
228  // Entities handled by tinyXML2:
229  // - special entities in the entity table [in/out]
230  // - numeric character reference [in]
231  // &#20013; or &#x4e2d;
232 
233  if ( *(p+1) == '#' ) {
234  char buf[10] = { 0 };
235  int len;
236  p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
237  for( int i=0; i<len; ++i ) {
238  *q++ = buf[i];
239  }
240  TIXMLASSERT( q <= p );
241  }
242  else {
243  int i=0;
244  for(; i<NUM_ENTITIES; ++i ) {
245  if ( strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
246  && *(p+entities[i].length+1) == ';' )
247  {
248  // Found an entity convert;
249  *q = entities[i].value;
250  ++q;
251  p += entities[i].length + 2;
252  break;
253  }
254  }
255  if ( i == NUM_ENTITIES ) {
256  // fixme: treat as error?
257  ++p;
258  ++q;
259  }
260  }
261  }
262  else {
263  *q = *p;
264  ++p;
265  ++q;
266  }
267  }
268  *q = 0;
269  }
270  // The loop below has plenty going on, and this
271  // is a less useful mode. Break it out.
272  if ( flags & COLLAPSE_WHITESPACE ) {
274  }
275  flags = (flags & NEEDS_DELETE);
276  }
277  return start;
278 }
279 
280 
281 
282 
283 // --------- XMLUtil ----------- //
284 
285 inline
286 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
287 {
288  *bom = false;
289  const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
290  // Check for BOM:
291  if ( *(pu+0) == TIXML_UTF_LEAD_0
292  && *(pu+1) == TIXML_UTF_LEAD_1
293  && *(pu+2) == TIXML_UTF_LEAD_2 )
294  {
295  *bom = true;
296  p += 3;
297  }
298  return p;
299 }
300 
301 
302 inline
303 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
304 {
305  const unsigned long BYTE_MASK = 0xBF;
306  const unsigned long BYTE_MARK = 0x80;
307  const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
308 
309  if (input < 0x80)
310  *length = 1;
311  else if ( input < 0x800 )
312  *length = 2;
313  else if ( input < 0x10000 )
314  *length = 3;
315  else if ( input < 0x200000 )
316  *length = 4;
317  else
318  { *length = 0; return; } // This code won't covert this correctly anyway.
319 
320  output += *length;
321 
322  // Scary scary fall throughs.
323  switch (*length)
324  {
325  case 4:
326  --output;
327  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
328  input >>= 6;
329  case 3:
330  --output;
331  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
332  input >>= 6;
333  case 2:
334  --output;
335  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
336  input >>= 6;
337  case 1:
338  --output;
339  *output = (char)(input | FIRST_BYTE_MARK[*length]);
340  }
341 }
342 
343 
344 inline
345 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
346 {
347  // Presume an entity, and pull it out.
348  *length = 0;
349 
350  if ( *(p+1) == '#' && *(p+2) )
351  {
352  unsigned long ucs = 0;
353  ptrdiff_t delta = 0;
354  unsigned mult = 1;
355 
356  if ( *(p+2) == 'x' )
357  {
358  // Hexadecimal.
359  if ( !*(p+3) ) return 0;
360 
361  const char* q = p+3;
362  q = strchr( q, ';' );
363 
364  if ( !q || !*q ) return 0;
365 
366  delta = q-p;
367  --q;
368 
369  while ( *q != 'x' )
370  {
371  if ( *q >= '0' && *q <= '9' )
372  ucs += mult * (*q - '0');
373  else if ( *q >= 'a' && *q <= 'f' )
374  ucs += mult * (*q - 'a' + 10);
375  else if ( *q >= 'A' && *q <= 'F' )
376  ucs += mult * (*q - 'A' + 10 );
377  else
378  return 0;
379  mult *= 16;
380  --q;
381  }
382  }
383  else
384  {
385  // Decimal.
386  if ( !*(p+2) ) return 0;
387 
388  const char* q = p+2;
389  q = strchr( q, ';' );
390 
391  if ( !q || !*q ) return 0;
392 
393  delta = q-p;
394  --q;
395 
396  while ( *q != '#' )
397  {
398  if ( *q >= '0' && *q <= '9' )
399  ucs += mult * (*q - '0');
400  else
401  return 0;
402  mult *= 10;
403  --q;
404  }
405  }
406  // convert the UCS to UTF-8
407  ConvertUTF32ToUTF8( ucs, value, length );
408  return p + delta + 1;
409  }
410  return p+1;
411 }
412 
413 
414 inline
415 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
416 {
417  TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
418 }
419 
420 
421 inline
422 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
423 {
424  TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
425 }
426 
427 
428 inline
429 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
430 {
431  TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
432 }
433 
434 
435 inline
436 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
437 {
438  TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
439 }
440 
441 
442 inline
443 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
444 {
445  TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
446 }
447 
448 
449 inline
450 bool XMLUtil::ToInt( const char* str, int* value )
451 {
452  if ( TIXML_SSCANF( str, "%d", value ) == 1 )
453  return true;
454  return false;
455 }
456 
457 inline
458 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
459 {
460  if ( TIXML_SSCANF( str, "%u", value ) == 1 )
461  return true;
462  return false;
463 }
464 
465 inline
466 bool XMLUtil::ToBool( const char* str, bool* value )
467 {
468  int ival = 0;
469  if ( ToInt( str, &ival )) {
470  *value = (ival==0) ? false : true;
471  return true;
472  }
473  if ( StringEqual( str, "true" ) ) {
474  *value = true;
475  return true;
476  }
477  else if ( StringEqual( str, "false" ) ) {
478  *value = false;
479  return true;
480  }
481  return false;
482 }
483 
484 
485 inline
486 bool XMLUtil::ToFloat( const char* str, float* value )
487 {
488  if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
489  return true;
490  }
491  return false;
492 }
493 
494 inline
495 bool XMLUtil::ToDouble( const char* str, double* value )
496 {
497  if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
498  return true;
499  }
500  return false;
501 }
502 
503 
504 inline
505 char* XMLDocument::Identify( char* p, XMLNode** node )
506 {
507  XMLNode* returnNode = 0;
508  char* start = p;
509  p = XMLUtil::SkipWhiteSpace( p );
510  if( !p || !*p )
511  {
512  return p;
513  }
514 
515  // What is this thing?
516  // - Elements start with a letter or underscore, but xml is reserved.
517  // - Comments: <!--
518  // - Decleration: <?
519  // - Everthing else is unknown to tinyxml.
520  //
521 
522  static const char* xmlHeader = { "<?" };
523  static const char* commentHeader = { "<!--" };
524  static const char* dtdHeader = { "<!" };
525  static const char* cdataHeader = { "<![CDATA[" };
526  static const char* elementHeader = { "<" }; // and a header for everything else; check last.
527 
528  static const int xmlHeaderLen = 2;
529  static const int commentHeaderLen = 4;
530  static const int dtdHeaderLen = 2;
531  static const int cdataHeaderLen = 9;
532  static const int elementHeaderLen = 1;
533 
534 #if defined(_MSC_VER)
535 #pragma warning ( push )
536 #pragma warning ( disable : 4127 )
537 #endif
538  TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) ); // use same memory pool
539  TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) ); // use same memory pool
540 #if defined(_MSC_VER)
541 #pragma warning (pop)
542 #endif
543  if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
544  returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
545  returnNode->memPool = &commentPool;
546  p += xmlHeaderLen;
547  }
548  else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
549  returnNode = new (commentPool.Alloc()) XMLComment( this );
550  returnNode->memPool = &commentPool;
551  p += commentHeaderLen;
552  }
553  else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
554  XMLText* text = new (textPool.Alloc()) XMLText( this );
555  returnNode = text;
556  returnNode->memPool = &textPool;
557  p += cdataHeaderLen;
558  text->SetCData( true );
559  }
560  else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
561  returnNode = new (commentPool.Alloc()) XMLUnknown( this );
562  returnNode->memPool = &commentPool;
563  p += dtdHeaderLen;
564  }
565  else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
566  returnNode = new (elementPool.Alloc()) XMLElement( this );
567  returnNode->memPool = &elementPool;
568  p += elementHeaderLen;
569  }
570  else {
571  returnNode = new (textPool.Alloc()) XMLText( this );
572  returnNode->memPool = &textPool;
573  p = start; // Back it up, all the text counts.
574  }
575 
576  *node = returnNode;
577  return p;
578 }
579 
580 
581 inline
582 bool XMLDocument::Accept( XMLVisitor* visitor ) const
583 {
584  if ( visitor->VisitEnter( *this ) )
585  {
586  for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
587  {
588  if ( !node->Accept( visitor ) )
589  break;
590  }
591  }
592  return visitor->VisitExit( *this );
593 }
594 
595 
596 // --------- XMLNode ----------- //
597 
598 inline
600  document( doc ),
601  parent( 0 ),
602  firstChild( 0 ), lastChild( 0 ),
603  prev( 0 ), next( 0 )
604 {
605 }
606 
607 
608 inline
610 {
611  DeleteChildren();
612  if ( parent ) {
613  parent->Unlink( this );
614  }
615 }
616 
617 
618 inline
619 void XMLNode::SetValue( const char* str, bool staticMem )
620 {
621  if ( staticMem )
622  value.SetInternedStr( str );
623  else
624  value.SetStr( str );
625 }
626 
627 
628 inline
630 {
631  while( firstChild ) {
632  XMLNode* node = firstChild;
633  Unlink( node );
634 
635  DELETE_NODE( node );
636  }
637  firstChild = lastChild = 0;
638 }
639 
640 
641 inline
642 void XMLNode::Unlink( XMLNode* child )
643 {
644  TIXMLASSERT( child->parent == this );
645  if ( child == firstChild )
647  if ( child == lastChild )
649 
650  if ( child->prev ) {
651  child->prev->next = child->next;
652  }
653  if ( child->next ) {
654  child->next->prev = child->prev;
655  }
656  child->parent = 0;
657 }
658 
659 
660 inline
662 {
663  TIXMLASSERT( node->parent == this );
664  DELETE_NODE( node );
665 }
666 
667 
668 inline
670 {
671  if ( lastChild ) {
673  TIXMLASSERT( lastChild->next == 0 );
674  lastChild->next = addThis;
675  addThis->prev = lastChild;
676  lastChild = addThis;
677 
678  addThis->next = 0;
679  }
680  else {
681  TIXMLASSERT( firstChild == 0 );
682  firstChild = lastChild = addThis;
683 
684  addThis->prev = 0;
685  addThis->next = 0;
686  }
687  addThis->parent = this;
688  return addThis;
689 }
690 
691 
692 inline
694 {
695  if ( firstChild ) {
697  TIXMLASSERT( firstChild->prev == 0 );
698 
699  firstChild->prev = addThis;
700  addThis->next = firstChild;
701  firstChild = addThis;
702 
703  addThis->prev = 0;
704  }
705  else {
706  TIXMLASSERT( lastChild == 0 );
707  firstChild = lastChild = addThis;
708 
709  addThis->prev = 0;
710  addThis->next = 0;
711  }
712  addThis->parent = this;
713  return addThis;
714 }
715 
716 
717 inline
719 {
720  TIXMLASSERT( afterThis->parent == this );
721  if ( afterThis->parent != this )
722  return 0;
723 
724  if ( afterThis->next == 0 ) {
725  // The last node or the only node.
726  return InsertEndChild( addThis );
727  }
728  addThis->prev = afterThis;
729  addThis->next = afterThis->next;
730  afterThis->next->prev = addThis;
731  afterThis->next = addThis;
732  addThis->parent = this;
733  return addThis;
734 }
735 
736 
737 
738 
739 inline
740 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
741 {
742  for( XMLNode* node=firstChild; node; node=node->next ) {
743  XMLElement* element = node->ToElement();
744  if ( element ) {
745  if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
746  return element;
747  }
748  }
749  }
750  return 0;
751 }
752 
753 
754 inline
755 const XMLElement* XMLNode::LastChildElement( const char* value ) const
756 {
757  for( XMLNode* node=lastChild; node; node=node->prev ) {
758  XMLElement* element = node->ToElement();
759  if ( element ) {
760  if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
761  return element;
762  }
763  }
764  }
765  return 0;
766 }
767 
768 
769 inline
770 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
771 {
772  for( XMLNode* element=this->next; element; element = element->next ) {
773  if ( element->ToElement()
774  && (!value || XMLUtil::StringEqual( value, element->Value() )))
775  {
776  return element->ToElement();
777  }
778  }
779  return 0;
780 }
781 
782 
783 inline
784 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
785 {
786  for( XMLNode* element=this->prev; element; element = element->prev ) {
787  if ( element->ToElement()
788  && (!value || XMLUtil::StringEqual( value, element->Value() )))
789  {
790  return element->ToElement();
791  }
792  }
793  return 0;
794 }
795 
796 
797 inline
798 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
799 {
800  // This is a recursive method, but thinking about it "at the current level"
801  // it is a pretty simple flat list:
802  // <foo/>
803  // <!-- comment -->
804  //
805  // With a special case:
806  // <foo>
807  // </foo>
808  // <!-- comment -->
809  //
810  // Where the closing element (/foo) *must* be the next thing after the opening
811  // element, and the names must match. BUT the tricky bit is that the closing
812  // element will be read by the child.
813  //
814  // 'endTag' is the end tag for this node, it is returned by a call to a child.
815  // 'parentEnd' is the end tag for the parent, which is filled in and returned.
816 
817  while( p && *p ) {
818  XMLNode* node = 0;
819 
820  p = document->Identify( p, &node );
821  if ( p == 0 || node == 0 ) {
822  break;
823  }
824 
825  StrPair endTag;
826  p = node->ParseDeep( p, &endTag );
827  if ( !p ) {
828  DELETE_NODE( node );
829  node = 0;
830  if ( !document->Error() ) {
832  }
833  break;
834  }
835 
836  // We read the end tag. Return it to the parent.
837  if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
838  if ( parentEnd ) {
839  *parentEnd = static_cast<XMLElement*>(node)->value;
840  }
841  DELETE_NODE( node );
842  return p;
843  }
844 
845  // Handle an end tag returned to this level.
846  // And handle a bunch of annoying errors.
847  XMLElement* ele = node->ToElement();
848  if ( ele ) {
849  if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
851  p = 0;
852  }
853  else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
855  p = 0;
856  }
857  else if ( !endTag.Empty() ) {
858  if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
860  p = 0;
861  }
862  }
863  }
864  if ( p == 0 ) {
865  DELETE_NODE( node );
866  node = 0;
867  }
868  if ( node ) {
869  this->InsertEndChild( node );
870  }
871  }
872  return 0;
873 }
874 
875 // --------- XMLText ---------- //
876 inline
877 char* XMLText::ParseDeep( char* p, StrPair* )
878 {
879  const char* start = p;
880  if ( this->CData() ) {
882  if ( !p ) {
884  }
885  return p;
886  }
887  else {
891 
892  p = value.ParseText( p, "<", flags );
893  if ( !p ) {
895  }
896  if ( p && *p ) {
897  return p-1;
898  }
899  }
900  return 0;
901 }
902 
903 
904 inline
906 {
907  if ( !doc ) {
908  doc = document;
909  }
910  XMLText* text = doc->NewText( Value() ); // fixme: this will always allocate memory. Intern?
911  text->SetCData( this->CData() );
912  return text;
913 }
914 
915 
916 inline
917 bool XMLText::ShallowEqual( const XMLNode* compare ) const
918 {
919  return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
920 }
921 
922 
923 inline
924 bool XMLText::Accept( XMLVisitor* visitor ) const
925 {
926  return visitor->Visit( *this );
927 }
928 
929 
930 // --------- XMLComment ---------- //
931 
932 inline
934 {
935 }
936 
937 
938 inline
940 {
941  //printf( "~XMLComment\n" );
942 }
943 
944 
945 inline
946 char* XMLComment::ParseDeep( char* p, StrPair* )
947 {
948  // Comment parses as text.
949  const char* start = p;
950  p = value.ParseText( p, "-->", StrPair::COMMENT );
951  if ( p == 0 ) {
953  }
954  return p;
955 }
956 
957 
958 inline
960 {
961  if ( !doc ) {
962  doc = document;
963  }
964  XMLComment* comment = doc->NewComment( Value() ); // fixme: this will always allocate memory. Intern?
965  return comment;
966 }
967 
968 
969 inline
970 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
971 {
972  return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
973 }
974 
975 
976 inline
977 bool XMLComment::Accept( XMLVisitor* visitor ) const
978 {
979  return visitor->Visit( *this );
980 }
981 
982 
983 // --------- XMLDeclaration ---------- //
984 
985 inline
987 {
988 }
989 
990 
991 inline
993 {
994  //printf( "~XMLDeclaration\n" );
995 }
996 
997 
998 inline
1000 {
1001  // Declaration parses as text.
1002  const char* start = p;
1004  if ( p == 0 ) {
1006  }
1007  return p;
1008 }
1009 
1010 
1011 inline
1013 {
1014  if ( !doc ) {
1015  doc = document;
1016  }
1017  XMLDeclaration* dec = doc->NewDeclaration( Value() ); // fixme: this will always allocate memory. Intern?
1018  return dec;
1019 }
1020 
1021 
1022 inline
1023 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1024 {
1025  return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
1026 }
1027 
1028 
1029 
1030 inline
1031 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1032 {
1033  return visitor->Visit( *this );
1034 }
1035 
1036 // --------- XMLUnknown ---------- //
1037 
1038 inline
1040 {
1041 }
1042 
1043 
1044 inline
1046 {
1047 }
1048 
1049 
1050 inline
1051 char* XMLUnknown::ParseDeep( char* p, StrPair* )
1052 {
1053  // Unknown parses as text.
1054  const char* start = p;
1055 
1057  if ( !p ) {
1059  }
1060  return p;
1061 }
1062 
1063 
1064 inline
1066 {
1067  if ( !doc ) {
1068  doc = document;
1069  }
1070  XMLUnknown* text = doc->NewUnknown( Value() ); // fixme: this will always allocate memory. Intern?
1071  return text;
1072 }
1073 
1074 
1075 inline
1076 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1077 {
1078  return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
1079 }
1080 
1081 
1082 inline
1083 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1084 {
1085  return visitor->Visit( *this );
1086 }
1087 
1088 // --------- XMLAttribute ---------- //
1089 inline
1090 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
1091 {
1092  // Parse using the name rules: bug fix, was using ParseText before
1093  p = name.ParseName( p );
1094  if ( !p || !*p ) return 0;
1095 
1096  // Skip white space before =
1097  p = XMLUtil::SkipWhiteSpace( p );
1098  if ( !p || *p != '=' ) return 0;
1099 
1100  ++p; // move up to opening quote
1101  p = XMLUtil::SkipWhiteSpace( p );
1102  if ( *p != '\"' && *p != '\'' ) return 0;
1103 
1104  char endTag[2] = { *p, 0 };
1105  ++p; // move past opening quote
1106 
1108  return p;
1109 }
1110 
1111 
1112 inline
1113 void XMLAttribute::SetName( const char* n )
1114 {
1115  name.SetStr( n );
1116 }
1117 
1118 
1119 inline
1120 int XMLAttribute::QueryIntValue( int* value ) const
1121 {
1122  if ( XMLUtil::ToInt( Value(), value ))
1123  return XML_NO_ERROR;
1124  return XML_WRONG_ATTRIBUTE_TYPE;
1125 }
1126 
1127 
1128 inline
1129 int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1130 {
1131  if ( XMLUtil::ToUnsigned( Value(), value ))
1132  return XML_NO_ERROR;
1133  return XML_WRONG_ATTRIBUTE_TYPE;
1134 }
1135 
1136 
1137 inline
1138 int XMLAttribute::QueryBoolValue( bool* value ) const
1139 {
1140  if ( XMLUtil::ToBool( Value(), value )) {
1141  return XML_NO_ERROR;
1142  }
1143  return XML_WRONG_ATTRIBUTE_TYPE;
1144 }
1145 
1146 
1147 inline
1148 int XMLAttribute::QueryFloatValue( float* value ) const
1149 {
1150  if ( XMLUtil::ToFloat( Value(), value ))
1151  return XML_NO_ERROR;
1152  return XML_WRONG_ATTRIBUTE_TYPE;
1153 }
1154 
1155 
1156 inline
1157 int XMLAttribute::QueryDoubleValue( double* value ) const
1158 {
1159  if ( XMLUtil::ToDouble( Value(), value ))
1160  return XML_NO_ERROR;
1161  return XML_WRONG_ATTRIBUTE_TYPE;
1162 }
1163 
1164 
1165 inline
1166 void XMLAttribute::SetAttribute( const char* v )
1167 {
1168  value.SetStr( v );
1169 }
1170 
1171 
1172 inline
1174 {
1175  char buf[BUF_SIZE];
1176  XMLUtil::ToStr( v, buf, BUF_SIZE );
1177  value.SetStr( buf );
1178 }
1179 
1180 
1181 inline
1182 void XMLAttribute::SetAttribute( unsigned v )
1183 {
1184  char buf[BUF_SIZE];
1185  XMLUtil::ToStr( v, buf, BUF_SIZE );
1186  value.SetStr( buf );
1187 }
1188 
1189 
1190 inline
1192 {
1193  char buf[BUF_SIZE];
1194  XMLUtil::ToStr( v, buf, BUF_SIZE );
1195  value.SetStr( buf );
1196 }
1197 
1198 inline
1200 {
1201  char buf[BUF_SIZE];
1202  XMLUtil::ToStr( v, buf, BUF_SIZE );
1203  value.SetStr( buf );
1204 }
1205 
1206 inline
1208 {
1209  char buf[BUF_SIZE];
1210  XMLUtil::ToStr( v, buf, BUF_SIZE );
1211  value.SetStr( buf );
1212 }
1213 
1214 
1215 // --------- XMLElement ---------- //
1216 inline
1218  closingType( 0 ),
1219  rootAttribute( 0 )
1220 {
1221 }
1222 
1223 
1224 inline
1226 {
1227  while( rootAttribute ) {
1230  rootAttribute = next;
1231  }
1232 }
1233 
1234 
1235 inline
1237 {
1238  XMLAttribute* a = 0;
1239  for( a=rootAttribute; a; a = a->next ) {
1240  if ( XMLUtil::StringEqual( a->Name(), name ) )
1241  return a;
1242  }
1243  return 0;
1244 }
1245 
1246 
1247 inline
1248 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1249 {
1250  XMLAttribute* a = 0;
1251  for( a=rootAttribute; a; a = a->next ) {
1252  if ( XMLUtil::StringEqual( a->Name(), name ) )
1253  return a;
1254  }
1255  return 0;
1256 }
1257 
1258 
1259 inline
1260 const char* XMLElement::Attribute( const char* name, const char* value ) const
1261 {
1262  const XMLAttribute* a = FindAttribute( name );
1263  if ( !a )
1264  return 0;
1265  if ( !value || XMLUtil::StringEqual( a->Value(), value ))
1266  return a->Value();
1267  return 0;
1268 }
1269 
1270 
1271 inline
1272 const char* XMLElement::GetText() const
1273 {
1274  if ( FirstChild() && FirstChild()->ToText() ) {
1275  return FirstChild()->ToText()->Value();
1276  }
1277  return 0;
1278 }
1279 
1280 
1281 inline
1282 int XMLElement::QueryIntText( int* _value ) const
1283 {
1284  if ( FirstChild() && FirstChild()->ToText() ) {
1285  const char* t = FirstChild()->ToText()->Value();
1286  if ( XMLUtil::ToInt( t, _value ) ) {
1287  return XML_SUCCESS;
1288  }
1289  return XML_CAN_NOT_CONVERT_TEXT;
1290  }
1291  return XML_NO_TEXT_NODE;
1292 }
1293 
1294 
1295 inline
1296 int XMLElement::QueryUnsignedText( unsigned* _value ) const
1297 {
1298  if ( FirstChild() && FirstChild()->ToText() ) {
1299  const char* t = FirstChild()->ToText()->Value();
1300  if ( XMLUtil::ToUnsigned( t, _value ) ) {
1301  return XML_SUCCESS;
1302  }
1303  return XML_CAN_NOT_CONVERT_TEXT;
1304  }
1305  return XML_NO_TEXT_NODE;
1306 }
1307 
1308 
1309 inline
1310 int XMLElement::QueryBoolText( bool* _value ) const
1311 {
1312  if ( FirstChild() && FirstChild()->ToText() ) {
1313  const char* t = FirstChild()->ToText()->Value();
1314  if ( XMLUtil::ToBool( t, _value ) ) {
1315  return XML_SUCCESS;
1316  }
1317  return XML_CAN_NOT_CONVERT_TEXT;
1318  }
1319  return XML_NO_TEXT_NODE;
1320 }
1321 
1322 
1323 inline
1324 int XMLElement::QueryDoubleText( double* _value ) const
1325 {
1326  if ( FirstChild() && FirstChild()->ToText() ) {
1327  const char* t = FirstChild()->ToText()->Value();
1328  if ( XMLUtil::ToDouble( t, _value ) ) {
1329  return XML_SUCCESS;
1330  }
1331  return XML_CAN_NOT_CONVERT_TEXT;
1332  }
1333  return XML_NO_TEXT_NODE;
1334 }
1335 
1336 
1337 inline
1338 int XMLElement::QueryFloatText( float* _value ) const
1339 {
1340  if ( FirstChild() && FirstChild()->ToText() ) {
1341  const char* t = FirstChild()->ToText()->Value();
1342  if ( XMLUtil::ToFloat( t, _value ) ) {
1343  return XML_SUCCESS;
1344  }
1345  return XML_CAN_NOT_CONVERT_TEXT;
1346  }
1347  return XML_NO_TEXT_NODE;
1348 }
1349 
1350 
1351 
1352 inline
1354 {
1355  XMLAttribute* last = 0;
1356  XMLAttribute* attrib = 0;
1357  for( attrib = rootAttribute;
1358  attrib;
1359  last = attrib, attrib = attrib->next )
1360  {
1361  if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1362  break;
1363  }
1364  }
1365  if ( !attrib ) {
1366  attrib = new (document->attributePool.Alloc() ) XMLAttribute();
1367  attrib->memPool = &document->attributePool;
1368  if ( last ) {
1369  last->next = attrib;
1370  }
1371  else {
1372  rootAttribute = attrib;
1373  }
1374  attrib->SetName( name );
1375  }
1376  return attrib;
1377 }
1378 
1379 
1380 inline
1381 void XMLElement::DeleteAttribute( const char* name )
1382 {
1383  XMLAttribute* prev = 0;
1384  for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
1385  if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1386  if ( prev ) {
1387  prev->next = a->next;
1388  }
1389  else {
1390  rootAttribute = a->next;
1391  }
1392  DELETE_ATTRIBUTE( a );
1393  break;
1394  }
1395  prev = a;
1396  }
1397 }
1398 
1399 
1400 inline
1402 {
1403  const char* start = p;
1404  XMLAttribute* prevAttribute = 0;
1405 
1406  // Read the attributes.
1407  while( p ) {
1408  p = XMLUtil::SkipWhiteSpace( p );
1409  if ( !p || !(*p) ) {
1411  return 0;
1412  }
1413 
1414  // attribute.
1415  if ( XMLUtil::IsAlpha( *p ) ) {
1416  XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
1417  attrib->memPool = &document->attributePool;
1418 
1419  p = attrib->ParseDeep( p, document->ProcessEntities() );
1420  if ( !p || Attribute( attrib->Name() ) ) {
1421  DELETE_ATTRIBUTE( attrib );
1423  return 0;
1424  }
1425  // There is a minor bug here: if the attribute in the source xml
1426  // document is duplicated, it will not be detected and the
1427  // attribute will be doubly added. However, tracking the 'prevAttribute'
1428  // avoids re-scanning the attribute list. Preferring performance for
1429  // now, may reconsider in the future.
1430  if ( prevAttribute ) {
1431  prevAttribute->next = attrib;
1432  }
1433  else {
1434  rootAttribute = attrib;
1435  }
1436  prevAttribute = attrib;
1437  }
1438  // end of the tag
1439  else if ( *p == '/' && *(p+1) == '>' ) {
1440  closingType = CLOSED;
1441  return p+2; // done; sealed element.
1442  }
1443  // end of the tag
1444  else if ( *p == '>' ) {
1445  ++p;
1446  break;
1447  }
1448  else {
1450  return 0;
1451  }
1452  }
1453  return p;
1454 }
1455 
1456 
1457 //
1458 // <ele></ele>
1459 // <ele>foo<b>bar</b></ele>
1460 //
1461 inline
1462 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
1463 {
1464  // Read the element name.
1465  p = XMLUtil::SkipWhiteSpace( p );
1466  if ( !p ) return 0;
1467 
1468  // The closing element is the </element> form. It is
1469  // parsed just like a regular element then deleted from
1470  // the DOM.
1471  if ( *p == '/' ) {
1472  closingType = CLOSING;
1473  ++p;
1474  }
1475 
1476  p = value.ParseName( p );
1477  if ( value.Empty() ) return 0;
1478 
1479  p = ParseAttributes( p );
1480  if ( !p || !*p || closingType )
1481  return p;
1482 
1483  p = XMLNode::ParseDeep( p, strPair );
1484  return p;
1485 }
1486 
1487 
1488 
1489 inline
1491 {
1492  if ( !doc ) {
1493  doc = document;
1494  }
1495  XMLElement* element = doc->NewElement( Value() ); // fixme: this will always allocate memory. Intern?
1496  for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
1497  element->SetAttribute( a->Name(), a->Value() ); // fixme: this will always allocate memory. Intern?
1498  }
1499  return element;
1500 }
1501 
1502 
1503 inline
1504 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
1505 {
1506  const XMLElement* other = compare->ToElement();
1507  if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
1508 
1509  const XMLAttribute* a=FirstAttribute();
1510  const XMLAttribute* b=other->FirstAttribute();
1511 
1512  while ( a && b ) {
1513  if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
1514  return false;
1515  }
1516  a = a->Next();
1517  b = b->Next();
1518  }
1519  if ( a || b ) {
1520  // different count
1521  return false;
1522  }
1523  return true;
1524  }
1525  return false;
1526 }
1527 
1528 
1529 inline
1530 bool XMLElement::Accept( XMLVisitor* visitor ) const
1531 {
1532  if ( visitor->VisitEnter( *this, rootAttribute ) )
1533  {
1534  for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
1535  {
1536  if ( !node->Accept( visitor ) )
1537  break;
1538  }
1539  }
1540  return visitor->VisitExit( *this );
1541 }
1542 
1543 
1544 // --------- XMLDocument ----------- //
1545 inline
1546 XMLDocument::XMLDocument( bool _processEntities, Whitespace _whitespace ) :
1547  XMLNode( 0 ),
1548  writeBOM( false ),
1549  processEntities( _processEntities ),
1550  errorID( 0 ),
1551  whitespace( _whitespace ),
1552  errorStr1( 0 ),
1553  errorStr2( 0 ),
1554  charBuffer( 0 )
1555 {
1556  document = this; // avoid warning about 'this' in initializer list
1557 }
1558 
1559 
1560 inline
1562 {
1563  DeleteChildren();
1564  delete [] charBuffer;
1565 
1566 #if 0
1567  textPool.Trace( "text" );
1568  elementPool.Trace( "element" );
1569  commentPool.Trace( "comment" );
1570  attributePool.Trace( "attribute" );
1571 #endif
1572 
1573  TIXMLASSERT( textPool.CurrentAllocs() == 0 );
1574  TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
1575  TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
1576  TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
1577 }
1578 
1579 
1580 inline
1582 {
1584  errorStr1 = 0;
1585  errorStr2 = 0;
1586 
1587  delete [] charBuffer;
1588  charBuffer = 0;
1589 
1590 }
1591 
1592 
1593 inline
1595 {
1596  XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
1597  ele->memPool = &elementPool;
1598  ele->SetName( name );
1599  return ele;
1600 }
1601 
1602 
1603 inline
1605 {
1606  XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
1607  comment->memPool = &commentPool;
1608  comment->SetValue( str );
1609  return comment;
1610 }
1611 
1612 
1613 inline
1614 XMLText* XMLDocument::NewText( const char* str )
1615 {
1616  XMLText* text = new (textPool.Alloc()) XMLText( this );
1617  text->memPool = &textPool;
1618  text->SetValue( str );
1619  return text;
1620 }
1621 
1622 
1623 inline
1625 {
1626  XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
1627  dec->memPool = &commentPool;
1628  dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
1629  return dec;
1630 }
1631 
1632 
1633 inline
1635 {
1636  XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
1637  unk->memPool = &commentPool;
1638  unk->SetValue( str );
1639  return unk;
1640 }
1641 
1642 
1643 inline
1644 int XMLDocument::LoadFile( const char* filename )
1645 {
1646  DeleteChildren();
1647  InitDocument();
1648  FILE* fp = 0;
1649 
1650  #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1651  errno_t err = fopen_s(&fp, filename, "rb" );
1652  if ( !fp || err) {
1653  #else
1654  fp = fopen( filename, "rb" );
1655  if ( !fp) {
1656  #endif
1657  SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
1658  return errorID;
1659  }
1660  LoadFile( fp );
1661  fclose( fp );
1662  return errorID;
1663 }
1664 
1665 
1666 inline
1667 int XMLDocument::LoadFile( FILE* fp )
1668 {
1669  DeleteChildren();
1670  InitDocument();
1671 
1672  fseek( fp, 0, SEEK_END );
1673  unsigned size = ftell( fp );
1674  fseek( fp, 0, SEEK_SET );
1675 
1676  if ( size == 0 ) {
1677  return errorID;
1678  }
1679 
1680  charBuffer = new char[size+1];
1681  size_t read = fread( charBuffer, 1, size, fp );
1682  if ( read != size ) {
1684  return errorID;
1685  }
1686 
1687  charBuffer[size] = 0;
1688 
1689  const char* p = charBuffer;
1690  p = XMLUtil::SkipWhiteSpace( p );
1691  p = XMLUtil::ReadBOM( p, &writeBOM );
1692  if ( !p || !*p ) {
1694  return errorID;
1695  }
1696 
1697  ParseDeep( charBuffer + (p-charBuffer), 0 );
1698  return errorID;
1699 }
1700 
1701 
1702 inline
1703 int XMLDocument::SaveFile( const char* filename, bool compact )
1704 {
1705  FILE* fp = 0;
1706  #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
1707  errno_t err = fopen_s(&fp, filename, "w" );
1708  if ( !fp || err) {
1709  #else
1710  fp = fopen( filename, "w" );
1711  if ( !fp) {
1712  #endif
1714  return errorID;
1715  }
1716  SaveFile(fp, compact);
1717  fclose( fp );
1718  return errorID;
1719 }
1720 
1721 
1722 inline
1723 int XMLDocument::SaveFile( FILE* fp, bool compact )
1724 {
1725  XMLPrinter stream( fp, compact );
1726  Print( &stream );
1727  return errorID;
1728 }
1729 
1730 
1731 inline
1732 int XMLDocument::Parse( const char* p, size_t len )
1733 {
1734  DeleteChildren();
1735  InitDocument();
1736 
1737  if ( !p || !*p ) {
1739  return errorID;
1740  }
1741  if ( len == (size_t)(-1) ) {
1742  len = strlen( p );
1743  }
1744  charBuffer = new char[ len+1 ];
1745  memcpy( charBuffer, p, len );
1746  charBuffer[len] = 0;
1747 
1748  p = XMLUtil::SkipWhiteSpace( p );
1749  p = XMLUtil::ReadBOM( p, &writeBOM );
1750  if ( !p || !*p ) {
1752  return errorID;
1753  }
1754 
1755  ParseDeep( charBuffer, 0 );
1756  return errorID;
1757 }
1758 
1759 
1760 inline
1762 {
1763  XMLPrinter stdStreamer( stdout );
1764  if ( !streamer )
1765  streamer = &stdStreamer;
1766  Accept( streamer );
1767 }
1768 
1769 
1770 inline
1771 void XMLDocument::SetError( int error, const char* str1, const char* str2 )
1772 {
1773  errorID = error;
1774  errorStr1 = str1;
1775  errorStr2 = str2;
1776 }
1777 
1778 
1779 inline
1781 {
1782  if ( errorID ) {
1783  static const int LEN = 20;
1784  char buf1[LEN] = { 0 };
1785  char buf2[LEN] = { 0 };
1786 
1787  if ( errorStr1 ) {
1788  TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
1789  }
1790  if ( errorStr2 ) {
1791  TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
1792  }
1793 
1794  printf( "XMLDocument error id=%d str1=%s str2=%s\n",
1795  errorID, buf1, buf2 );
1796  }
1797 }
1798 
1799 
1800 inline
1801 XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
1802  elementJustOpened( false ),
1803  firstElement( true ),
1804  fp( file ),
1805  depth( 0 ),
1806  textDepth( -1 ),
1807  processEntities( true ),
1808  compactMode( compact )
1809 {
1810  for( int i=0; i<ENTITY_RANGE; ++i ) {
1811  entityFlag[i] = false;
1812  restrictedEntityFlag[i] = false;
1813  }
1814  for( int i=0; i<NUM_ENTITIES; ++i ) {
1815  TIXMLASSERT( entities[i].value < ENTITY_RANGE );
1816  if ( entities[i].value < ENTITY_RANGE ) {
1817  entityFlag[ (int)entities[i].value ] = true;
1818  }
1819  }
1820  restrictedEntityFlag[(int)'&'] = true;
1821  restrictedEntityFlag[(int)'<'] = true;
1822  restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
1823  buffer.Push( 0 );
1824 }
1825 
1826 
1827 inline
1828 void XMLPrinter::Print( const char* format, ... )
1829 {
1830  va_list va;
1831  va_start( va, format );
1832 
1833  if ( fp ) {
1834  vfprintf( fp, format, va );
1835  }
1836  else {
1837  // This seems brutally complex. Haven't figured out a better
1838  // way on windows.
1839  #ifdef _MSC_VER
1840  int len = -1;
1841  int expand = 1000;
1842  while ( len < 0 ) {
1843  len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
1844  if ( len < 0 ) {
1845  expand *= 3/2;
1846  accumulator.PushArr( expand );
1847  }
1848  }
1849  char* p = buffer.PushArr( len ) - 1;
1850  memcpy( p, accumulator.Mem(), len+1 );
1851  #else
1852  int len = vsnprintf( 0, 0, format, va );
1853  // Close out and re-start the va-args
1854  va_end( va );
1855  va_start( va, format );
1856  char* p = buffer.PushArr( len ) - 1;
1857  vsnprintf( p, len+1, format, va );
1858  #endif
1859  }
1860  va_end( va );
1861 }
1862 
1863 
1864 inline
1865 void XMLPrinter::PrintSpace( int depth )
1866 {
1867  for( int i=0; i<depth; ++i ) {
1868  Print( " " );
1869  }
1870 }
1871 
1872 
1873 inline
1874 void XMLPrinter::PrintString( const char* p, bool restricted )
1875 {
1876  // Look for runs of bytes between entities to print.
1877  const char* q = p;
1878  const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
1879 
1880  if ( processEntities ) {
1881  while ( *q ) {
1882  // Remember, char is sometimes signed. (How many times has that bitten me?)
1883  if ( *q > 0 && *q < ENTITY_RANGE ) {
1884  // Check for entities. If one is found, flush
1885  // the stream up until the entity, write the
1886  // entity, and keep looking.
1887  if ( flag[(unsigned)(*q)] ) {
1888  while ( p < q ) {
1889  Print( "%c", *p );
1890  ++p;
1891  }
1892  for( int i=0; i<NUM_ENTITIES; ++i ) {
1893  if ( entities[i].value == *q ) {
1894  Print( "&%s;", entities[i].pattern );
1895  break;
1896  }
1897  }
1898  ++p;
1899  }
1900  }
1901  ++q;
1902  }
1903  }
1904  // Flush the remaining string. This will be the entire
1905  // string if an entity wasn't found.
1906  if ( !processEntities || (q-p > 0) ) {
1907  Print( "%s", p );
1908  }
1909 }
1910 
1911 
1912 inline
1913 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
1914 {
1915  static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
1916  if ( writeBOM ) {
1917  Print( "%s", bom );
1918  }
1919  if ( writeDec ) {
1920  PushDeclaration( "xml version=\"1.0\"" );
1921  }
1922 }
1923 
1924 
1925 inline
1926 void XMLPrinter::OpenElement( const char* name )
1927 {
1928  if ( elementJustOpened ) {
1929  SealElement();
1930  }
1931  stack.Push( name );
1932 
1933  if ( textDepth < 0 && !firstElement && !compactMode ) {
1934  Print( "\n" );
1935  PrintSpace( depth );
1936  }
1937 
1938  Print( "<%s", name );
1939  elementJustOpened = true;
1940  firstElement = false;
1941  ++depth;
1942 }
1943 
1944 
1945 inline
1946 void XMLPrinter::PushAttribute( const char* name, const char* value )
1947 {
1949  Print( " %s=\"", name );
1950  PrintString( value, false );
1951  Print( "\"" );
1952 }
1953 
1954 
1955 inline
1956 void XMLPrinter::PushAttribute( const char* name, int v )
1957 {
1958  char buf[BUF_SIZE];
1959  XMLUtil::ToStr( v, buf, BUF_SIZE );
1960  PushAttribute( name, buf );
1961 }
1962 
1963 
1964 inline
1965 void XMLPrinter::PushAttribute( const char* name, unsigned v )
1966 {
1967  char buf[BUF_SIZE];
1968  XMLUtil::ToStr( v, buf, BUF_SIZE );
1969  PushAttribute( name, buf );
1970 }
1971 
1972 
1973 inline
1974 void XMLPrinter::PushAttribute( const char* name, bool v )
1975 {
1976  char buf[BUF_SIZE];
1977  XMLUtil::ToStr( v, buf, BUF_SIZE );
1978  PushAttribute( name, buf );
1979 }
1980 
1981 
1982 inline
1983 void XMLPrinter::PushAttribute( const char* name, double v )
1984 {
1985  char buf[BUF_SIZE];
1986  XMLUtil::ToStr( v, buf, BUF_SIZE );
1987  PushAttribute( name, buf );
1988 }
1989 
1990 
1991 inline
1993 {
1994  --depth;
1995  const char* name = stack.Pop();
1996 
1997  if ( elementJustOpened ) {
1998  Print( "/>" );
1999  }
2000  else {
2001  if ( textDepth < 0 && !compactMode) {
2002  Print( "\n" );
2003  PrintSpace( depth );
2004  }
2005  Print( "</%s>", name );
2006  }
2007 
2008  if ( textDepth == depth )
2009  textDepth = -1;
2010  if ( depth == 0 && !compactMode)
2011  Print( "\n" );
2012  elementJustOpened = false;
2013 }
2014 
2015 
2016 inline
2018 {
2019  elementJustOpened = false;
2020  Print( ">" );
2021 }
2022 
2023 
2024 inline
2025 void XMLPrinter::PushText( const char* text, bool cdata )
2026 {
2027  textDepth = depth-1;
2028 
2029  if ( elementJustOpened ) {
2030  SealElement();
2031  }
2032  if ( cdata ) {
2033  Print( "<![CDATA[" );
2034  Print( "%s", text );
2035  Print( "]]>" );
2036  }
2037  else {
2038  PrintString( text, true );
2039  }
2040 }
2041 
2042 
2043 inline
2044 void XMLPrinter::PushText( int value )
2045 {
2046  char buf[BUF_SIZE];
2047  XMLUtil::ToStr( value, buf, BUF_SIZE );
2048  PushText( buf, false );
2049 }
2050 
2051 
2052 inline
2053 void XMLPrinter::PushText( unsigned value )
2054 {
2055  char buf[BUF_SIZE];
2056  XMLUtil::ToStr( value, buf, BUF_SIZE );
2057  PushText( buf, false );
2058 }
2059 
2060 
2061 inline
2062 void XMLPrinter::PushText( bool value )
2063 {
2064  char buf[BUF_SIZE];
2065  XMLUtil::ToStr( value, buf, BUF_SIZE );
2066  PushText( buf, false );
2067 }
2068 
2069 
2070 inline
2071 void XMLPrinter::PushText( float value )
2072 {
2073  char buf[BUF_SIZE];
2074  XMLUtil::ToStr( value, buf, BUF_SIZE );
2075  PushText( buf, false );
2076 }
2077 
2078 
2079 inline
2080 void XMLPrinter::PushText( double value )
2081 {
2082  char buf[BUF_SIZE];
2083  XMLUtil::ToStr( value, buf, BUF_SIZE );
2084  PushText( buf, false );
2085 }
2086 
2087 
2088 inline
2089 void XMLPrinter::PushComment( const char* comment )
2090 {
2091  if ( elementJustOpened ) {
2092  SealElement();
2093  }
2094  if ( textDepth < 0 && !firstElement && !compactMode) {
2095  Print( "\n" );
2096  PrintSpace( depth );
2097  }
2098  firstElement = false;
2099  Print( "<!--%s-->", comment );
2100 }
2101 
2102 
2103 inline
2104 void XMLPrinter::PushDeclaration( const char* value )
2105 {
2106  if ( elementJustOpened ) {
2107  SealElement();
2108  }
2109  if ( textDepth < 0 && !firstElement && !compactMode) {
2110  Print( "\n" );
2111  PrintSpace( depth );
2112  }
2113  firstElement = false;
2114  Print( "<?%s?>", value );
2115 }
2116 
2117 
2118 inline
2119 void XMLPrinter::PushUnknown( const char* value )
2120 {
2121  if ( elementJustOpened ) {
2122  SealElement();
2123  }
2124  if ( textDepth < 0 && !firstElement && !compactMode) {
2125  Print( "\n" );
2126  PrintSpace( depth );
2127  }
2128  firstElement = false;
2129  Print( "<!%s>", value );
2130 }
2131 
2132 
2133 inline
2135 {
2137  if ( doc.HasBOM() ) {
2138  PushHeader( true, false );
2139  }
2140  return true;
2141 }
2142 
2143 
2144 inline
2145 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2146 {
2147  OpenElement( element.Name() );
2148  while ( attribute ) {
2149  PushAttribute( attribute->Name(), attribute->Value() );
2150  attribute = attribute->Next();
2151  }
2152  return true;
2153 }
2154 
2155 
2156 inline
2158 {
2159  CloseElement();
2160  return true;
2161 }
2162 
2163 
2164 inline
2165 bool XMLPrinter::Visit( const XMLText& text )
2166 {
2167  PushText( text.Value(), text.CData() );
2168  return true;
2169 }
2170 
2171 
2172 inline
2173 bool XMLPrinter::Visit( const XMLComment& comment )
2174 {
2175  PushComment( comment.Value() );
2176  return true;
2177 }
2178 
2179 inline
2180 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2181 {
2182  PushDeclaration( declaration.Value() );
2183  return true;
2184 }
2185 
2186 
2187 inline
2188 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2189 {
2190  PushUnknown( unknown.Value() );
2191  return true;
2192 }
void PushComment(const char *comment)
Add a comment.
const char * Attribute(const char *name, const char *value=0) const
#define DELETE_NODE(node)
Definition: tinyxml2_imp.h:56
#define TIXMLASSERT(x)
Definition: tinyxml2.h:68
XMLNode * InsertFirstChild(XMLNode *addThis)
Definition: tinyxml2_imp.h:693
virtual bool Accept(XMLVisitor *visitor) const
static bool ToFloat(const char *str, float *value)
Definition: tinyxml2_imp.h:486
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2_imp.h:970
XMLDeclaration(XMLDocument *doc)
Definition: tinyxml2_imp.h:986
int QueryUnsignedValue(unsigned int *value) const
See QueryIntAttribute.
int QueryBoolValue(bool *value) const
See QueryIntAttribute.
void SetName(const char *str, bool staticMem=false)
Set the name of the element.
Definition: tinyxml2.h:863
const XMLElement * PreviousSiblingElement(const char *value=0) const
Get the previous (left) sibling element of this node, with an opitionally supplied name...
Definition: tinyxml2_imp.h:784
void Unlink(XMLNode *child)
Definition: tinyxml2_imp.h:642
DynArray< char, 20 > buffer
Definition: tinyxml2.h:1498
MemPoolT< sizeof(XMLText) > textPool
Definition: tinyxml2.h:1226
XMLNode * firstChild
Definition: tinyxml2.h:611
const char * Value() const
The value of the attribute.
Definition: tinyxml2.h:789
const char * GetStr()
Definition: tinyxml2_imp.h:195
const XMLAttribute * Next() const
The next attribute in the list.
Definition: tinyxml2.h:790
static void ConvertUTF32ToUTF8(unsigned long input, char *output, int *length)
Definition: tinyxml2_imp.h:303
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2_imp.h:946
void DeleteChild(XMLNode *node)
Definition: tinyxml2_imp.h:661
void Set(char *_start, char *_end, int _flags)
Definition: tinyxml2.h:138
static bool StringEqual(const char *p, const char *q, int nChar=INT_MAX)
Definition: tinyxml2.h:384
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2_imp.h:999
XMLNode * parent
Definition: tinyxml2.h:608
XMLElement(XMLDocument *doc)
MemPoolT< sizeof(XMLElement) > elementPool
Definition: tinyxml2.h:1224
virtual XMLText * ToText()
Safely cast to Text, or null.
Definition: tinyxml2.h:460
#define DELETE_ATTRIBUTE(attrib)
Definition: tinyxml2_imp.h:63
char * ParseText(char *in, const char *endTag, int strFlags)
Definition: tinyxml2_imp.h:120
T * PushArr(int count)
Definition: tinyxml2.h:195
const char * errorStr1
Definition: tinyxml2.h:1220
static void ToStr(int v, char *buffer, int bufferSize)
Definition: tinyxml2_imp.h:415
XMLComment * NewComment(const char *comment)
bool CData() const
Returns true if this is a CDATA text element.
Definition: tinyxml2.h:648
const XMLElement * LastChildElement(const char *value=0) const
Definition: tinyxml2_imp.h:755
static bool IsWhiteSpace(char p)
Definition: tinyxml2.h:382
virtual XMLUnknown * ToUnknown()
Safely cast to an Unknown, or null.
Definition: tinyxml2.h:464
char * ParseDeep(char *p, StrPair *endTag)
XMLAttribute * rootAttribute
Definition: tinyxml2.h:1045
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2_imp.h:905
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2_imp.h:582
int QueryFloatText(float *_value) const
See QueryIntText()
int Parse(const char *xml, size_t nBytes=(size_t)(-1))
const char * Name() const
Get the name of an element (which is the Value() of the node.)
Definition: tinyxml2.h:861
int LoadFile(const char *filename)
void PushUnknown(const char *value)
XMLElement * NewElement(const char *name)
bool Error() const
Return true if there was an error parsing the document.
Definition: tinyxml2.h:1195
const XMLNode * NextSibling() const
Get the next (right) sibling node of this node.
Definition: tinyxml2.h:523
static bool ToDouble(const char *str, double *value)
Definition: tinyxml2_imp.h:495
#define TIXML_SNPRINTF
Definition: tinyxml2.h:92
XMLNode * InsertAfterChild(XMLNode *afterThis, XMLNode *addThis)
Definition: tinyxml2_imp.h:718
const char * pattern
Definition: tinyxml2_imp.h:72
int QueryIntValue(int *value) const
void DeleteAttribute(const char *name)
XMLDocument * document
Definition: tinyxml2.h:607
virtual bool ShallowEqual(const XMLNode *compare) const
char * ParseName(char *in)
Definition: tinyxml2_imp.h:141
virtual XMLNode * ShallowClone(XMLDocument *document) const
Definition: tinyxml2_imp.h:959
virtual bool Accept(XMLVisitor *visitor) const
void Print(const char *format,...)
char * ParseDeep(char *, StrPair *endTag)
Definition: tinyxml2_imp.h:877
virtual bool VisitEnter(const XMLDocument &)
Visit a document.
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:459
const XMLElement * NextSiblingElement(const char *value=0) const
Get the next (right) sibling element of this node, with an opitionally supplied name.
Definition: tinyxml2_imp.h:770
static int IsAlpha(unsigned char anyByte)
Definition: tinyxml2.h:399
const XMLAttribute * FirstAttribute() const
Return the first attribute in the list.
Definition: tinyxml2.h:949
XMLDeclaration * NewDeclaration(const char *text=0)
virtual XMLDeclaration * ToDeclaration()
Safely cast to a Declaration, or null.
Definition: tinyxml2.h:463
void SetName(const char *name)
virtual bool Visit(const XMLDeclaration &)
Visit a declaration.
Definition: tinyxml2.h:362
char * ParseAttributes(char *p)
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2_imp.h:977
XMLAttribute * FindOrCreateAttribute(const char *name)
int QueryIntText(int *_value) const
virtual bool ShallowEqual(const XMLNode *compare) const
void PushAttribute(const char *name, const char *value)
If streaming, add an attribute to an open element.
void PushDeclaration(const char *value)
char * ParseDeep(char *, StrPair *endTag)
XMLPrinter(FILE *file=0, bool compact=false)
static const char * GetCharacterRef(const char *p, char *value, int *length)
Definition: tinyxml2_imp.h:345
virtual bool Accept(XMLVisitor *visitor) const
a int
Definition: eigen_utils.h:67
XMLNode * InsertEndChild(XMLNode *addThis)
Definition: tinyxml2_imp.h:669
static const char * SkipWhiteSpace(const char *p)
Definition: tinyxml2.h:380
void SetError(int error, const char *str1, const char *str2)
void SetCData(bool _isCData)
Declare whether this should be CDATA or standard text.
Definition: tinyxml2.h:646
bool Empty() const
Definition: tinyxml2.h:143
void SetStr(const char *str, int flags=0)
Definition: tinyxml2_imp.h:108
void Print(XMLPrinter *streamer=0)
const XMLAttribute * FindAttribute(const char *name) const
Query a specific attribute in the list.
const XMLElement * FirstChildElement(const char *value=0) const
Definition: tinyxml2_imp.h:740
virtual XMLNode * ShallowClone(XMLDocument *document) const
void SetInternedStr(const char *str)
Definition: tinyxml2.h:145
void SetValue(const char *val, bool staticMem=false)
Definition: tinyxml2_imp.h:619
bool restrictedEntityFlag[ENTITY_RANGE]
Definition: tinyxml2.h:1495
static int IsAlphaNum(unsigned char anyByte)
Definition: tinyxml2.h:398
XMLNode * next
Definition: tinyxml2.h:615
MemPoolT< sizeof(XMLComment) > commentPool
Definition: tinyxml2.h:1227
XMLComment(XMLDocument *doc)
Definition: tinyxml2_imp.h:933
int QueryDoubleText(double *_value) const
See QueryIntText()
virtual bool Visit(const XMLText &text)
Visit a text node.
XMLNode * lastChild
Definition: tinyxml2.h:612
virtual char * ParseDeep(char *, StrPair *)
Definition: tinyxml2_imp.h:798
virtual XMLElement * ToElement()
Safely cast to an Element, or null.
Definition: tinyxml2.h:865
int ClosingType() const
Definition: tinyxml2.h:1025
bool HasBOM() const
Definition: tinyxml2.h:1121
void PushHeader(bool writeBOM, bool writeDeclaration)
virtual bool VisitExit(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:1454
const char * Value() const
Definition: tinyxml2.h:482
virtual XMLNode * ShallowClone(XMLDocument *document) const
void Push(T t)
Definition: tinyxml2.h:189
int SaveFile(const char *filename, bool compact=false)
virtual ~XMLNode()
Definition: tinyxml2_imp.h:609
XMLUnknown(XMLDocument *doc)
void OpenElement(const char *name)
const char * Name() const
The name of the attribute.
Definition: tinyxml2.h:788
char value
Definition: tinyxml2_imp.h:74
XMLNode(XMLDocument *)
Definition: tinyxml2_imp.h:599
char * Identify(char *p, XMLNode **node)
Definition: tinyxml2_imp.h:505
XMLText * NewText(const char *text)
char * ParseDeep(char *p, bool processEntities)
void SetAttribute(const char *name, const char *_value)
Sets the named attribute to value.
Definition: tinyxml2.h:933
static bool ToUnsigned(const char *str, unsigned *value)
Definition: tinyxml2_imp.h:458
static bool ToBool(const char *str, bool *value)
Definition: tinyxml2_imp.h:466
static const char * ReadBOM(const char *p, bool *hasBOM)
Definition: tinyxml2_imp.h:286
int length
Definition: tinyxml2_imp.h:73
DynArray< const char *, 10 > stack
Definition: tinyxml2.h:1497
MemPool * memPool
Definition: tinyxml2.h:618
#define TIXML_SSCANF
Definition: tinyxml2.h:93
MemPoolT< sizeof(XMLAttribute) > attributePool
Definition: tinyxml2.h:1225
const XMLNode * FirstChild() const
Get the first child node, or null if none exists.
Definition: tinyxml2.h:496
XMLUnknown * NewUnknown(const char *text)
void CloseElement()
If streaming, close the Element.
const char * errorStr2
Definition: tinyxml2.h:1221
const char * GetText() const
virtual XMLNode * ShallowClone(XMLDocument *document) const
int QueryFloatValue(float *value) const
See QueryIntAttribute.
virtual bool ShallowEqual(const XMLNode *compare) const
virtual bool VisitEnter(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:352
int QueryDoubleValue(double *value) const
See QueryIntAttribute.
virtual bool Accept(XMLVisitor *visitor) const
Definition: tinyxml2_imp.h:924
friend class XMLElement
Definition: tinyxml2.h:1062
int QueryBoolText(bool *_value) const
See QueryIntText()
XMLAttribute * next
Definition: tinyxml2.h:846
XMLDocument(bool processEntities=true, Whitespace=PRESERVE_WHITESPACE)
constructor
int QueryUnsignedText(unsigned *_value) const
See QueryIntText()
void PrintString(const char *, bool restrictedEntitySet)
void PrintError() const
If there is an error, print it to stdout.
void CollapseWhitespace()
Definition: tinyxml2_imp.h:168
static bool ToInt(const char *str, int *value)
Definition: tinyxml2_imp.h:450
Whitespace WhitespaceMode() const
Definition: tinyxml2.h:1116
void PrintSpace(int depth)
XMLNode * prev
Definition: tinyxml2.h:614
virtual bool ShallowEqual(const XMLNode *compare) const
Definition: tinyxml2_imp.h:917
virtual bool VisitExit(const XMLDocument &)
Visit a document.
Definition: tinyxml2.h:354
bool entityFlag[ENTITY_RANGE]
Definition: tinyxml2.h:1494
bool ProcessEntities() const
Definition: tinyxml2.h:1115
void SetAttribute(const char *value)
Set the attribute to a string value.
void PushText(const char *text, bool cdata=false)
Add a text node.
virtual XMLComment * ToComment()
Safely cast to a Comment, or null.
Definition: tinyxml2.h:461

Generated on Thu Jul 7 2016 11:09:45 for antioch-0.4.0 by  doxygen 1.8.8