Otclient  14/8/2020
tinyxmlparser.cpp
Go to the documentation of this file.
1 /*
2 www.sourceforge.net/projects/tinyxml
3 Original code by Lee Thomason (www.grinninglizard.com)
4 
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any
7 damages arising from the use of this software.
8 
9 Permission is granted to anyone to use this software for any
10 purpose, including commercial applications, and to alter it and
11 redistribute it freely, subject to the following restrictions:
12 
13 1. The origin of this software must not be misrepresented; you must
14 not claim that you wrote the original software. If you use this
15 software in a product, an acknowledgment in the product documentation
16 would be appreciated but is not required.
17 
18 2. Altered source versions must be plainly marked as such, and
19 must not be misrepresented as being the original software.
20 
21 3. This notice may not be removed or altered from any source
22 distribution.
23 */
24 
25 #include <ctype.h>
26 #include <stddef.h>
27 
28 #include "tinyxml.h"
29 
30 //#define DEBUG_PARSER
31 #if defined( DEBUG_PARSER )
32 # if defined( DEBUG ) && defined( _MSC_VER )
33 # include <windows.h>
34 # define TIXML_LOG OutputDebugString
35 # else
36 # define TIXML_LOG printf
37 # endif
38 #endif
39 
40 // Note tha "PutString" hardcodes the same list. This
41 // is less flexible than it appears. Changing the entries
42 // or order will break putstring.
43 TiXmlBase::Entity TiXmlBase::entity[ TiXmlBase::NUM_ENTITY ] =
44 {
45  { "&amp;", 5, '&' },
46  { "&lt;", 4, '<' },
47  { "&gt;", 4, '>' },
48  { "&quot;", 6, '\"' },
49  { "&apos;", 6, '\'' }
50 };
51 
52 // Bunch of unicode info at:
53 // http://www.unicode.org/faq/utf_bom.html
54 // Including the basic of this table, which determines the #bytes in the
55 // sequence from the lead byte. 1 placed for invalid sequences --
56 // although the result will be junk, pass it through as much as possible.
57 // Beware of the non-characters in UTF-8:
58 // ef bb bf (Microsoft "lead bytes")
59 // ef bf be
60 // ef bf bf
61 
62 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
63 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
64 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
65 
66 const int TiXmlBase::utf8ByteTable[256] =
67 {
68  // 0 1 2 3 4 5 6 7 8 9 a b c d e f
69  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
70  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
71  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20
72  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30
73  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
74  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
75  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
76  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
77  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
78  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
79  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
80  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
81  1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
82  2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
83  3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
84  4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
85 };
86 
87 
88 void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
89 {
90  const unsigned long BYTE_MASK = 0xBF;
91  const unsigned long BYTE_MARK = 0x80;
92  const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
93 
94  if (input < 0x80)
95  *length = 1;
96  else if ( input < 0x800 )
97  *length = 2;
98  else if ( input < 0x10000 )
99  *length = 3;
100  else if ( input < 0x200000 )
101  *length = 4;
102  else
103  { *length = 0; return; } // This code won't covert this correctly anyway.
104 
105  output += *length;
106 
107  // Scary scary fall throughs.
108  switch (*length)
109  {
110  /* FALLTHROUGH */
111  case 4:
112  --output;
113  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
114  input >>= 6;
115  /* FALLTHROUGH */
116  case 3:
117  --output;
118  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
119  input >>= 6;
120  /* FALLTHROUGH */
121  case 2:
122  --output;
123  *output = (char)((input | BYTE_MARK) & BYTE_MASK);
124  input >>= 6;
125  /* FALLTHROUGH */
126  case 1:
127  --output;
128  *output = (char)(input | FIRST_BYTE_MARK[*length]);
129  }
130 }
131 
132 
133 /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
134 {
135  // This will only work for low-ascii, everything else is assumed to be a valid
136  // letter. I'm not sure this is the best approach, but it is quite tricky trying
137  // to figure out alhabetical vs. not across encoding. So take a very
138  // conservative approach.
139 
140 // if ( encoding == TIXML_ENCODING_UTF8 )
141 // {
142  if ( anyByte < 127 )
143  return isalpha( anyByte );
144  else
145  return 1; // What else to do? The unicode set is huge...get the english ones right.
146 // }
147 // else
148 // {
149 // return isalpha( anyByte );
150 // }
151 }
152 
153 
154 /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
155 {
156  // This will only work for low-ascii, everything else is assumed to be a valid
157  // letter. I'm not sure this is the best approach, but it is quite tricky trying
158  // to figure out alhabetical vs. not across encoding. So take a very
159  // conservative approach.
160 
161 // if ( encoding == TIXML_ENCODING_UTF8 )
162 // {
163  if ( anyByte < 127 )
164  return isalnum( anyByte );
165  else
166  return 1; // What else to do? The unicode set is huge...get the english ones right.
167 // }
168 // else
169 // {
170 // return isalnum( anyByte );
171 // }
172 }
173 
174 
176 {
177  friend class TiXmlDocument;
178  public:
179  void Stamp( const char* now, TiXmlEncoding encoding );
180 
181  const TiXmlCursor& Cursor() const { return cursor; }
182 
183  private:
184  // Only used by the document!
185  TiXmlParsingData( const char* start, int _tabsize, int row, int col )
186  {
187  assert( start );
188  stamp = start;
189  tabsize = _tabsize;
190  cursor.row = row;
191  cursor.col = col;
192  }
193 
194  TiXmlCursor cursor;
195  const char* stamp;
196  int tabsize;
197 };
198 
199 
200 void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
201 {
202  assert( now );
203 
204  // Do nothing if the tabsize is 0.
205  if ( tabsize < 1 )
206  {
207  return;
208  }
209 
210  // Get the current row, column.
211  int row = cursor.row;
212  int col = cursor.col;
213  const char* p = stamp;
214  assert( p );
215 
216  while ( p < now )
217  {
218  // Treat p as unsigned, so we have a happy compiler.
219  const unsigned char* pU = (const unsigned char*)p;
220 
221  // Code contributed by Fletcher Dunn: (modified by lee)
222  switch (*pU) {
223  case 0:
224  // We *should* never get here, but in case we do, don't
225  // advance past the terminating null character, ever
226  return;
227 
228  case '\r':
229  // bump down to the next line
230  ++row;
231  col = 0;
232  // Eat the character
233  ++p;
234 
235  // Check for \r\n sequence, and treat this as a single character
236  if (*p == '\n') {
237  ++p;
238  }
239  break;
240 
241  case '\n':
242  // bump down to the next line
243  ++row;
244  col = 0;
245 
246  // Eat the character
247  ++p;
248 
249  // Check for \n\r sequence, and treat this as a single
250  // character. (Yes, this bizarre thing does occur still
251  // on some arcane platforms...)
252  if (*p == '\r') {
253  ++p;
254  }
255  break;
256 
257  case '\t':
258  // Eat the character
259  ++p;
260 
261  // Skip to next tab stop
262  col = (col / tabsize + 1) * tabsize;
263  break;
264 
265  case TIXML_UTF_LEAD_0:
266  if ( encoding == TIXML_ENCODING_UTF8 )
267  {
268  if ( *(p+1) && *(p+2) )
269  {
270  // In these cases, don't advance the column. These are
271  // 0-width spaces.
272  if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
273  p += 3;
274  else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
275  p += 3;
276  else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
277  p += 3;
278  else
279  { p +=3; ++col; } // A normal character.
280  }
281  }
282  else
283  {
284  ++p;
285  ++col;
286  }
287  break;
288 
289  default:
290  if ( encoding == TIXML_ENCODING_UTF8 )
291  {
292  // Eat the 1 to 4 byte utf8 character.
293  int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
294  if ( step == 0 )
295  step = 1; // Error case from bad encoding, but handle gracefully.
296  p += step;
297 
298  // Just advance one column, of course.
299  ++col;
300  }
301  else
302  {
303  ++p;
304  ++col;
305  }
306  break;
307  }
308  }
309  cursor.row = row;
310  cursor.col = col;
311  assert( cursor.row >= -1 );
312  assert( cursor.col >= -1 );
313  stamp = p;
314  assert( stamp );
315 }
316 
317 
318 const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
319 {
320  if ( !p || !*p )
321  {
322  return 0;
323  }
324  if ( encoding == TIXML_ENCODING_UTF8 )
325  {
326  while ( *p )
327  {
328  const unsigned char* pU = (const unsigned char*)p;
329 
330  // Skip the stupid Microsoft UTF-8 Byte order marks
331  if ( *(pU+0)==TIXML_UTF_LEAD_0
332  && *(pU+1)==TIXML_UTF_LEAD_1
333  && *(pU+2)==TIXML_UTF_LEAD_2 )
334  {
335  p += 3;
336  continue;
337  }
338  else if(*(pU+0)==TIXML_UTF_LEAD_0
339  && *(pU+1)==0xbfU
340  && *(pU+2)==0xbeU )
341  {
342  p += 3;
343  continue;
344  }
345  else if(*(pU+0)==TIXML_UTF_LEAD_0
346  && *(pU+1)==0xbfU
347  && *(pU+2)==0xbfU )
348  {
349  p += 3;
350  continue;
351  }
352 
353  if ( IsWhiteSpace( *p ) ) // Still using old rules for white space.
354  ++p;
355  else
356  break;
357  }
358  }
359  else
360  {
361  while ( *p && IsWhiteSpace( *p ) )
362  ++p;
363  }
364 
365  return p;
366 }
367 
368 #ifdef TIXML_USE_STL
369 /*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
370 {
371  for( ;; )
372  {
373  if ( !in->good() ) return false;
374 
375  int c = in->peek();
376  // At this scope, we can't get to a document. So fail silently.
377  if ( !IsWhiteSpace( c ) || c <= 0 )
378  return true;
379 
380  *tag += (char) in->get();
381  }
382 }
383 
384 /*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
385 {
386  //assert( character > 0 && character < 128 ); // else it won't work in utf-8
387  while ( in->good() )
388  {
389  int c = in->peek();
390  if ( c == character )
391  return true;
392  if ( c <= 0 ) // Silent failure: can't get document at this scope
393  return false;
394 
395  in->get();
396  *tag += (char) c;
397  }
398  return false;
399 }
400 #endif
401 
402 // One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
403 // "assign" optimization removes over 10% of the execution time.
404 //
405 const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
406 {
407  // Oddly, not supported on some comilers,
408  //name->clear();
409  // So use this:
410  *name = "";
411  assert( p );
412 
413  // Names start with letters or underscores.
414  // Of course, in unicode, tinyxml has no idea what a letter *is*. The
415  // algorithm is generous.
416  //
417  // After that, they can be letters, underscores, numbers,
418  // hyphens, or colons. (Colons are valid ony for namespaces,
419  // but tinyxml can't tell namespaces from names.)
420  if ( p && *p
421  && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
422  {
423  const char* start = p;
424  while( p && *p
425  && ( IsAlphaNum( (unsigned char ) *p, encoding )
426  || *p == '_'
427  || *p == '-'
428  || *p == '.'
429  || *p == ':' ) )
430  {
431  //(*name) += *p; // expensive
432  ++p;
433  }
434  if ( p-start > 0 ) {
435  name->assign( start, p-start );
436  }
437  return p;
438  }
439  return 0;
440 }
441 
442 const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
443 {
444  // Presume an entity, and pull it out.
445  TIXML_STRING ent;
446  int i;
447  *length = 0;
448 
449  if ( *(p+1) && *(p+1) == '#' && *(p+2) )
450  {
451  unsigned long ucs = 0;
452  ptrdiff_t delta = 0;
453  unsigned mult = 1;
454 
455  if ( *(p+2) == 'x' )
456  {
457  // Hexadecimal.
458  if ( !*(p+3) ) return 0;
459 
460  const char* q = p+3;
461  q = strchr( q, ';' );
462 
463  if ( !q || !*q ) return 0;
464 
465  delta = q-p;
466  --q;
467 
468  while ( *q != 'x' )
469  {
470  if ( *q >= '0' && *q <= '9' )
471  ucs += mult * (*q - '0');
472  else if ( *q >= 'a' && *q <= 'f' )
473  ucs += mult * (*q - 'a' + 10);
474  else if ( *q >= 'A' && *q <= 'F' )
475  ucs += mult * (*q - 'A' + 10 );
476  else
477  return 0;
478  mult *= 16;
479  --q;
480  }
481  }
482  else
483  {
484  // Decimal.
485  if ( !*(p+2) ) return 0;
486 
487  const char* q = p+2;
488  q = strchr( q, ';' );
489 
490  if ( !q || !*q ) return 0;
491 
492  delta = q-p;
493  --q;
494 
495  while ( *q != '#' )
496  {
497  if ( *q >= '0' && *q <= '9' )
498  ucs += mult * (*q - '0');
499  else
500  return 0;
501  mult *= 10;
502  --q;
503  }
504  }
505  if ( encoding == TIXML_ENCODING_UTF8 )
506  {
507  // convert the UCS to UTF-8
508  ConvertUTF32ToUTF8( ucs, value, length );
509  }
510  else
511  {
512  *value = (char)ucs;
513  *length = 1;
514  }
515  return p + delta + 1;
516  }
517 
518  // Now try to match it.
519  for( i=0; i<NUM_ENTITY; ++i )
520  {
521  if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
522  {
523  assert( strlen( entity[i].str ) == entity[i].strLength );
524  *value = entity[i].chr;
525  *length = 1;
526  return ( p + entity[i].strLength );
527  }
528  }
529 
530  // So it wasn't an entity, its unrecognized, or something like that.
531  *value = *p; // Don't put back the last one, since we return it!
532  //*length = 1; // Leave unrecognized entities - this doesn't really work.
533  // Just writes strange XML.
534  return p+1;
535 }
536 
537 
538 bool TiXmlBase::StringEqual( const char* p,
539  const char* tag,
540  bool ignoreCase,
541  TiXmlEncoding encoding )
542 {
543  assert( p );
544  assert( tag );
545  if ( !p || !*p )
546  {
547  assert( 0 );
548  return false;
549  }
550 
551  const char* q = p;
552 
553  if ( ignoreCase )
554  {
555  while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
556  {
557  ++q;
558  ++tag;
559  }
560 
561  if ( *tag == 0 )
562  return true;
563  }
564  else
565  {
566  while ( *q && *tag && *q == *tag )
567  {
568  ++q;
569  ++tag;
570  }
571 
572  if ( *tag == 0 ) // Have we found the end of the tag, and everything equal?
573  return true;
574  }
575  return false;
576 }
577 
578 const char* TiXmlBase::ReadText( const char* p,
579  TIXML_STRING * text,
580  bool trimWhiteSpace,
581  const char* endTag,
582  bool caseInsensitive,
583  TiXmlEncoding encoding )
584 {
585  *text = "";
586  if ( !trimWhiteSpace // certain tags always keep whitespace
587  || !condenseWhiteSpace ) // if true, whitespace is always kept
588  {
589  // Keep all the white space.
590  while ( p && *p
591  && !StringEqual( p, endTag, caseInsensitive, encoding )
592  )
593  {
594  int len;
595  char cArr[4] = { 0, 0, 0, 0 };
596  p = GetChar( p, cArr, &len, encoding );
597  text->append( cArr, len );
598  }
599  }
600  else
601  {
602  bool whitespace = false;
603 
604  // Remove leading white space:
605  p = SkipWhiteSpace( p, encoding );
606  while ( p && *p
607  && !StringEqual( p, endTag, caseInsensitive, encoding ) )
608  {
609  if ( *p == '\r' || *p == '\n' )
610  {
611  whitespace = true;
612  ++p;
613  }
614  else if ( IsWhiteSpace( *p ) )
615  {
616  whitespace = true;
617  ++p;
618  }
619  else
620  {
621  // If we've found whitespace, add it before the
622  // new character. Any whitespace just becomes a space.
623  if ( whitespace )
624  {
625  (*text) += ' ';
626  whitespace = false;
627  }
628  int len;
629  char cArr[4] = { 0, 0, 0, 0 };
630  p = GetChar( p, cArr, &len, encoding );
631  if ( len == 1 )
632  (*text) += cArr[0]; // more efficient
633  else
634  text->append( cArr, len );
635  }
636  }
637  }
638  if ( p && *p )
639  p += strlen( endTag );
640  return ( p && *p ) ? p : 0;
641 }
642 
643 #ifdef TIXML_USE_STL
644 
645 void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
646 {
647  // The basic issue with a document is that we don't know what we're
648  // streaming. Read something presumed to be a tag (and hope), then
649  // identify it, and call the appropriate stream method on the tag.
650  //
651  // This "pre-streaming" will never read the closing ">" so the
652  // sub-tag can orient itself.
653 
654  if ( !StreamTo( in, '<', tag ) )
655  {
657  return;
658  }
659 
660  while ( in->good() )
661  {
662  int tagIndex = (int) tag->length();
663  while ( in->good() && in->peek() != '>' )
664  {
665  int c = in->get();
666  if ( c <= 0 )
667  {
669  break;
670  }
671  (*tag) += (char) c;
672  }
673 
674  if ( in->good() )
675  {
676  // We now have something we presume to be a node of
677  // some sort. Identify it, and call the node to
678  // continue streaming.
679  TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
680 
681  if ( node )
682  {
683  node->StreamIn( in, tag );
684  bool isElement = node->ToElement() != 0;
685  delete node;
686  node = 0;
687 
688  // If this is the root element, we're done. Parsing will be
689  // done by the >> operator.
690  if ( isElement )
691  {
692  return;
693  }
694  }
695  else
696  {
698  return;
699  }
700  }
701  }
702  // We should have returned sooner.
704 }
705 
706 #endif
707 
708 const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
709 {
710  ClearError();
711 
712  // Parse away, at the document level. Since a document
713  // contains nothing but other tags, most of what happens
714  // here is skipping white space.
715  if ( !p || !*p )
716  {
718  return 0;
719  }
720 
721  // Note that, for a document, this needs to come
722  // before the while space skip, so that parsing
723  // starts from the pointer we are given.
724  location.Clear();
725  if ( prevData )
726  {
727  location.row = prevData->cursor.row;
728  location.col = prevData->cursor.col;
729  }
730  else
731  {
732  location.row = 0;
733  location.col = 0;
734  }
736  location = data.Cursor();
737 
738  if ( encoding == TIXML_ENCODING_UNKNOWN )
739  {
740  // Check for the Microsoft UTF-8 lead bytes.
741  const unsigned char* pU = (const unsigned char*)p;
742  if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
743  && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
744  && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
745  {
746  encoding = TIXML_ENCODING_UTF8;
747  useMicrosoftBOM = true;
748  }
749  }
750 
751  p = SkipWhiteSpace( p, encoding );
752  if ( !p )
753  {
755  return 0;
756  }
757 
758  while ( p && *p )
759  {
760  TiXmlNode* node = Identify( p, encoding );
761  if ( node )
762  {
763  p = node->Parse( p, &data, encoding );
764  LinkEndChild( node );
765  }
766  else
767  {
768  break;
769  }
770 
771  // Did we get encoding info?
772  if ( encoding == TIXML_ENCODING_UNKNOWN
773  && node->ToDeclaration() )
774  {
775  TiXmlDeclaration* dec = node->ToDeclaration();
776  const char* enc = dec->Encoding();
777  assert( enc );
778 
779  if ( *enc == 0 )
780  encoding = TIXML_ENCODING_UTF8;
781  else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
782  encoding = TIXML_ENCODING_UTF8;
783  else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
784  encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
785  else
786  encoding = TIXML_ENCODING_LEGACY;
787  }
788 
789  p = SkipWhiteSpace( p, encoding );
790  }
791 
792  // Was this empty?
793  if ( !firstChild ) {
794  SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
795  return 0;
796  }
797 
798  // All is well.
799  return p;
800 }
801 
802 void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
803 {
804  // The first error in a chain is more accurate - don't set again!
805  if ( error )
806  return;
807 
808  assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
809  error = true;
810  errorId = err;
811  errorDesc = errorString[ errorId ];
812 
813  errorLocation.Clear();
814  if ( pError && data )
815  {
816  data->Stamp( pError, encoding );
817  errorLocation = data->Cursor();
818  }
819 }
820 
821 
822 TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
823 {
824  TiXmlNode* returnNode = 0;
825 
826  p = SkipWhiteSpace( p, encoding );
827  if( !p || !*p || *p != '<' )
828  {
829  return 0;
830  }
831 
832  p = SkipWhiteSpace( p, encoding );
833 
834  if ( !p || !*p )
835  {
836  return 0;
837  }
838 
839  // What is this thing?
840  // - Elements start with a letter or underscore, but xml is reserved.
841  // - Comments: <!--
842  // - Decleration: <?xml
843  // - Everthing else is unknown to tinyxml.
844  //
845 
846  const char* xmlHeader = { "<?xml" };
847  const char* commentHeader = { "<!--" };
848  const char* dtdHeader = { "<!" };
849  const char* cdataHeader = { "<![CDATA[" };
850 
851  if ( StringEqual( p, xmlHeader, true, encoding ) )
852  {
853  #ifdef DEBUG_PARSER
854  TIXML_LOG( "XML parsing Declaration\n" );
855  #endif
856  returnNode = new TiXmlDeclaration();
857  }
858  else if ( StringEqual( p, commentHeader, false, encoding ) )
859  {
860  #ifdef DEBUG_PARSER
861  TIXML_LOG( "XML parsing Comment\n" );
862  #endif
863  returnNode = new TiXmlComment();
864  }
865  else if ( StringEqual( p, cdataHeader, false, encoding ) )
866  {
867  #ifdef DEBUG_PARSER
868  TIXML_LOG( "XML parsing CDATA\n" );
869  #endif
870  TiXmlText* text = new TiXmlText( "" );
871  text->SetCDATA( true );
872  returnNode = text;
873  }
874  else if ( StringEqual( p, dtdHeader, false, encoding ) )
875  {
876  #ifdef DEBUG_PARSER
877  TIXML_LOG( "XML parsing Unknown(1)\n" );
878  #endif
879  returnNode = new TiXmlUnknown();
880  }
881  else if ( IsAlpha( *(p+1), encoding )
882  || *(p+1) == '_' )
883  {
884  #ifdef DEBUG_PARSER
885  TIXML_LOG( "XML parsing Element\n" );
886  #endif
887  returnNode = new TiXmlElement( "" );
888  }
889  else
890  {
891  #ifdef DEBUG_PARSER
892  TIXML_LOG( "XML parsing Unknown(2)\n" );
893  #endif
894  returnNode = new TiXmlUnknown();
895  }
896 
897  if ( returnNode )
898  {
899  // Set the parent, so it can report errors
900  returnNode->parent = this;
901  }
902  return returnNode;
903 }
904 
905 #ifdef TIXML_USE_STL
906 
907 void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
908 {
909  // We're called with some amount of pre-parsing. That is, some of "this"
910  // element is in "tag". Go ahead and stream to the closing ">"
911  while( in->good() )
912  {
913  int c = in->get();
914  if ( c <= 0 )
915  {
916  TiXmlDocument* document = GetDocument();
917  if ( document )
919  return;
920  }
921  (*tag) += (char) c ;
922 
923  if ( c == '>' )
924  break;
925  }
926 
927  if ( tag->length() < 3 ) return;
928 
929  // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
930  // If not, identify and stream.
931 
932  if ( tag->at( tag->length() - 1 ) == '>'
933  && tag->at( tag->length() - 2 ) == '/' )
934  {
935  // All good!
936  return;
937  }
938  else if ( tag->at( tag->length() - 1 ) == '>' )
939  {
940  // There is more. Could be:
941  // text
942  // cdata text (which looks like another node)
943  // closing tag
944  // another node.
945  for ( ;; )
946  {
947  StreamWhiteSpace( in, tag );
948 
949  // Do we have text?
950  if ( in->good() && in->peek() != '<' )
951  {
952  // Yep, text.
953  TiXmlText text( "" );
954  text.StreamIn( in, tag );
955 
956  // What follows text is a closing tag or another node.
957  // Go around again and figure it out.
958  continue;
959  }
960 
961  // We now have either a closing tag...or another node.
962  // We should be at a "<", regardless.
963  if ( !in->good() ) return;
964  assert( in->peek() == '<' );
965  int tagIndex = (int) tag->length();
966 
967  bool closingTag = false;
968  bool firstCharFound = false;
969 
970  for( ;; )
971  {
972  if ( !in->good() )
973  return;
974 
975  int c = in->peek();
976  if ( c <= 0 )
977  {
978  TiXmlDocument* document = GetDocument();
979  if ( document )
981  return;
982  }
983 
984  if ( c == '>' )
985  break;
986 
987  *tag += (char) c;
988  in->get();
989 
990  // Early out if we find the CDATA id.
991  if ( c == '[' && tag->size() >= 9 )
992  {
993  size_t len = tag->size();
994  const char* start = tag->c_str() + len - 9;
995  if ( strcmp( start, "<![CDATA[" ) == 0 ) {
996  assert( !closingTag );
997  break;
998  }
999  }
1000 
1001  if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
1002  {
1003  firstCharFound = true;
1004  if ( c == '/' )
1005  closingTag = true;
1006  }
1007  }
1008  // If it was a closing tag, then read in the closing '>' to clean up the input stream.
1009  // If it was not, the streaming will be done by the tag.
1010  if ( closingTag )
1011  {
1012  if ( !in->good() )
1013  return;
1014 
1015  int c = in->get();
1016  if ( c <= 0 )
1017  {
1018  TiXmlDocument* document = GetDocument();
1019  if ( document )
1021  return;
1022  }
1023  assert( c == '>' );
1024  *tag += (char) c;
1025 
1026  // We are done, once we've found our closing tag.
1027  return;
1028  }
1029  else
1030  {
1031  // If not a closing tag, id it, and stream.
1032  const char* tagloc = tag->c_str() + tagIndex;
1033  TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
1034  if ( !node )
1035  return;
1036  node->StreamIn( in, tag );
1037  delete node;
1038  node = 0;
1039 
1040  // No return: go around from the beginning: text, closing tag, or node.
1041  }
1042  }
1043  }
1044 }
1045 #endif
1046 
1047 const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1048 {
1049  p = SkipWhiteSpace( p, encoding );
1050  TiXmlDocument* document = GetDocument();
1051 
1052  if ( !p || !*p )
1053  {
1054  if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
1055  return 0;
1056  }
1057 
1058  if ( data )
1059  {
1060  data->Stamp( p, encoding );
1061  location = data->Cursor();
1062  }
1063 
1064  if ( *p != '<' )
1065  {
1066  if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
1067  return 0;
1068  }
1069 
1070  p = SkipWhiteSpace( p+1, encoding );
1071 
1072  // Read the name.
1073  const char* pErr = p;
1074 
1075  p = ReadName( p, &value, encoding );
1076  if ( !p || !*p )
1077  {
1078  if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
1079  return 0;
1080  }
1081 
1082  TIXML_STRING endTag ("</");
1083  endTag += value;
1084 
1085  // Check for and read attributes. Also look for an empty
1086  // tag or an end tag.
1087  while ( p && *p )
1088  {
1089  pErr = p;
1090  p = SkipWhiteSpace( p, encoding );
1091  if ( !p || !*p )
1092  {
1093  if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1094  return 0;
1095  }
1096  if ( *p == '/' )
1097  {
1098  ++p;
1099  // Empty tag.
1100  if ( *p != '>' )
1101  {
1102  if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
1103  return 0;
1104  }
1105  return (p+1);
1106  }
1107  else if ( *p == '>' )
1108  {
1109  // Done with attributes (if there were any.)
1110  // Read the value -- which can include other
1111  // elements -- read the end tag, and return.
1112  ++p;
1113  p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens.
1114  if ( !p || !*p ) {
1115  // We were looking for the end tag, but found nothing.
1116  // Fix for [ 1663758 ] Failure to report error on bad XML
1117  if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1118  return 0;
1119  }
1120 
1121  // We should find the end tag now
1122  // note that:
1123  // </foo > and
1124  // </foo>
1125  // are both valid end tags.
1126  if ( StringEqual( p, endTag.c_str(), false, encoding ) )
1127  {
1128  p += endTag.length();
1129  p = SkipWhiteSpace( p, encoding );
1130  if ( p && *p && *p == '>' ) {
1131  ++p;
1132  return p;
1133  }
1134  if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1135  return 0;
1136  }
1137  else
1138  {
1139  if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1140  return 0;
1141  }
1142  }
1143  else
1144  {
1145  // Try to read an attribute:
1146  TiXmlAttribute* attrib = new TiXmlAttribute();
1147  if ( !attrib )
1148  {
1149  return 0;
1150  }
1151 
1152  attrib->SetDocument( document );
1153  pErr = p;
1154  p = attrib->Parse( p, data, encoding );
1155 
1156  if ( !p || !*p )
1157  {
1158  if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
1159  delete attrib;
1160  return 0;
1161  }
1162 
1163  // Handle the strange case of double attributes:
1164  #ifdef TIXML_USE_STL
1165  TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
1166  #else
1167  TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
1168  #endif
1169  if ( node )
1170  {
1171  if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
1172  delete attrib;
1173  return 0;
1174  }
1175 
1176  attributeSet.Add( attrib );
1177  }
1178  }
1179  return p;
1180 }
1181 
1182 
1183 const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1184 {
1185  TiXmlDocument* document = GetDocument();
1186 
1187  // Read in text and elements in any order.
1188  const char* pWithWhiteSpace = p;
1189  p = SkipWhiteSpace( p, encoding );
1190 
1191  while ( p && *p )
1192  {
1193  if ( *p != '<' )
1194  {
1195  // Take what we have, make a text element.
1196  TiXmlText* textNode = new TiXmlText( "" );
1197 
1198  if ( !textNode )
1199  {
1200  return 0;
1201  }
1202 
1204  {
1205  p = textNode->Parse( p, data, encoding );
1206  }
1207  else
1208  {
1209  // Special case: we want to keep the white space
1210  // so that leading spaces aren't removed.
1211  p = textNode->Parse( pWithWhiteSpace, data, encoding );
1212  }
1213 
1214  if ( !textNode->Blank() )
1215  LinkEndChild( textNode );
1216  else
1217  delete textNode;
1218  }
1219  else
1220  {
1221  // We hit a '<'
1222  // Have we hit a new element or an end tag? This could also be
1223  // a TiXmlText in the "CDATA" style.
1224  if ( StringEqual( p, "</", false, encoding ) )
1225  {
1226  return p;
1227  }
1228  else
1229  {
1230  TiXmlNode* node = Identify( p, encoding );
1231  if ( node )
1232  {
1233  p = node->Parse( p, data, encoding );
1234  LinkEndChild( node );
1235  }
1236  else
1237  {
1238  return 0;
1239  }
1240  }
1241  }
1242  pWithWhiteSpace = p;
1243  p = SkipWhiteSpace( p, encoding );
1244  }
1245 
1246  if ( !p )
1247  {
1248  if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
1249  }
1250  return p;
1251 }
1252 
1253 
1254 #ifdef TIXML_USE_STL
1255 void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
1256 {
1257  while ( in->good() )
1258  {
1259  int c = in->get();
1260  if ( c <= 0 )
1261  {
1262  TiXmlDocument* document = GetDocument();
1263  if ( document )
1265  return;
1266  }
1267  (*tag) += (char) c;
1268 
1269  if ( c == '>' )
1270  {
1271  // All is well.
1272  return;
1273  }
1274  }
1275 }
1276 #endif
1277 
1278 
1279 const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1280 {
1281  TiXmlDocument* document = GetDocument();
1282  p = SkipWhiteSpace( p, encoding );
1283 
1284  if ( data )
1285  {
1286  data->Stamp( p, encoding );
1287  location = data->Cursor();
1288  }
1289  if ( !p || !*p || *p != '<' )
1290  {
1291  if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
1292  return 0;
1293  }
1294  ++p;
1295  value = "";
1296 
1297  while ( p && *p && *p != '>' )
1298  {
1299  value += *p;
1300  ++p;
1301  }
1302 
1303  if ( !p )
1304  {
1305  if ( document )
1306  document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
1307  }
1308  if ( p && *p == '>' )
1309  return p+1;
1310  return p;
1311 }
1312 
1313 #ifdef TIXML_USE_STL
1314 void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
1315 {
1316  while ( in->good() )
1317  {
1318  int c = in->get();
1319  if ( c <= 0 )
1320  {
1321  TiXmlDocument* document = GetDocument();
1322  if ( document )
1324  return;
1325  }
1326 
1327  (*tag) += (char) c;
1328 
1329  if ( c == '>'
1330  && tag->at( tag->length() - 2 ) == '-'
1331  && tag->at( tag->length() - 3 ) == '-' )
1332  {
1333  // All is well.
1334  return;
1335  }
1336  }
1337 }
1338 #endif
1339 
1340 
1341 const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1342 {
1343  TiXmlDocument* document = GetDocument();
1344  value = "";
1345 
1346  p = SkipWhiteSpace( p, encoding );
1347 
1348  if ( data )
1349  {
1350  data->Stamp( p, encoding );
1351  location = data->Cursor();
1352  }
1353  const char* startTag = "<!--";
1354  const char* endTag = "-->";
1355 
1356  if ( !StringEqual( p, startTag, false, encoding ) )
1357  {
1358  if ( document )
1359  document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
1360  return 0;
1361  }
1362  p += strlen( startTag );
1363 
1364  // [ 1475201 ] TinyXML parses entities in comments
1365  // Oops - ReadText doesn't work, because we don't want to parse the entities.
1366  // p = ReadText( p, &value, false, endTag, false, encoding );
1367  //
1368  // from the XML spec:
1369  /*
1370  [Definition: Comments may appear anywhere in a document outside other markup; in addition,
1371  they may appear within the document type declaration at places allowed by the grammar.
1372  They are not part of the document's character data; an XML processor MAY, but need not,
1373  make it possible for an application to retrieve the text of comments. For compatibility,
1374  the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity
1375  references MUST NOT be recognized within comments.
1376 
1377  An example of a comment:
1378 
1379  <!-- declarations for <head> & <body> -->
1380  */
1381 
1382  value = "";
1383  // Keep all the white space.
1384  while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
1385  {
1386  value.append( p, 1 );
1387  ++p;
1388  }
1389  if ( p && *p )
1390  p += strlen( endTag );
1391 
1392  return p;
1393 }
1394 
1395 
1396 const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1397 {
1398  p = SkipWhiteSpace( p, encoding );
1399  if ( !p || !*p ) return 0;
1400 
1401  if ( data )
1402  {
1403  data->Stamp( p, encoding );
1404  location = data->Cursor();
1405  }
1406  // Read the name, the '=' and the value.
1407  const char* pErr = p;
1408  p = ReadName( p, &name, encoding );
1409  if ( !p || !*p )
1410  {
1411  if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1412  return 0;
1413  }
1414  p = SkipWhiteSpace( p, encoding );
1415  if ( !p || !*p || *p != '=' )
1416  {
1417  if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1418  return 0;
1419  }
1420 
1421  ++p; // skip '='
1422  p = SkipWhiteSpace( p, encoding );
1423  if ( !p || !*p )
1424  {
1425  if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1426  return 0;
1427  }
1428 
1429  const char* end;
1430  const char SINGLE_QUOTE = '\'';
1431  const char DOUBLE_QUOTE = '\"';
1432 
1433  if ( *p == SINGLE_QUOTE )
1434  {
1435  ++p;
1436  end = "\'"; // single quote in string
1437  p = ReadText( p, &value, false, end, false, encoding );
1438  }
1439  else if ( *p == DOUBLE_QUOTE )
1440  {
1441  ++p;
1442  end = "\""; // double quote in string
1443  p = ReadText( p, &value, false, end, false, encoding );
1444  }
1445  else
1446  {
1447  // All attribute values should be in single or double quotes.
1448  // But this is such a common error that the parser will try
1449  // its best, even without them.
1450  value = "";
1451  while ( p && *p // existence
1452  && !IsWhiteSpace( *p ) // whitespace
1453  && *p != '/' && *p != '>' ) // tag end
1454  {
1455  if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
1456  // [ 1451649 ] Attribute values with trailing quotes not handled correctly
1457  // We did not have an opening quote but seem to have a
1458  // closing one. Give up and throw an error.
1459  if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1460  return 0;
1461  }
1462  value += *p;
1463  ++p;
1464  }
1465  }
1466  return p;
1467 }
1468 
1469 #ifdef TIXML_USE_STL
1470 void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
1471 {
1472  while ( in->good() )
1473  {
1474  int c = in->peek();
1475  if ( !cdata && (c == '<' ) )
1476  {
1477  return;
1478  }
1479  if ( c <= 0 )
1480  {
1481  TiXmlDocument* document = GetDocument();
1482  if ( document )
1484  return;
1485  }
1486 
1487  (*tag) += (char) c;
1488  in->get(); // "commits" the peek made above
1489 
1490  if ( cdata && c == '>' && tag->size() >= 3 ) {
1491  size_t len = tag->size();
1492  if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
1493  // terminator of cdata.
1494  return;
1495  }
1496  }
1497  }
1498 }
1499 #endif
1500 
1501 const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1502 {
1503  value = "";
1504  TiXmlDocument* document = GetDocument();
1505 
1506  if ( data )
1507  {
1508  data->Stamp( p, encoding );
1509  location = data->Cursor();
1510  }
1511 
1512  const char* const startTag = "<![CDATA[";
1513  const char* const endTag = "]]>";
1514 
1515  if ( cdata || StringEqual( p, startTag, false, encoding ) )
1516  {
1517  cdata = true;
1518 
1519  if ( !StringEqual( p, startTag, false, encoding ) )
1520  {
1521  if ( document )
1522  document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
1523  return 0;
1524  }
1525  p += strlen( startTag );
1526 
1527  // Keep all the white space, ignore the encoding, etc.
1528  while ( p && *p
1529  && !StringEqual( p, endTag, false, encoding )
1530  )
1531  {
1532  value += *p;
1533  ++p;
1534  }
1535 
1536  TIXML_STRING dummy;
1537  p = ReadText( p, &dummy, false, endTag, false, encoding );
1538  return p;
1539  }
1540  else
1541  {
1542  bool ignoreWhite = true;
1543 
1544  const char* end = "<";
1545  p = ReadText( p, &value, ignoreWhite, end, false, encoding );
1546  if ( p && *p )
1547  return p-1; // don't truncate the '<'
1548  return 0;
1549  }
1550 }
1551 
1552 #ifdef TIXML_USE_STL
1553 void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
1554 {
1555  while ( in->good() )
1556  {
1557  int c = in->get();
1558  if ( c <= 0 )
1559  {
1560  TiXmlDocument* document = GetDocument();
1561  if ( document )
1563  return;
1564  }
1565  (*tag) += (char) c;
1566 
1567  if ( c == '>' )
1568  {
1569  // All is well.
1570  return;
1571  }
1572  }
1573 }
1574 #endif
1575 
1576 const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
1577 {
1578  p = SkipWhiteSpace( p, _encoding );
1579  // Find the beginning, find the end, and look for
1580  // the stuff in-between.
1581  TiXmlDocument* document = GetDocument();
1582  if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
1583  {
1584  if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
1585  return 0;
1586  }
1587  if ( data )
1588  {
1589  data->Stamp( p, _encoding );
1590  location = data->Cursor();
1591  }
1592  p += 5;
1593 
1594  version = "";
1595  encoding = "";
1596  standalone = "";
1597 
1598  while ( p && *p )
1599  {
1600  if ( *p == '>' )
1601  {
1602  ++p;
1603  return p;
1604  }
1605 
1606  p = SkipWhiteSpace( p, _encoding );
1607  if ( StringEqual( p, "version", true, _encoding ) )
1608  {
1609  TiXmlAttribute attrib;
1610  p = attrib.Parse( p, data, _encoding );
1611  version = attrib.Value();
1612  }
1613  else if ( StringEqual( p, "encoding", true, _encoding ) )
1614  {
1615  TiXmlAttribute attrib;
1616  p = attrib.Parse( p, data, _encoding );
1617  encoding = attrib.Value();
1618  }
1619  else if ( StringEqual( p, "standalone", true, _encoding ) )
1620  {
1621  TiXmlAttribute attrib;
1622  p = attrib.Parse( p, data, _encoding );
1623  standalone = attrib.Value();
1624  }
1625  else
1626  {
1627  // Read over whatever it is.
1628  while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
1629  ++p;
1630  }
1631  }
1632  return 0;
1633 }
1634 
1635 bool TiXmlText::Blank() const
1636 {
1637  for ( unsigned i=0; i<value.length(); i++ )
1638  if ( !IsWhiteSpace( value[i] ) )
1639  return false;
1640  return true;
1641 }
1642 
TiXmlParsingData::Stamp
void Stamp(const char *now, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:200
TiXmlBase::TIXML_ERROR_PARSING_UNKNOWN
@ TIXML_ERROR_PARSING_UNKNOWN
Definition: tinyxml.h:282
TiXmlText::Blank
bool Blank() const
Definition: tinyxmlparser.cpp:1635
TiXmlBase::TIXML_ERROR_STRING_COUNT
@ TIXML_ERROR_STRING_COUNT
Definition: tinyxml.h:290
TiXmlParsingData
Definition: tinyxmlparser.cpp:175
TiXmlBase::TIXML_ERROR_READING_ATTRIBUTES
@ TIXML_ERROR_READING_ATTRIBUTES
Definition: tinyxml.h:279
TiXmlText::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:1470
TiXmlBase::SkipWhiteSpace
static const char * SkipWhiteSpace(const char *, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:318
TiXmlAttribute::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1396
TIXML_UTF_LEAD_2
const unsigned char TIXML_UTF_LEAD_2
Definition: tinyxmlparser.cpp:64
TiXmlBase::ConvertUTF32ToUTF8
static void ConvertUTF32ToUTF8(unsigned long input, char *output, int *length)
Definition: tinyxmlparser.cpp:88
TiXmlDeclaration::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:1553
TiXmlAttributeSet::Find
TiXmlAttribute * Find(const char *_name) const
Definition: tinyxml.cpp:1375
TIXML_ENCODING_UTF8
@ TIXML_ENCODING_UTF8
Definition: tinyxml.h:172
TiXmlCursor
Definition: tinyxml.h:105
TiXmlBase::GetChar
static const char * GetChar(const char *p, char *_value, int *length, TiXmlEncoding encoding)
Definition: tinyxml.h:334
TIXML_UTF_LEAD_1
const unsigned char TIXML_UTF_LEAD_1
Definition: tinyxmlparser.cpp:63
TiXmlBase::StreamWhiteSpace
static bool StreamWhiteSpace(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:369
TiXmlBase::ToLower
static int ToLower(int v, TiXmlEncoding encoding)
Definition: tinyxml.h:389
TiXmlNode::TiXmlElement
friend class TiXmlElement
Definition: tinyxml.h:430
TiXmlNode::LinkEndChild
TiXmlNode * LinkEndChild(TiXmlNode *addThis)
Definition: tinyxml.cpp:186
TiXmlDocument::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data=0, TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Definition: tinyxmlparser.cpp:708
TIXML_ENCODING_UNKNOWN
@ TIXML_ENCODING_UNKNOWN
Definition: tinyxml.h:171
TiXmlDeclaration
Definition: tinyxml.h:1202
TiXmlBase::IsAlphaNum
static int IsAlphaNum(unsigned char anyByte, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:154
TiXmlBase::StringEqual
static bool StringEqual(const char *p, const char *endTag, bool ignoreCase, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:538
TiXmlDeclaration::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1576
tinyxml.h
TiXmlBase::IsWhiteSpaceCondensed
static bool IsWhiteSpaceCondensed()
Return the current white space setting.
Definition: tinyxml.h:231
TiXmlBase::errorString
static const char * errorString[TIXML_ERROR_STRING_COUNT]
Definition: tinyxml.h:378
TiXmlUnknown::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1279
TiXmlNode::firstChild
TiXmlNode * firstChild
Definition: tinyxml.h:765
TiXmlAttributeSet::Add
void Add(TiXmlAttribute *attribute)
Definition: tinyxml.cpp:1317
TiXmlComment::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:1314
TiXmlNode::GetDocument
const TiXmlDocument * GetDocument() const
Definition: tinyxml.cpp:506
TiXmlBase::TIXML_ERROR
@ TIXML_ERROR
Definition: tinyxml.h:274
TiXmlUnknown
Definition: tinyxml.h:1271
TiXmlBase::TIXML_ERROR_EMBEDDED_NULL
@ TIXML_ERROR_EMBEDDED_NULL
Definition: tinyxml.h:286
TiXmlBase::TIXML_ERROR_READING_ELEMENT_VALUE
@ TIXML_ERROR_READING_ELEMENT_VALUE
Definition: tinyxml.h:278
TiXmlDocument::ClearError
void ClearError()
Definition: tinyxml.h:1428
TiXmlCursor::col
int col
Definition: tinyxml.h:111
TiXmlBase::TIXML_ERROR_PARSING_CDATA
@ TIXML_ERROR_PARSING_CDATA
Definition: tinyxml.h:287
TiXmlNode::value
TIXML_STRING value
Definition: tinyxml.h:768
TiXmlElement::ReadValue
const char * ReadValue(const char *in, TiXmlParsingData *prevData, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1183
TiXmlBase::location
TiXmlCursor location
Definition: tinyxml.h:380
TiXmlNode
Definition: tinyxml.h:427
TiXmlElement::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1047
TIXML_ENCODING_LEGACY
@ TIXML_ENCODING_LEGACY
Definition: tinyxml.h:173
TiXmlBase::TIXML_ERROR_READING_END_TAG
@ TIXML_ERROR_READING_END_TAG
Definition: tinyxml.h:281
TiXmlBase::GetEntity
static const char * GetEntity(const char *in, char *value, int *length, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:442
TiXmlDocument
Definition: tinyxml.h:1310
TiXmlBase::utf8ByteTable
static const int utf8ByteTable[256]
Definition: tinyxml.h:260
TiXmlElement::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:907
TiXmlCursor::row
int row
Definition: tinyxml.h:110
TiXmlComment
Definition: tinyxml.h:1079
TiXmlBase::ReadText
static const char * ReadText(const char *in, TIXML_STRING *text, bool ignoreWhiteSpace, const char *endTag, bool ignoreCase, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:578
TiXmlAttribute::NameTStr
const TIXML_STRING & NameTStr() const
Definition: tinyxml.h:823
TiXmlText::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1501
TiXmlDocument::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:645
TiXmlUnknown::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:1255
TiXmlBase::StreamTo
static bool StreamTo(std::istream *in, int character, TIXML_STRING *tag)
Definition: tinyxmlparser.cpp:384
TiXmlText
Definition: tinyxml.h:1129
TiXmlEncoding
TiXmlEncoding
Definition: tinyxml.h:169
TiXmlComment::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:1341
TiXmlParsingData::Cursor
const TiXmlCursor & Cursor() const
Definition: tinyxmlparser.cpp:181
TiXmlBase::TIXML_ERROR_PARSING_EMPTY
@ TIXML_ERROR_PARSING_EMPTY
Definition: tinyxml.h:280
TiXmlBase::IsWhiteSpace
static bool IsWhiteSpace(char c)
Definition: tinyxml.h:297
TiXmlAttribute::SetDocument
void SetDocument(TiXmlDocument *doc)
Definition: tinyxml.h:880
TiXmlBase::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data, TiXmlEncoding encoding)=0
TiXmlAttribute
Definition: tinyxml.h:782
TiXmlBase::TIXML_ERROR_DOCUMENT_EMPTY
@ TIXML_ERROR_DOCUMENT_EMPTY
Definition: tinyxml.h:285
TiXmlBase::TIXML_ERROR_PARSING_ELEMENT
@ TIXML_ERROR_PARSING_ELEMENT
Definition: tinyxml.h:276
TiXmlBase::TIXML_ERROR_PARSING_COMMENT
@ TIXML_ERROR_PARSING_COMMENT
Definition: tinyxml.h:283
TiXmlBase::IsAlpha
static int IsAlpha(unsigned char anyByte, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:133
TiXmlBase::TIXML_ERROR_PARSING_DECLARATION
@ TIXML_ERROR_PARSING_DECLARATION
Definition: tinyxml.h:284
TiXmlDocument::SetError
void SetError(int err, const char *errorLocation, TiXmlParsingData *prevData, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:802
TiXmlNode::Identify
TiXmlNode * Identify(const char *start, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:822
TiXmlText::SetCDATA
void SetCDATA(bool _cdata)
Turns on or off a CDATA representation of text.
Definition: tinyxml.h:1162
TiXmlCursor::Clear
void Clear()
Definition: tinyxml.h:108
TIXML_UTF_LEAD_0
const unsigned char TIXML_UTF_LEAD_0
Definition: tinyxmlparser.cpp:62
TIXML_STRING
#define TIXML_STRING
Definition: tinyxml.h:56
TiXmlDeclaration::Encoding
const char * Encoding() const
Encoding. Will return an empty string if none was found.
Definition: tinyxml.h:1228
TiXmlBase::ReadName
static const char * ReadName(const char *p, TIXML_STRING *name, TiXmlEncoding encoding)
Definition: tinyxmlparser.cpp:405
TiXmlNode::parent
TiXmlNode * parent
Definition: tinyxml.h:762
TiXmlDocument::TabSize
int TabSize() const
Definition: tinyxml.h:1423
TiXmlBase::TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME
@ TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME
Definition: tinyxml.h:277
TiXmlNode::StreamIn
virtual void StreamIn(std::istream *in, TIXML_STRING *tag)=0