root/vtcross/branches/trnewman/src/tinyxmlparser.cpp @ 35

Revision 35, 36.5 KB (checked in by trnewman, 16 years ago)

adding c++

Line 
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 0;
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 ) || *p == '\n' || *p =='\r' )            // Still using old rules for white space.
350                                ++p;
351                        else
352                                break;
353                }
354        }
355        else
356        {
357                while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
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 0;
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 0;
455
456                        const char* q = p+3;
457                        q = strchr( q, ';' );
458
459                        if ( !q || !*q ) return 0;
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 0;
474                                mult *= 16;
475                                --q;
476                        }
477                }
478                else
479                {
480                        // Decimal.
481                        if ( !*(p+2) ) return 0;
482
483                        const char* q = p+2;
484                        q = strchr( q, ';' );
485
486                        if ( !q || !*q ) return 0;
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 0;
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 )
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, 0, 0, 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, 0, 0, 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() != 0;
681                                delete node;
682                                node = 0;
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, 0, 0, TIXML_ENCODING_UNKNOWN );
694                                return;
695                        }
696                }
697        }
698        // We should have returned sooner.
699        SetError( TIXML_ERROR, 0, 0, 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, 0, 0, TIXML_ENCODING_UNKNOWN );
714                return 0;
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, 0, 0, TIXML_ENCODING_UNKNOWN );
751                return 0;
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, 0, 0, encoding );
791                return 0;
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 = 0;
821
822        p = SkipWhiteSpace( p, encoding );
823        if( !p || !*p || *p != '<' )
824        {
825                return 0;
826        }
827
828        TiXmlDocument* doc = GetDocument();
829        p = SkipWhiteSpace( p, encoding );
830
831        if ( !p || !*p )
832        {
833                return 0;
834        }
835
836        // What is this thing?
837        // - Elements start with a letter or underscore, but xml is reserved.
838        // - Comments: <!--
839        // - Decleration: <?xml
840        // - Everthing else is unknown to tinyxml.
841        //
842
843        const char* xmlHeader = { "<?xml" };
844        const char* commentHeader = { "<!--" };
845        const char* dtdHeader = { "<!" };
846        const char* cdataHeader = { "<![CDATA[" };
847
848        if ( StringEqual( p, xmlHeader, true, encoding ) )
849        {
850                #ifdef DEBUG_PARSER
851                        TIXML_LOG( "XML parsing Declaration\n" );
852                #endif
853                returnNode = new TiXmlDeclaration();
854        }
855        else if ( StringEqual( p, commentHeader, false, encoding ) )
856        {
857                #ifdef DEBUG_PARSER
858                        TIXML_LOG( "XML parsing Comment\n" );
859                #endif
860                returnNode = new TiXmlComment();
861        }
862        else if ( StringEqual( p, cdataHeader, false, encoding ) )
863        {
864                #ifdef DEBUG_PARSER
865                        TIXML_LOG( "XML parsing CDATA\n" );
866                #endif
867                TiXmlText* text = new TiXmlText( "" );
868                text->SetCDATA( true );
869                returnNode = text;
870        }
871        else if ( StringEqual( p, dtdHeader, false, encoding ) )
872        {
873                #ifdef DEBUG_PARSER
874                        TIXML_LOG( "XML parsing Unknown(1)\n" );
875                #endif
876                returnNode = new TiXmlUnknown();
877        }
878        else if (    IsAlpha( *(p+1), encoding )
879                          || *(p+1) == '_' )
880        {
881                #ifdef DEBUG_PARSER
882                        TIXML_LOG( "XML parsing Element\n" );
883                #endif
884                returnNode = new TiXmlElement( "" );
885        }
886        else
887        {
888                #ifdef DEBUG_PARSER
889                        TIXML_LOG( "XML parsing Unknown(2)\n" );
890                #endif
891                returnNode = new TiXmlUnknown();
892        }
893
894        if ( returnNode )
895        {
896                // Set the parent, so it can report errors
897                returnNode->parent = this;
898        }
899        else
900        {
901                if ( doc )
902                        doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
903        }
904        return returnNode;
905}
906
907#ifdef TIXML_USE_STL
908
909void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
910{
911        // We're called with some amount of pre-parsing. That is, some of "this"
912        // element is in "tag". Go ahead and stream to the closing ">"
913        while( in->good() )
914        {
915                int c = in->get();
916                if ( c <= 0 )
917                {
918                        TiXmlDocument* document = GetDocument();
919                        if ( document )
920                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
921                        return;
922                }
923                (*tag) += (char) c ;
924               
925                if ( c == '>' )
926                        break;
927        }
928
929        if ( tag->length() < 3 ) return;
930
931        // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
932        // If not, identify and stream.
933
934        if (    tag->at( tag->length() - 1 ) == '>'
935                 && tag->at( tag->length() - 2 ) == '/' )
936        {
937                // All good!
938                return;
939        }
940        else if ( tag->at( tag->length() - 1 ) == '>' )
941        {
942                // There is more. Could be:
943                //              text
944                //              cdata text (which looks like another node)
945                //              closing tag
946                //              another node.
947                for ( ;; )
948                {
949                        StreamWhiteSpace( in, tag );
950
951                        // Do we have text?
952                        if ( in->good() && in->peek() != '<' )
953                        {
954                                // Yep, text.
955                                TiXmlText text( "" );
956                                text.StreamIn( in, tag );
957
958                                // What follows text is a closing tag or another node.
959                                // Go around again and figure it out.
960                                continue;
961                        }
962
963                        // We now have either a closing tag...or another node.
964                        // We should be at a "<", regardless.
965                        if ( !in->good() ) return;
966                        assert( in->peek() == '<' );
967                        int tagIndex = (int) tag->length();
968
969                        bool closingTag = false;
970                        bool firstCharFound = false;
971
972                        for( ;; )
973                        {
974                                if ( !in->good() )
975                                        return;
976
977                                int c = in->peek();
978                                if ( c <= 0 )
979                                {
980                                        TiXmlDocument* document = GetDocument();
981                                        if ( document )
982                                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
983                                        return;
984                                }
985                               
986                                if ( c == '>' )
987                                        break;
988
989                                *tag += (char) c;
990                                in->get();
991
992                                // Early out if we find the CDATA id.
993                                if ( c == '[' && tag->size() >= 9 )
994                                {
995                                        size_t len = tag->size();
996                                        const char* start = tag->c_str() + len - 9;
997                                        if ( strcmp( start, "<![CDATA[" ) == 0 ) {
998                                                assert( !closingTag );
999                                                break;
1000                                        }
1001                                }
1002
1003                                if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
1004                                {
1005                                        firstCharFound = true;
1006                                        if ( c == '/' )
1007                                                closingTag = true;
1008                                }
1009                        }
1010                        // If it was a closing tag, then read in the closing '>' to clean up the input stream.
1011                        // If it was not, the streaming will be done by the tag.
1012                        if ( closingTag )
1013                        {
1014                                if ( !in->good() )
1015                                        return;
1016
1017                                int c = in->get();
1018                                if ( c <= 0 )
1019                                {
1020                                        TiXmlDocument* document = GetDocument();
1021                                        if ( document )
1022                                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1023                                        return;
1024                                }
1025                                assert( c == '>' );
1026                                *tag += (char) c;
1027
1028                                // We are done, once we've found our closing tag.
1029                                return;
1030                        }
1031                        else
1032                        {
1033                                // If not a closing tag, id it, and stream.
1034                                const char* tagloc = tag->c_str() + tagIndex;
1035                                TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
1036                                if ( !node )
1037                                        return;
1038                                node->StreamIn( in, tag );
1039                                delete node;
1040                                node = 0;
1041
1042                                // No return: go around from the beginning: text, closing tag, or node.
1043                        }
1044                }
1045        }
1046}
1047#endif
1048
1049const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1050{
1051        p = SkipWhiteSpace( p, encoding );
1052        TiXmlDocument* document = GetDocument();
1053
1054        if ( !p || !*p )
1055        {
1056                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
1057                return 0;
1058        }
1059
1060        if ( data )
1061        {
1062                data->Stamp( p, encoding );
1063                location = data->Cursor();
1064        }
1065
1066        if ( *p != '<' )
1067        {
1068                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
1069                return 0;
1070        }
1071
1072        p = SkipWhiteSpace( p+1, encoding );
1073
1074        // Read the name.
1075        const char* pErr = p;
1076
1077    p = ReadName( p, &value, encoding );
1078        if ( !p || !*p )
1079        {
1080                if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
1081                return 0;
1082        }
1083
1084    TIXML_STRING endTag ("</");
1085        endTag += value;
1086        endTag += ">";
1087
1088        // Check for and read attributes. Also look for an empty
1089        // tag or an end tag.
1090        while ( p && *p )
1091        {
1092                pErr = p;
1093                p = SkipWhiteSpace( p, encoding );
1094                if ( !p || !*p )
1095                {
1096                        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1097                        return 0;
1098                }
1099                if ( *p == '/' )
1100                {
1101                        ++p;
1102                        // Empty tag.
1103                        if ( *p  != '>' )
1104                        {
1105                                if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );             
1106                                return 0;
1107                        }
1108                        return (p+1);
1109                }
1110                else if ( *p == '>' )
1111                {
1112                        // Done with attributes (if there were any.)
1113                        // Read the value -- which can include other
1114                        // elements -- read the end tag, and return.
1115                        ++p;
1116                        p = ReadValue( p, data, encoding );             // Note this is an Element method, and will set the error if one happens.
1117                        if ( !p || !*p ) {
1118                                // We were looking for the end tag, but found nothing.
1119                                // Fix for [ 1663758 ] Failure to report error on bad XML
1120                                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1121                                return 0;
1122                        }
1123
1124                        // We should find the end tag now
1125                        if ( StringEqual( p, endTag.c_str(), false, encoding ) )
1126                        {
1127                                p += endTag.length();
1128                                return p;
1129                        }
1130                        else
1131                        {
1132                                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1133                                return 0;
1134                        }
1135                }
1136                else
1137                {
1138                        // Try to read an attribute:
1139                        TiXmlAttribute* attrib = new TiXmlAttribute();
1140                        if ( !attrib )
1141                        {
1142                                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
1143                                return 0;
1144                        }
1145
1146                        attrib->SetDocument( document );
1147                        pErr = p;
1148                        p = attrib->Parse( p, data, encoding );
1149
1150                        if ( !p || !*p )
1151                        {
1152                                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
1153                                delete attrib;
1154                                return 0;
1155                        }
1156
1157                        // Handle the strange case of double attributes:
1158                        #ifdef TIXML_USE_STL
1159                        TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
1160                        #else
1161                        TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
1162                        #endif
1163                        if ( node )
1164                        {
1165                                node->SetValue( attrib->Value() );
1166                                delete attrib;
1167                                return 0;
1168                        }
1169
1170                        attributeSet.Add( attrib );
1171                }
1172        }
1173        return p;
1174}
1175
1176
1177const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1178{
1179        TiXmlDocument* document = GetDocument();
1180
1181        // Read in text and elements in any order.
1182        const char* pWithWhiteSpace = p;
1183        p = SkipWhiteSpace( p, encoding );
1184
1185        while ( p && *p )
1186        {
1187                if ( *p != '<' )
1188                {
1189                        // Take what we have, make a text element.
1190                        TiXmlText* textNode = new TiXmlText( "" );
1191
1192                        if ( !textNode )
1193                        {
1194                                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
1195                                    return 0;
1196                        }
1197
1198                        if ( TiXmlBase::IsWhiteSpaceCondensed() )
1199                        {
1200                                p = textNode->Parse( p, data, encoding );
1201                        }
1202                        else
1203                        {
1204                                // Special case: we want to keep the white space
1205                                // so that leading spaces aren't removed.
1206                                p = textNode->Parse( pWithWhiteSpace, data, encoding );
1207                        }
1208
1209                        if ( !textNode->Blank() )
1210                                LinkEndChild( textNode );
1211                        else
1212                                delete textNode;
1213                }
1214                else
1215                {
1216                        // We hit a '<'
1217                        // Have we hit a new element or an end tag? This could also be
1218                        // a TiXmlText in the "CDATA" style.
1219                        if ( StringEqual( p, "</", false, encoding ) )
1220                        {
1221                                return p;
1222                        }
1223                        else
1224                        {
1225                                TiXmlNode* node = Identify( p, encoding );
1226                                if ( node )
1227                                {
1228                                        p = node->Parse( p, data, encoding );
1229                                        LinkEndChild( node );
1230                                }                               
1231                                else
1232                                {
1233                                        return 0;
1234                                }
1235                        }
1236                }
1237                pWithWhiteSpace = p;
1238                p = SkipWhiteSpace( p, encoding );
1239        }
1240
1241        if ( !p )
1242        {
1243                if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
1244        }       
1245        return p;
1246}
1247
1248
1249#ifdef TIXML_USE_STL
1250void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
1251{
1252        while ( in->good() )
1253        {
1254                int c = in->get();     
1255                if ( c <= 0 )
1256                {
1257                        TiXmlDocument* document = GetDocument();
1258                        if ( document )
1259                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1260                        return;
1261                }
1262                (*tag) += (char) c;
1263
1264                if ( c == '>' )
1265                {
1266                        // All is well.
1267                        return;         
1268                }
1269        }
1270}
1271#endif
1272
1273
1274const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1275{
1276        TiXmlDocument* document = GetDocument();
1277        p = SkipWhiteSpace( p, encoding );
1278
1279        if ( data )
1280        {
1281                data->Stamp( p, encoding );
1282                location = data->Cursor();
1283        }
1284        if ( !p || !*p || *p != '<' )
1285        {
1286                if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
1287                return 0;
1288        }
1289        ++p;
1290    value = "";
1291
1292        while ( p && *p && *p != '>' )
1293        {
1294                value += *p;
1295                ++p;
1296        }
1297
1298        if ( !p )
1299        {
1300                if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
1301        }
1302        if ( *p == '>' )
1303                return p+1;
1304        return p;
1305}
1306
1307#ifdef TIXML_USE_STL
1308void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
1309{
1310        while ( in->good() )
1311        {
1312                int c = in->get();     
1313                if ( c <= 0 )
1314                {
1315                        TiXmlDocument* document = GetDocument();
1316                        if ( document )
1317                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1318                        return;
1319                }
1320
1321                (*tag) += (char) c;
1322
1323                if ( c == '>'
1324                         && tag->at( tag->length() - 2 ) == '-'
1325                         && tag->at( tag->length() - 3 ) == '-' )
1326                {
1327                        // All is well.
1328                        return;         
1329                }
1330        }
1331}
1332#endif
1333
1334
1335const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1336{
1337        TiXmlDocument* document = GetDocument();
1338        value = "";
1339
1340        p = SkipWhiteSpace( p, encoding );
1341
1342        if ( data )
1343        {
1344                data->Stamp( p, encoding );
1345                location = data->Cursor();
1346        }
1347        const char* startTag = "<!--";
1348        const char* endTag   = "-->";
1349
1350        if ( !StringEqual( p, startTag, false, encoding ) )
1351        {
1352                document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
1353                return 0;
1354        }
1355        p += strlen( startTag );
1356
1357        // [ 1475201 ] TinyXML parses entities in comments
1358        // Oops - ReadText doesn't work, because we don't want to parse the entities.
1359        // p = ReadText( p, &value, false, endTag, false, encoding );
1360        //
1361        // from the XML spec:
1362        /*
1363         [Definition: Comments may appear anywhere in a document outside other markup; in addition,
1364                      they may appear within the document type declaration at places allowed by the grammar.
1365                                  They are not part of the document's character data; an XML processor MAY, but need not,
1366                                  make it possible for an application to retrieve the text of comments. For compatibility,
1367                                  the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity
1368                                  references MUST NOT be recognized within comments.
1369
1370                                  An example of a comment:
1371
1372                                  <!-- declarations for <head> & <body> -->
1373        */
1374
1375    value = "";
1376        // Keep all the white space.
1377        while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
1378        {
1379                value.append( p, 1 );
1380                ++p;
1381        }
1382        if ( p )
1383                p += strlen( endTag );
1384
1385        return p;
1386}
1387
1388
1389const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1390{
1391        p = SkipWhiteSpace( p, encoding );
1392        if ( !p || !*p ) return 0;
1393
1394//      int tabsize = 4;
1395//      if ( document )
1396//              tabsize = document->TabSize();
1397
1398        if ( data )
1399        {
1400                data->Stamp( p, encoding );
1401                location = data->Cursor();
1402        }
1403        // Read the name, the '=' and the value.
1404        const char* pErr = p;
1405        p = ReadName( p, &name, encoding );
1406        if ( !p || !*p )
1407        {
1408                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1409                return 0;
1410        }
1411        p = SkipWhiteSpace( p, encoding );
1412        if ( !p || !*p || *p != '=' )
1413        {
1414                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1415                return 0;
1416        }
1417
1418        ++p;    // skip '='
1419        p = SkipWhiteSpace( p, encoding );
1420        if ( !p || !*p )
1421        {
1422                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1423                return 0;
1424        }
1425       
1426        const char* end;
1427        const char SINGLE_QUOTE = '\'';
1428        const char DOUBLE_QUOTE = '\"';
1429
1430        if ( *p == SINGLE_QUOTE )
1431        {
1432                ++p;
1433                end = "\'";             // single quote in string
1434                p = ReadText( p, &value, false, end, false, encoding );
1435        }
1436        else if ( *p == DOUBLE_QUOTE )
1437        {
1438                ++p;
1439                end = "\"";             // double quote in string
1440                p = ReadText( p, &value, false, end, false, encoding );
1441        }
1442        else
1443        {
1444                // All attribute values should be in single or double quotes.
1445                // But this is such a common error that the parser will try
1446                // its best, even without them.
1447                value = "";
1448                while (    p && *p                                                                                      // existence
1449                                && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r'      // whitespace
1450                                && *p != '/' && *p != '>' )                                                     // tag end
1451                {
1452                        if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
1453                                // [ 1451649 ] Attribute values with trailing quotes not handled correctly
1454                                // We did not have an opening quote but seem to have a
1455                                // closing one. Give up and throw an error.
1456                                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1457                                return 0;
1458                        }
1459                        value += *p;
1460                        ++p;
1461                }
1462        }
1463        return p;
1464}
1465
1466#ifdef TIXML_USE_STL
1467void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
1468{
1469        while ( in->good() )
1470        {
1471                int c = in->peek();     
1472                if ( !cdata && (c == '<' ) )
1473                {
1474                        return;
1475                }
1476                if ( c <= 0 )
1477                {
1478                        TiXmlDocument* document = GetDocument();
1479                        if ( document )
1480                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1481                        return;
1482                }
1483
1484                (*tag) += (char) c;
1485                in->get();      // "commits" the peek made above
1486
1487                if ( cdata && c == '>' && tag->size() >= 3 ) {
1488                        size_t len = tag->size();
1489                        if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
1490                                // terminator of cdata.
1491                                return;
1492                        }
1493                }   
1494        }
1495}
1496#endif
1497
1498const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1499{
1500        value = "";
1501        TiXmlDocument* document = GetDocument();
1502
1503        if ( data )
1504        {
1505                data->Stamp( p, encoding );
1506                location = data->Cursor();
1507        }
1508
1509        const char* const startTag = "<![CDATA[";
1510        const char* const endTag   = "]]>";
1511
1512        if ( cdata || StringEqual( p, startTag, false, encoding ) )
1513        {
1514                cdata = true;
1515
1516                if ( !StringEqual( p, startTag, false, encoding ) )
1517                {
1518                        document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
1519                        return 0;
1520                }
1521                p += strlen( startTag );
1522
1523                // Keep all the white space, ignore the encoding, etc.
1524                while (    p && *p
1525                                && !StringEqual( p, endTag, false, encoding )
1526                          )
1527                {
1528                        value += *p;
1529                        ++p;
1530                }
1531
1532                TIXML_STRING dummy;
1533                p = ReadText( p, &dummy, false, endTag, false, encoding );
1534                return p;
1535        }
1536        else
1537        {
1538                bool ignoreWhite = true;
1539
1540                const char* end = "<";
1541                p = ReadText( p, &value, ignoreWhite, end, false, encoding );
1542                if ( p )
1543                        return p-1;     // don't truncate the '<'
1544                return 0;
1545        }
1546}
1547
1548#ifdef TIXML_USE_STL
1549void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
1550{
1551        while ( in->good() )
1552        {
1553                int c = in->get();
1554                if ( c <= 0 )
1555                {
1556                        TiXmlDocument* document = GetDocument();
1557                        if ( document )
1558                                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1559                        return;
1560                }
1561                (*tag) += (char) c;
1562
1563                if ( c == '>' )
1564                {
1565                        // All is well.
1566                        return;
1567                }
1568        }
1569}
1570#endif
1571
1572const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
1573{
1574        p = SkipWhiteSpace( p, _encoding );
1575        // Find the beginning, find the end, and look for
1576        // the stuff in-between.
1577        TiXmlDocument* document = GetDocument();
1578        if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
1579        {
1580                if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
1581                return 0;
1582        }
1583        if ( data )
1584        {
1585                data->Stamp( p, _encoding );
1586                location = data->Cursor();
1587        }
1588        p += 5;
1589
1590        version = "";
1591        encoding = "";
1592        standalone = "";
1593
1594        while ( p && *p )
1595        {
1596                if ( *p == '>' )
1597                {
1598                        ++p;
1599                        return p;
1600                }
1601
1602                p = SkipWhiteSpace( p, _encoding );
1603                if ( StringEqual( p, "version", true, _encoding ) )
1604                {
1605                        TiXmlAttribute attrib;
1606                        p = attrib.Parse( p, data, _encoding );         
1607                        version = attrib.Value();
1608                }
1609                else if ( StringEqual( p, "encoding", true, _encoding ) )
1610                {
1611                        TiXmlAttribute attrib;
1612                        p = attrib.Parse( p, data, _encoding );         
1613                        encoding = attrib.Value();
1614                }
1615                else if ( StringEqual( p, "standalone", true, _encoding ) )
1616                {
1617                        TiXmlAttribute attrib;
1618                        p = attrib.Parse( p, data, _encoding );         
1619                        standalone = attrib.Value();
1620                }
1621                else
1622                {
1623                        // Read over whatever it is.
1624                        while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
1625                                ++p;
1626                }
1627        }
1628        return 0;
1629}
1630
1631bool TiXmlText::Blank() const
1632{
1633        for ( unsigned i=0; i<value.length(); i++ )
1634                if ( !IsWhiteSpace( value[i] ) )
1635                        return false;
1636        return true;
1637}
1638
Note: See TracBrowser for help on using the browser.