source: branches/VUT/0.2/work/tinyxml/tinyxmlparser.cpp @ 61

Revision 61, 18.0 KB checked in by mattausch, 20 years ago (diff)
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 "tinyxml.h"
26#include <ctype.h>
27
28//#define DEBUG_PARSER
29
30// Note tha "PutString" hardcodes the same list. This
31// is less flexible than it appears. Changing the entries
32// or order will break putstring.       
33TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
34{
35        { "&amp;",  5, '&' },
36        { "&lt;",   4, '<' },
37        { "&gt;",   4, '>' },
38        { "&quot;", 6, '\"' },
39        { "&apos;", 6, '\'' }
40};
41
42
43const char* TiXmlBase::SkipWhiteSpace( const char* p )
44{
45        if ( !p || !*p )
46        {
47                return 0;
48        }
49        while ( p && *p )
50        {
51                if ( isspace( *p ) || *p == '\n' || *p =='\r' )         // Still using old rules for white space.
52                        ++p;
53                else
54                        break;
55        }
56
57        return p;
58}
59
60#ifdef TIXML_USE_STL
61/*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag )
62{
63        for( ;; )
64        {
65                if ( !in->good() ) return false;
66
67                int c = in->peek();
68                if ( !IsWhiteSpace( c ) )
69                        return true;
70                *tag += in->get();
71        }
72}
73
74/*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag )
75{
76        while ( in->good() )
77        {
78                int c = in->peek();
79                if ( c == character )
80                        return true;
81
82                in->get();
83                *tag += c;
84        }
85        return false;
86}
87#endif
88
89const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name )
90{
91        *name = "";
92        assert( p );
93
94        // Names start with letters or underscores.
95        // After that, they can be letters, underscores, numbers,
96        // hyphens, or colons. (Colons are valid ony for namespaces,
97        // but tinyxml can't tell namespaces from names.)
98        if (    p && *p
99                 && ( isalpha( (unsigned char) *p ) || *p == '_' ) )
100        {
101                while(          p && *p
102                                &&      (               isalnum( (unsigned char ) *p )
103                                                 || *p == '_'
104                                                 || *p == '-'
105                                                 || *p == ':' ) )
106                {
107                        (*name) += *p;
108                        ++p;
109                }
110                return p;
111        }
112        return 0;
113}
114
115const char* TiXmlBase::GetEntity( const char* p, char* value )
116{
117        // Presume an entity, and pull it out.
118    TIXML_STRING ent;
119        int i;
120
121        // Ignore the &#x entities.
122        if (    strncmp( "&#x", p, 3 ) == 0
123             && *(p+3)
124                 && *(p+4) )
125        {
126                *value = 0;
127               
128                if ( isalpha( *(p+3) ) ) *value += ( tolower( *(p+3) ) - 'a' + 10 ) * 16;
129                else                                 *value += ( *(p+3) - '0' ) * 16;
130
131                if ( isalpha( *(p+4) ) ) *value += ( tolower( *(p+4) ) - 'a' + 10 );
132                else                                 *value += ( *(p+4) - '0' );
133
134                return p+6;
135        }
136
137        // Now try to match it.
138        for( i=0; i<NUM_ENTITY; ++i )
139        {
140                if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
141                {
142                        assert( strlen( entity[i].str ) == entity[i].strLength );
143                        *value = entity[i].chr;
144                        return ( p + entity[i].strLength );
145                }
146        }
147
148        // So it wasn't an entity, its unrecognized, or something like that.
149        *value = *p;    // Don't put back the last one, since we return it!
150        return p+1;
151}
152
153
154bool TiXmlBase::StringEqual( const char* p,
155                                                         const char* tag,
156                                                         bool ignoreCase )
157{
158        assert( p );
159        if ( !p || !*p )
160        {
161                assert( 0 );
162                return false;
163        }
164
165    if ( tolower( *p ) == tolower( *tag ) )
166        {
167                const char* q = p;
168
169                if (ignoreCase)
170                {
171                        while ( *q && *tag && *q == *tag )
172                        {
173                                ++q;
174                                ++tag;
175                        }
176
177                        if ( *tag == 0 )                // Have we found the end of the tag, and everything equal?
178                        {
179                                return true;
180                        }
181                }
182                else
183                {
184                        while ( *q && *tag && tolower( *q ) == tolower( *tag ) )
185                        {
186                                ++q;
187                                ++tag;
188                        }
189
190                        if ( *tag == 0 )
191                        {
192                                return true;
193                        }
194                }
195        }
196        return false;
197}
198
199const char* TiXmlBase::ReadText(        const char* p,
200                                                                        TIXML_STRING * text,
201                                                                        bool trimWhiteSpace,
202                                                                        const char* endTag,
203                                                                        bool caseInsensitive )
204{
205    *text = "";
206        if (    !trimWhiteSpace                 // certain tags always keep whitespace
207                 || !condenseWhiteSpace )       // if true, whitespace is always kept
208        {
209                // Keep all the white space.
210                while (    p && *p
211                                && !StringEqual( p, endTag, caseInsensitive )
212                          )
213                {
214                        char c;
215                        p = GetChar( p, &c );
216            (* text) += c;
217                }
218        }
219        else
220        {
221                bool whitespace = false;
222
223                // Remove leading white space:
224                p = SkipWhiteSpace( p );
225                while (    p && *p
226                                && !StringEqual( p, endTag, caseInsensitive ) )
227                {
228                        if ( *p == '\r' || *p == '\n' )
229                        {
230                                whitespace = true;
231                                ++p;
232                        }
233                        else if ( isspace( *p ) )
234                        {
235                                whitespace = true;
236                                ++p;
237                        }
238                        else
239                        {
240                                // If we've found whitespace, add it before the
241                                // new character. Any whitespace just becomes a space.
242                                if ( whitespace )
243                                {
244               (* text) += ' ';
245                                        whitespace = false;
246                                }
247                                char c;
248                                p = GetChar( p, &c );
249            (* text) += c;
250                        }
251                }
252        }
253        return p + strlen( endTag );
254}
255
256#ifdef TIXML_USE_STL
257
258void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
259{
260        // The basic issue with a document is that we don't know what we're
261        // streaming. Read something presumed to be a tag (and hope), then
262        // identify it, and call the appropriate stream method on the tag.
263        //
264        // This "pre-streaming" will never read the closing ">" so the
265        // sub-tag can orient itself.
266
267        if ( !StreamTo( in, '<', tag ) )
268        {
269                SetError( TIXML_ERROR_PARSING_EMPTY );
270                return;
271        }
272
273        while ( in->good() )
274        {
275                size_t tagIndex = tag->length();
276                while ( in->good() && in->peek() != '>' )
277                {
278                        int c = in->get();
279                        (*tag) += (char) c;
280                }
281
282                if ( in->good() )
283                {
284                        // We now have something we presume to be a node of
285                        // some sort. Identify it, and call the node to
286                        // continue streaming.
287                        TiXmlNode* node = Identify( tag->c_str() + tagIndex );
288
289                        if ( node )
290                        {
291                                node->StreamIn( in, tag );
292                                bool isElement = node->ToElement() != 0;
293                                delete node;
294                                node = 0;
295
296                                // If this is the root element, we're done. Parsing will be
297                                // done by the >> operator.
298                                if ( isElement )
299                                {
300                                        return;
301                                }
302                        }
303                        else
304                        {
305                                SetError( TIXML_ERROR );
306                                return;
307                        }
308                }
309        }
310        // We should have returned sooner.
311        SetError( TIXML_ERROR );
312}
313
314#endif
315
316const char* TiXmlDocument::Parse( const char* p )
317{
318        // Parse away, at the document level. Since a document
319        // contains nothing but other tags, most of what happens
320        // here is skipping white space.
321        //
322        // In this variant (as opposed to stream and Parse) we
323        // read everything we can.
324
325
326        if ( !p || !*p )
327        {
328                SetError( TIXML_ERROR_DOCUMENT_EMPTY );
329                return false;
330        }
331
332    p = SkipWhiteSpace( p );
333        if ( !p )
334        {
335                SetError( TIXML_ERROR_DOCUMENT_EMPTY );
336                return false;
337        }
338
339        while ( p && *p )
340        {
341                TiXmlNode* node = Identify( p );
342                if ( node )
343                {
344                        p = node->Parse( p );
345                        LinkEndChild( node );
346                }
347                else
348                {
349                        break;
350                }
351                p = SkipWhiteSpace( p );
352        }
353        // All is well.
354        return p;
355}
356
357
358TiXmlNode* TiXmlNode::Identify( const char* p )
359{
360        TiXmlNode* returnNode = 0;
361
362        p = SkipWhiteSpace( p );
363        if( !p || !*p || *p != '<' )
364        {
365                return 0;
366        }
367
368        TiXmlDocument* doc = GetDocument();
369        p = SkipWhiteSpace( p );
370
371        if ( !p || !*p )
372        {
373                return 0;
374        }
375
376        // What is this thing?
377        // - Elements start with a letter or underscore, but xml is reserved.
378        // - Comments: <!--
379        // - Decleration: <?xml
380        // - Everthing else is unknown to tinyxml.
381        //
382
383        const char* xmlHeader = { "<?xml" };
384        const char* commentHeader = { "<!--" };
385
386        if ( StringEqual( p, xmlHeader, true ) )
387        {
388                #ifdef DEBUG_PARSER
389                        TIXML_LOG( "XML parsing Declaration\n" );
390                #endif
391                returnNode = new TiXmlDeclaration();
392        }
393        else if (    isalpha( *(p+1) )
394                          || *(p+1) == '_' )
395        {
396                #ifdef DEBUG_PARSER
397                        TIXML_LOG( "XML parsing Element\n" );
398                #endif
399                returnNode = new TiXmlElement( "" );
400        }
401        else if ( StringEqual( p, commentHeader, false ) )
402        {
403                #ifdef DEBUG_PARSER
404                        TIXML_LOG( "XML parsing Comment\n" );
405                #endif
406                returnNode = new TiXmlComment();
407        }
408        else
409        {
410                #ifdef DEBUG_PARSER
411                        TIXML_LOG( "XML parsing Unknown\n" );
412                #endif
413                returnNode = new TiXmlUnknown();
414        }
415
416        if ( returnNode )
417        {
418                // Set the parent, so it can report errors
419                returnNode->parent = this;
420                //p = returnNode->Parse( p );
421        }
422        else
423        {
424                if ( doc )
425                        doc->SetError( TIXML_ERROR_OUT_OF_MEMORY );
426        }
427        return returnNode;
428}
429
430#ifdef TIXML_USE_STL
431
432void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag)
433{
434        // We're called with some amount of pre-parsing. That is, some of "this"
435        // element is in "tag". Go ahead and stream to the closing ">"
436        while( in->good() )
437        {
438                int c = in->get();
439                (*tag) += (char) c ;
440               
441                if ( c == '>' )
442                        break;
443        }
444
445        if ( tag->length() < 3 ) return;
446
447        // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
448        // If not, identify and stream.
449
450        if (    tag->at( tag->length() - 1 ) == '>'
451                 && tag->at( tag->length() - 2 ) == '/' )
452        {
453                // All good!
454                return;
455        }
456        else if ( tag->at( tag->length() - 1 ) == '>' )
457        {
458                // There is more. Could be:
459                //              text
460                //              closing tag
461                //              another node.
462                for ( ;; )
463                {
464                        StreamWhiteSpace( in, tag );
465
466                        // Do we have text?
467                        if ( in->peek() != '<' )
468                        {
469                                // Yep, text.
470                                TiXmlText text( "" );
471                                text.StreamIn( in, tag );
472
473                                // What follows text is a closing tag or another node.
474                                // Go around again and figure it out.
475                                continue;
476                        }
477
478                        // We now have either a closing tag...or another node.
479                        // We should be at a "<", regardless.
480                        if ( !in->good() ) return;
481                        assert( in->peek() == '<' );
482                        size_t tagIndex = tag->length();
483
484                        bool closingTag = false;
485                        bool firstCharFound = false;
486
487                        for( ;; )
488                        {
489                                if ( !in->good() )
490                                        return;
491
492                                int c = in->peek();
493                               
494                                if ( c == '>' )
495                                        break;
496
497                                *tag += c;
498                                in->get();
499
500                                if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
501                                {
502                                        firstCharFound = true;
503                                        if ( c == '/' )
504                                                closingTag = true;
505                                }
506                        }
507                        // If it was a closing tag, then read in the closing '>' to clean up the input stream.
508                        // If it was not, the streaming will be done by the tag.
509                        if ( closingTag )
510                        {
511                                int c = in->get();
512                                assert( c == '>' );
513                                *tag += c;
514
515                                // We are done, once we've found our closing tag.
516                                return;
517                        }
518                        else
519                        {
520                                // If not a closing tag, id it, and stream.
521                                const char* tagloc = tag->c_str() + tagIndex;
522                                TiXmlNode* node = Identify( tagloc );
523                                if ( !node )
524                                        return;
525                                node->StreamIn( in, tag );
526                                delete node;
527                                node = 0;
528
529                                // No return: go around from the beginning: text, closing tag, or node.
530                        }
531                }
532        }
533}
534#endif
535
536const char* TiXmlElement::Parse( const char* p )
537{
538        p = SkipWhiteSpace( p );
539        TiXmlDocument* document = GetDocument();
540
541        if ( !p || !*p || *p != '<' )
542        {
543                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
544                return false;
545        }
546
547        p = SkipWhiteSpace( p+1 );
548
549        // Read the name.
550    p = ReadName( p, &value );
551        if ( !p || !*p )
552        {
553                if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME );
554                return false;
555        }
556
557    TIXML_STRING endTag ("</");
558        endTag += value;
559        endTag += ">";
560
561        // Check for and read attributes. Also look for an empty
562        // tag or an end tag.
563        while ( p && *p )
564        {
565                p = SkipWhiteSpace( p );
566                if ( !p || !*p )
567                {
568                        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
569                        return 0;
570                }
571                if ( *p == '/' )
572                {
573                        ++p;
574                        // Empty tag.
575                        if ( *p  != '>' )
576                        {
577                                if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY );               
578                                return 0;
579                        }
580                        return (p+1);
581                }
582                else if ( *p == '>' )
583                {
584                        // Done with attributes (if there were any.)
585                        // Read the value -- which can include other
586                        // elements -- read the end tag, and return.
587                        ++p;
588                        p = ReadValue( p );             // Note this is an Element method, and will set the error if one happens.
589                        if ( !p || !*p )
590                                return 0;
591
592                        // We should find the end tag now
593                        if ( StringEqual( p, endTag.c_str(), false ) )
594                        {
595                                p += endTag.length();
596                                return p;
597                        }
598                        else
599                        {
600                                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG );
601                                return 0;
602                        }
603                }
604                else
605                {
606                        // Try to read an element:
607                        TiXmlAttribute attrib;
608                        attrib.SetDocument( document );
609                        p = attrib.Parse( p );
610
611                        if ( !p || !*p )
612                        {
613                                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
614                                return 0;
615                        }
616                        SetAttribute( attrib.Name(), attrib.Value() );
617                }
618        }
619        return p;
620}
621
622
623const char* TiXmlElement::ReadValue( const char* p )
624{
625        TiXmlDocument* document = GetDocument();
626
627        // Read in text and elements in any order.
628        p = SkipWhiteSpace( p );
629        while ( p && *p )
630        {
631                if ( *p != '<' )
632                {
633                        // Take what we have, make a text element.
634                        TiXmlText* textNode = new TiXmlText( "" );
635
636                        if ( !textNode )
637                        {
638                                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY );
639                                    return 0;
640                        }
641
642                        p = textNode->Parse( p );
643
644                        if ( !textNode->Blank() )
645                                LinkEndChild( textNode );
646                        else
647                                delete textNode;
648                }
649                else
650                {
651                        // We hit a '<'
652                        // Have we hit a new element or an end tag?
653                        if ( StringEqual( p, "</", false ) )
654                        {
655                                return p;
656                        }
657                        else
658                        {
659                                TiXmlNode* node = Identify( p );
660                                if ( node )
661                                {
662                                        p = node->Parse( p );
663                                        LinkEndChild( node );
664                                }                               
665                                else
666                                {
667                                        return 0;
668                                }
669                        }
670                }
671                p = SkipWhiteSpace( p );
672        }
673
674        if ( !p )
675        {
676                if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE );
677        }       
678        return p;
679}
680
681
682#ifdef TIXML_USE_STL
683void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
684{
685        while ( in->good() )
686        {
687                int c = in->get();     
688                (*tag) += c;
689
690                if ( c == '>' )
691                {
692                        // All is well.
693                        return;         
694                }
695        }
696}
697#endif
698
699
700const char* TiXmlUnknown::Parse( const char* p )
701{
702        TiXmlDocument* document = GetDocument();
703        p = SkipWhiteSpace( p );
704        if ( !p || !*p || *p != '<' )
705        {
706                if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
707                return 0;
708        }
709        ++p;
710    value = "";
711
712        while ( p && *p && *p != '>' )
713        {
714                value += *p;
715                ++p;
716        }
717
718        if ( !p )
719        {
720                if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
721        }
722        if ( *p == '>' )
723                return p+1;
724        return p;
725}
726
727#ifdef TIXML_USE_STL
728void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
729{
730        while ( in->good() )
731        {
732                int c = in->get();     
733                (*tag) += c;
734
735                if ( c == '>'
736                         && tag->at( tag->length() - 2 ) == '-'
737                         && tag->at( tag->length() - 3 ) == '-' )
738                {
739                        // All is well.
740                        return;         
741                }
742        }
743}
744#endif
745
746
747const char* TiXmlComment::Parse( const char* p )
748{
749        TiXmlDocument* document = GetDocument();
750        value = "";
751
752        p = SkipWhiteSpace( p );
753        const char* startTag = "<!--";
754        const char* endTag   = "-->";
755
756        if ( !StringEqual( p, startTag, false ) )
757        {
758                document->SetError( TIXML_ERROR_PARSING_COMMENT );
759                return 0;
760        }
761        p += strlen( startTag );
762        p = ReadText( p, &value, false, endTag, false );
763        return p;
764}
765
766
767const char* TiXmlAttribute::Parse( const char* p )
768{
769        p = SkipWhiteSpace( p );
770        if ( !p || !*p ) return 0;
771
772        // Read the name, the '=' and the value.
773        p = ReadName( p, &name );
774        if ( !p || !*p )
775        {
776                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
777                return 0;
778        }
779        p = SkipWhiteSpace( p );
780        if ( !p || !*p || *p != '=' )
781        {
782                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
783                return 0;
784        }
785
786        ++p;    // skip '='
787        p = SkipWhiteSpace( p );
788        if ( !p || !*p )
789        {
790                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
791                return 0;
792        }
793       
794        const char* end;
795
796        if ( *p == '\'' )
797        {
798                ++p;
799                end = "\'";
800                p = ReadText( p, &value, false, end, false );
801        }
802        else if ( *p == '"' )
803        {
804                ++p;
805                end = "\"";
806                p = ReadText( p, &value, false, end, false );
807        }
808        else
809        {
810                // All attribute values should be in single or double quotes.
811                // But this is such a common error that the parser will try
812                // its best, even without them.
813                value = "";
814                while (    p && *p                                                                              // existence
815                                && !isspace( *p ) && *p != '\n' && *p != '\r'   // whitespace
816                                && *p != '/' && *p != '>' )                                             // tag end
817                {
818                        value += *p;
819                        ++p;
820                }
821        }
822        return p;
823}
824
825#ifdef TIXML_USE_STL
826void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
827{
828        while ( in->good() )
829        {
830                int c = in->peek();     
831                if ( c == '<' )
832                        return;
833
834                (*tag) += c;
835                in->get();
836        }
837}
838#endif
839
840const char* TiXmlText::Parse( const char* p )
841{
842        value = "";
843
844        //TiXmlDocument* doc = GetDocument();
845        bool ignoreWhite = true;
846//      if ( doc && !doc->IgnoreWhiteSpace() ) ignoreWhite = false;
847
848        const char* end = "<";
849        p = ReadText( p, &value, ignoreWhite, end, false );
850        if ( p )
851                return p-1;     // don't truncate the '<'
852        return 0;
853}
854
855#ifdef TIXML_USE_STL
856void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
857{
858        while ( in->good() )
859        {
860                int c = in->get();
861                (*tag) += c;
862
863                if ( c == '>' )
864                {
865                        // All is well.
866                        return;
867                }
868        }
869}
870#endif
871
872const char* TiXmlDeclaration::Parse( const char* p )
873{
874        p = SkipWhiteSpace( p );
875        // Find the beginning, find the end, and look for
876        // the stuff in-between.
877        TiXmlDocument* document = GetDocument();
878        if ( !p || !*p || !StringEqual( p, "<?xml", true ) )
879        {
880                if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION );
881                return 0;
882        }
883
884        p += 5;
885//      const char* start = p+5;
886//      const char* end  = strstr( start, "?>" );
887
888        version = "";
889        encoding = "";
890        standalone = "";
891
892        while ( p && *p )
893        {
894                if ( *p == '>' )
895                {
896                        ++p;
897                        return p;
898                }
899
900                p = SkipWhiteSpace( p );
901                if ( StringEqual( p, "version", true ) )
902                {
903//                      p += 7;
904                        TiXmlAttribute attrib;
905                        p = attrib.Parse( p );         
906                        version = attrib.Value();
907                }
908                else if ( StringEqual( p, "encoding", true ) )
909                {
910//                      p += 8;
911                        TiXmlAttribute attrib;
912                        p = attrib.Parse( p );         
913                        encoding = attrib.Value();
914                }
915                else if ( StringEqual( p, "standalone", true ) )
916                {
917//                      p += 10;
918                        TiXmlAttribute attrib;
919                        p = attrib.Parse( p );         
920                        standalone = attrib.Value();
921                }
922                else
923                {
924                        // Read over whatever it is.
925                        while( p && *p && *p != '>' && !isspace( *p ) )
926                                ++p;
927                }
928        }
929        return 0;
930}
931
932bool TiXmlText::Blank() const
933{
934        for ( unsigned i=0; i<value.length(); i++ )
935                if ( !isspace( value[i] ) )
936                        return false;
937        return true;
938}
939
Note: See TracBrowser for help on using the repository browser.