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