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