Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/FICN/src/tinyxml/tinyxml.cc @ 726

Last change on this file since 726 was 471, checked in by nicolape, 17 years ago

Added tinyxml library

File size: 33.0 KB
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 "tinyxml.h"
27
28#ifdef TIXML_USE_STL
29#include <sstream>
30#endif
31
32
33bool TiXmlBase::condenseWhiteSpace = true;
34
35void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_OSTREAM* stream )
36{
37        TIXML_STRING buffer;
38        PutString( str, &buffer );
39        (*stream) << buffer;
40}
41
42void TiXmlBase::PutString( const TIXML_STRING& str, TIXML_STRING* outString )
43{
44        int i=0;
45
46        while( i<(int)str.length() )
47        {
48                unsigned char c = (unsigned char) str[i];
49
50                if (    c == '&' 
51                     && i < ( (int)str.length() - 2 )
52                         && str[i+1] == '#'
53                         && str[i+2] == 'x' )
54                {
55                        // Hexadecimal character reference.
56                        // Pass through unchanged.
57                        // &#xA9;       -- copyright symbol, for example.
58                        //
59                        // The -1 is a bug fix from Rob Laveaux. It keeps
60                        // an overflow from happening if there is no ';'.
61                        // There are actually 2 ways to exit this loop -
62                        // while fails (error case) and break (semicolon found).
63                        // However, there is no mechanism (currently) for
64                        // this function to return an error.
65                        while ( i<(int)str.length()-1 )
66                        {
67                                outString->append( str.c_str() + i, 1 );
68                                ++i;
69                                if ( str[i] == ';' )
70                                        break;
71                        }
72                }
73                else if ( c == '&' )
74                {
75                        outString->append( entity[0].str, entity[0].strLength );
76                        ++i;
77                }
78                else if ( c == '<' )
79                {
80                        outString->append( entity[1].str, entity[1].strLength );
81                        ++i;
82                }
83                else if ( c == '>' )
84                {
85                        outString->append( entity[2].str, entity[2].strLength );
86                        ++i;
87                }
88                else if ( c == '\"' )
89                {
90                        outString->append( entity[3].str, entity[3].strLength );
91                        ++i;
92                }
93                else if ( c == '\'' )
94                {
95                        outString->append( entity[4].str, entity[4].strLength );
96                        ++i;
97                }
98                else if ( c < 32 )
99                {
100                        // Easy pass at non-alpha/numeric/symbol
101                        // Below 32 is symbolic.
102                        char buf[ 32 ];
103                       
104                        #if defined(TIXML_SNPRINTF)             
105                                TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
106                        #else
107                                sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
108                        #endif         
109
110                        //*ME:  warning C4267: convert 'size_t' to 'int'
111                        //*ME:  Int-Cast to make compiler happy ...
112                        outString->append( buf, (int)strlen( buf ) );
113                        ++i;
114                }
115                else
116                {
117                        //char realc = (char) c;
118                        //outString->append( &realc, 1 );
119                        *outString += (char) c; // somewhat more efficient function call.
120                        ++i;
121                }
122        }
123}
124
125
126// <-- Strange class for a bug fix. Search for STL_STRING_BUG
127TiXmlBase::StringToBuffer::StringToBuffer( const TIXML_STRING& str )
128{
129        buffer = new char[ str.length()+1 ];
130        if ( buffer )
131        {
132                strcpy( buffer, str.c_str() );
133        }
134}
135
136
137TiXmlBase::StringToBuffer::~StringToBuffer()
138{
139        delete [] buffer;
140}
141// End strange bug fix. -->
142
143
144TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
145{
146        parent = 0;
147        type = _type;
148        firstChild = 0;
149        lastChild = 0;
150        prev = 0;
151        next = 0;
152}
153
154
155TiXmlNode::~TiXmlNode()
156{
157        TiXmlNode* node = firstChild;
158        TiXmlNode* temp = 0;
159
160        while ( node )
161        {
162                temp = node;
163                node = node->next;
164                delete temp;
165        }       
166}
167
168
169void TiXmlNode::CopyTo( TiXmlNode* target ) const
170{
171        target->SetValue (value.c_str() );
172        target->userData = userData; 
173}
174
175
176void TiXmlNode::Clear()
177{
178        TiXmlNode* node = firstChild;
179        TiXmlNode* temp = 0;
180
181        while ( node )
182        {
183                temp = node;
184                node = node->next;
185                delete temp;
186        }       
187
188        firstChild = 0;
189        lastChild = 0;
190}
191
192
193TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
194{
195        node->parent = this;
196
197        node->prev = lastChild;
198        node->next = 0;
199
200        if ( lastChild )
201                lastChild->next = node;
202        else
203                firstChild = node;                      // it was an empty list.
204
205        lastChild = node;
206        return node;
207}
208
209
210TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
211{
212        TiXmlNode* node = addThis.Clone();
213        if ( !node )
214                return 0;
215
216        return LinkEndChild( node );
217}
218
219
220TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
221{       
222        if ( !beforeThis || beforeThis->parent != this )
223                return 0;
224
225        TiXmlNode* node = addThis.Clone();
226        if ( !node )
227                return 0;
228        node->parent = this;
229
230        node->next = beforeThis;
231        node->prev = beforeThis->prev;
232        if ( beforeThis->prev )
233        {
234                beforeThis->prev->next = node;
235        }
236        else
237        {
238                assert( firstChild == beforeThis );
239                firstChild = node;
240        }
241        beforeThis->prev = node;
242        return node;
243}
244
245
246TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
247{
248        if ( !afterThis || afterThis->parent != this )
249                return 0;
250
251        TiXmlNode* node = addThis.Clone();
252        if ( !node )
253                return 0;
254        node->parent = this;
255
256        node->prev = afterThis;
257        node->next = afterThis->next;
258        if ( afterThis->next )
259        {
260                afterThis->next->prev = node;
261        }
262        else
263        {
264                assert( lastChild == afterThis );
265                lastChild = node;
266        }
267        afterThis->next = node;
268        return node;
269}
270
271
272TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
273{
274        if ( replaceThis->parent != this )
275                return 0;
276
277        TiXmlNode* node = withThis.Clone();
278        if ( !node )
279                return 0;
280
281        node->next = replaceThis->next;
282        node->prev = replaceThis->prev;
283
284        if ( replaceThis->next )
285                replaceThis->next->prev = node;
286        else
287                lastChild = node;
288
289        if ( replaceThis->prev )
290                replaceThis->prev->next = node;
291        else
292                firstChild = node;
293
294        delete replaceThis;
295        node->parent = this;
296        return node;
297}
298
299
300bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
301{
302        if ( removeThis->parent != this )
303        {       
304                assert( 0 );
305                return false;
306        }
307
308        if ( removeThis->next )
309                removeThis->next->prev = removeThis->prev;
310        else
311                lastChild = removeThis->prev;
312
313        if ( removeThis->prev )
314                removeThis->prev->next = removeThis->next;
315        else
316                firstChild = removeThis->next;
317
318        delete removeThis;
319        return true;
320}
321
322const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
323{
324        const TiXmlNode* node;
325        for ( node = firstChild; node; node = node->next )
326        {
327                if ( strcmp( node->Value(), _value ) == 0 )
328                        return node;
329        }
330        return 0;
331}
332
333
334TiXmlNode* TiXmlNode::FirstChild( const char * _value )
335{
336        TiXmlNode* node;
337        for ( node = firstChild; node; node = node->next )
338        {
339                if ( strcmp( node->Value(), _value ) == 0 )
340                        return node;
341        }
342        return 0;
343}
344
345
346const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
347{
348        const TiXmlNode* node;
349        for ( node = lastChild; node; node = node->prev )
350        {
351                if ( strcmp( node->Value(), _value ) == 0 )
352                        return node;
353        }
354        return 0;
355}
356
357TiXmlNode* TiXmlNode::LastChild( const char * _value )
358{
359        TiXmlNode* node;
360        for ( node = lastChild; node; node = node->prev )
361        {
362                if ( strcmp( node->Value(), _value ) == 0 )
363                        return node;
364        }
365        return 0;
366}
367
368const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
369{
370        if ( !previous )
371        {
372                return FirstChild();
373        }
374        else
375        {
376                assert( previous->parent == this );
377                return previous->NextSibling();
378        }
379}
380
381TiXmlNode* TiXmlNode::IterateChildren( TiXmlNode* previous )
382{
383        if ( !previous )
384        {
385                return FirstChild();
386        }
387        else
388        {
389                assert( previous->parent == this );
390                return previous->NextSibling();
391        }
392}
393
394const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
395{
396        if ( !previous )
397        {
398                return FirstChild( val );
399        }
400        else
401        {
402                assert( previous->parent == this );
403                return previous->NextSibling( val );
404        }
405}
406
407TiXmlNode* TiXmlNode::IterateChildren( const char * val, TiXmlNode* previous )
408{
409        if ( !previous )
410        {
411                return FirstChild( val );
412        }
413        else
414        {
415                assert( previous->parent == this );
416                return previous->NextSibling( val );
417        }
418}
419
420const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const 
421{
422        const TiXmlNode* node;
423        for ( node = next; node; node = node->next )
424        {
425                if ( strcmp( node->Value(), _value ) == 0 )
426                        return node;
427        }
428        return 0;
429}
430
431TiXmlNode* TiXmlNode::NextSibling( const char * _value )
432{
433        TiXmlNode* node;
434        for ( node = next; node; node = node->next )
435        {
436                if ( strcmp( node->Value(), _value ) == 0 )
437                        return node;
438        }
439        return 0;
440}
441
442const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
443{
444        const TiXmlNode* node;
445        for ( node = prev; node; node = node->prev )
446        {
447                if ( strcmp( node->Value(), _value ) == 0 )
448                        return node;
449        }
450        return 0;
451}
452
453TiXmlNode* TiXmlNode::PreviousSibling( const char * _value )
454{
455        TiXmlNode* node;
456        for ( node = prev; node; node = node->prev )
457        {
458                if ( strcmp( node->Value(), _value ) == 0 )
459                        return node;
460        }
461        return 0;
462}
463
464void TiXmlElement::RemoveAttribute( const char * name )
465{
466        TiXmlAttribute* node = attributeSet.Find( name );
467        if ( node )
468        {
469                attributeSet.Remove( node );
470                delete node;
471        }
472}
473
474const TiXmlElement* TiXmlNode::FirstChildElement() const
475{
476        const TiXmlNode* node;
477
478        for (   node = FirstChild();
479                        node;
480                        node = node->NextSibling() )
481        {
482                if ( node->ToElement() )
483                        return node->ToElement();
484        }
485        return 0;
486}
487
488TiXmlElement* TiXmlNode::FirstChildElement()
489{
490        TiXmlNode* node;
491
492        for (   node = FirstChild();
493                        node;
494                        node = node->NextSibling() )
495        {
496                if ( node->ToElement() )
497                        return node->ToElement();
498        }
499        return 0;
500}
501
502const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
503{
504        const TiXmlNode* node;
505
506        for (   node = FirstChild( _value );
507                        node;
508                        node = node->NextSibling( _value ) )
509        {
510                if ( node->ToElement() )
511                        return node->ToElement();
512        }
513        return 0;
514}
515
516TiXmlElement* TiXmlNode::FirstChildElement( const char * _value )
517{
518        TiXmlNode* node;
519
520        for (   node = FirstChild( _value );
521                        node;
522                        node = node->NextSibling( _value ) )
523        {
524                if ( node->ToElement() )
525                        return node->ToElement();
526        }
527        return 0;
528}
529
530const TiXmlElement* TiXmlNode::NextSiblingElement() const
531{
532        const TiXmlNode* node;
533
534        for (   node = NextSibling();
535        node;
536        node = node->NextSibling() )
537        {
538                if ( node->ToElement() )
539                        return node->ToElement();
540        }
541        return 0;
542}
543
544TiXmlElement* TiXmlNode::NextSiblingElement()
545{
546        TiXmlNode* node;
547
548        for (   node = NextSibling();
549        node;
550        node = node->NextSibling() )
551        {
552                if ( node->ToElement() )
553                        return node->ToElement();
554        }
555        return 0;
556}
557
558const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
559{
560        const TiXmlNode* node;
561
562        for (   node = NextSibling( _value );
563        node;
564        node = node->NextSibling( _value ) )
565        {
566                if ( node->ToElement() )
567                        return node->ToElement();
568        }
569        return 0;
570}
571
572TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value )
573{
574        TiXmlNode* node;
575
576        for (   node = NextSibling( _value );
577        node;
578        node = node->NextSibling( _value ) )
579        {
580                if ( node->ToElement() )
581                        return node->ToElement();
582        }
583        return 0;
584}
585
586
587const TiXmlDocument* TiXmlNode::GetDocument() const
588{
589        const TiXmlNode* node;
590
591        for( node = this; node; node = node->parent )
592        {
593                if ( node->ToDocument() )
594                        return node->ToDocument();
595        }
596        return 0;
597}
598
599TiXmlDocument* TiXmlNode::GetDocument()
600{
601        TiXmlNode* node;
602
603        for( node = this; node; node = node->parent )
604        {
605                if ( node->ToDocument() )
606                        return node->ToDocument();
607        }
608        return 0;
609}
610
611TiXmlElement::TiXmlElement (const char * _value)
612        : TiXmlNode( TiXmlNode::ELEMENT )
613{
614        firstChild = lastChild = 0;
615        value = _value;
616}
617
618
619#ifdef TIXML_USE_STL
620TiXmlElement::TiXmlElement( const std::string& _value ) 
621        : TiXmlNode( TiXmlNode::ELEMENT )
622{
623        firstChild = lastChild = 0;
624        value = _value;
625}
626#endif
627
628
629TiXmlElement::TiXmlElement( const TiXmlElement& copy)
630        : TiXmlNode( TiXmlNode::ELEMENT )
631{
632        firstChild = lastChild = 0;
633        copy.CopyTo( this );   
634}
635
636
637void TiXmlElement::operator=( const TiXmlElement& base )
638{
639        ClearThis();
640        base.CopyTo( this );
641}
642
643
644TiXmlElement::~TiXmlElement()
645{
646        ClearThis();
647}
648
649
650void TiXmlElement::ClearThis()
651{
652        Clear();
653        while( attributeSet.First() )
654        {
655                TiXmlAttribute* node = attributeSet.First();
656                attributeSet.Remove( node );
657                delete node;
658        }
659}
660
661
662const char * TiXmlElement::Attribute( const char * name ) const
663{
664        const TiXmlAttribute* node = attributeSet.Find( name );
665
666        if ( node )
667                return node->Value();
668
669        return 0;
670}
671
672
673const char * TiXmlElement::Attribute( const char * name, int* i ) const
674{
675        const char * s = Attribute( name );
676        if ( i )
677        {
678                if ( s )
679                        *i = atoi( s );
680                else
681                        *i = 0;
682        }
683        return s;
684}
685
686
687const char * TiXmlElement::Attribute( const char * name, double* d ) const
688{
689        const char * s = Attribute( name );
690        if ( d )
691        {
692                if ( s )
693                        *d = atof( s );
694                else
695                        *d = 0;
696        }
697        return s;
698}
699
700
701int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
702{
703        const TiXmlAttribute* node = attributeSet.Find( name );
704        if ( !node )
705                return TIXML_NO_ATTRIBUTE;
706
707        return node->QueryIntValue( ival );
708}
709
710
711int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
712{
713        const TiXmlAttribute* node = attributeSet.Find( name );
714        if ( !node )
715                return TIXML_NO_ATTRIBUTE;
716
717        return node->QueryDoubleValue( dval );
718}
719
720
721void TiXmlElement::SetAttribute( const char * name, int val )
722{       
723        char buf[64];
724        #if defined(TIXML_SNPRINTF)             
725                TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
726        #else
727                sprintf( buf, "%d", val );
728        #endif
729        SetAttribute( name, buf );
730}
731
732
733void TiXmlElement::SetDoubleAttribute( const char * name, double val )
734{       
735        char buf[256];
736        #if defined(TIXML_SNPRINTF)             
737                TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
738        #else
739                sprintf( buf, "%f", val );
740        #endif
741        SetAttribute( name, buf );
742}
743
744
745void TiXmlElement::SetAttribute( const char * name, const char * _value )
746{
747        TiXmlAttribute* node = attributeSet.Find( name );
748        if ( node )
749        {
750                node->SetValue( _value );
751                return;
752        }
753
754        TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
755        if ( attrib )
756        {
757                attributeSet.Add( attrib );
758        }
759        else
760        {
761                TiXmlDocument* document = GetDocument();
762                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
763        }
764}
765
766void TiXmlElement::Print( FILE* cfile, int depth ) const
767{
768        int i;
769        for ( i=0; i<depth; i++ )
770        {
771                fprintf( cfile, "    " );
772        }
773
774        fprintf( cfile, "<%s", value.c_str() );
775
776        const TiXmlAttribute* attrib;
777        for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
778        {
779                fprintf( cfile, " " );
780                attrib->Print( cfile, depth );
781        }
782
783        // There are 3 different formatting approaches:
784        // 1) An element without children is printed as a <foo /> node
785        // 2) An element with only a text child is printed as <foo> text </foo>
786        // 3) An element with children is printed on multiple lines.
787        TiXmlNode* node;
788        if ( !firstChild )
789        {
790                fprintf( cfile, " />" );
791        }
792        else if ( firstChild == lastChild && firstChild->ToText() )
793        {
794                fprintf( cfile, ">" );
795                firstChild->Print( cfile, depth + 1 );
796                fprintf( cfile, "</%s>", value.c_str() );
797        }
798        else
799        {
800                fprintf( cfile, ">" );
801
802                for ( node = firstChild; node; node=node->NextSibling() )
803                {
804                        if ( !node->ToText() )
805                        {
806                                fprintf( cfile, "\n" );
807                        }
808                        node->Print( cfile, depth+1 );
809                }
810                fprintf( cfile, "\n" );
811                for( i=0; i<depth; ++i )
812                fprintf( cfile, "    " );
813                fprintf( cfile, "</%s>", value.c_str() );
814        }
815}
816
817void TiXmlElement::StreamOut( TIXML_OSTREAM * stream ) const
818{
819        (*stream) << "<" << value;
820
821        const TiXmlAttribute* attrib;
822        for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
823        {       
824                (*stream) << " ";
825                attrib->StreamOut( stream );
826        }
827
828        // If this node has children, give it a closing tag. Else
829        // make it an empty tag.
830        TiXmlNode* node;
831        if ( firstChild )
832        {               
833                (*stream) << ">";
834
835                for ( node = firstChild; node; node=node->NextSibling() )
836                {
837                        node->StreamOut( stream );
838                }
839                (*stream) << "</" << value << ">";
840        }
841        else
842        {
843                (*stream) << " />";
844        }
845}
846
847
848void TiXmlElement::CopyTo( TiXmlElement* target ) const
849{
850        // superclass:
851        TiXmlNode::CopyTo( target );
852
853        // Element class:
854        // Clone the attributes, then clone the children.
855        const TiXmlAttribute* attribute = 0;
856        for(    attribute = attributeSet.First();
857        attribute;
858        attribute = attribute->Next() )
859        {
860                target->SetAttribute( attribute->Name(), attribute->Value() );
861        }
862
863        TiXmlNode* node = 0;
864        for ( node = firstChild; node; node = node->NextSibling() )
865        {
866                target->LinkEndChild( node->Clone() );
867        }
868}
869
870
871TiXmlNode* TiXmlElement::Clone() const
872{
873        TiXmlElement* clone = new TiXmlElement( Value() );
874        if ( !clone )
875                return 0;
876
877        CopyTo( clone );
878        return clone;
879}
880
881
882const char* TiXmlElement::GetText() const
883{
884        const TiXmlNode* child = this->FirstChild();
885        if ( child ) {
886                const TiXmlText* childText = child->ToText();
887                if ( childText ) {
888                        return childText->Value();
889                }
890        }
891        return 0;
892}
893
894
895TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
896{
897        tabsize = 4;
898        useMicrosoftBOM = false;
899        ClearError();
900}
901
902TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
903{
904        tabsize = 4;
905        useMicrosoftBOM = false;
906        value = documentName;
907        ClearError();
908}
909
910
911#ifdef TIXML_USE_STL
912TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
913{
914        tabsize = 4;
915        useMicrosoftBOM = false;
916    value = documentName;
917        ClearError();
918}
919#endif
920
921
922TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
923{
924        copy.CopyTo( this );
925}
926
927
928void TiXmlDocument::operator=( const TiXmlDocument& copy )
929{
930        Clear();
931        copy.CopyTo( this );
932}
933
934
935bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
936{
937        // See STL_STRING_BUG below.
938        StringToBuffer buf( value );
939
940        if ( buf.buffer && LoadFile( buf.buffer, encoding ) )
941                return true;
942
943        return false;
944}
945
946
947bool TiXmlDocument::SaveFile() const
948{
949        // See STL_STRING_BUG below.
950        StringToBuffer buf( value );
951
952        if ( buf.buffer && SaveFile( buf.buffer ) )
953                return true;
954
955        return false;
956}
957
958bool TiXmlDocument::LoadFile( const char* filename, TiXmlEncoding encoding )
959{
960        // Delete the existing data:
961        Clear();
962        location.Clear();
963
964        // There was a really terrifying little bug here. The code:
965        //              value = filename
966        // in the STL case, cause the assignment method of the std::string to
967        // be called. What is strange, is that the std::string had the same
968        // address as it's c_str() method, and so bad things happen. Looks
969        // like a bug in the Microsoft STL implementation.
970        // See STL_STRING_BUG above.
971        // Fixed with the StringToBuffer class.
972        value = filename;
973
974        // reading in binary mode so that tinyxml can normalize the EOL
975        FILE* file = fopen( value.c_str (), "rb" );     
976
977        if ( file )
978        {
979                // Get the file size, so we can pre-allocate the string. HUGE speed impact.
980                long length = 0;
981                fseek( file, 0, SEEK_END );
982                length = ftell( file );
983                fseek( file, 0, SEEK_SET );
984
985                // Strange case, but good to handle up front.
986                if ( length == 0 )
987                {
988                        fclose( file );
989                        return false;
990                }
991
992                // If we have a file, assume it is all one big XML file, and read it in.
993                // The document parser may decide the document ends sooner than the entire file, however.
994                TIXML_STRING data;
995                data.reserve( length );
996
997                // Subtle bug here. TinyXml did use fgets. But from the XML spec:
998                // 2.11 End-of-Line Handling
999                // <snip>
1000                // <quote>
1001                // ...the XML processor MUST behave as if it normalized all line breaks in external
1002                // parsed entities (including the document entity) on input, before parsing, by translating
1003                // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
1004                // a single #xA character.
1005                // </quote>
1006                //
1007                // It is not clear fgets does that, and certainly isn't clear it works cross platform.
1008                // Generally, you expect fgets to translate from the convention of the OS to the c/unix
1009                // convention, and not work generally.
1010
1011                /*
1012                while( fgets( buf, sizeof(buf), file ) )
1013                {
1014                        data += buf;
1015                }
1016                */
1017
1018                char* buf = new char[ length+1 ];
1019                buf[0] = 0;
1020
1021                if ( fread( buf, length, 1, file ) != 1 ) {
1022                //if ( fread( buf, 1, length, file ) != (size_t)length ) {
1023                        SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1024                        fclose( file );
1025                        return false;
1026                }
1027                fclose( file );
1028
1029                const char* lastPos = buf;
1030                const char* p = buf;
1031
1032                buf[length] = 0;
1033                while( *p ) {
1034                        assert( p < (buf+length) );
1035                        if ( *p == 0xa ) {
1036                                // Newline character. No special rules for this. Append all the characters
1037                                // since the last string, and include the newline.
1038                                data.append( lastPos, p-lastPos+1 );    // append, include the newline
1039                                ++p;                                                                    // move past the newline
1040                                lastPos = p;                                                    // and point to the new buffer (may be 0)
1041                                assert( p <= (buf+length) );
1042                        }
1043                        else if ( *p == 0xd ) {
1044                                // Carriage return. Append what we have so far, then
1045                                // handle moving forward in the buffer.
1046                                if ( (p-lastPos) > 0 ) {
1047                                        data.append( lastPos, p-lastPos );      // do not add the CR
1048                                }
1049                                data += (char)0xa;                                              // a proper newline
1050
1051                                if ( *(p+1) == 0xa ) {
1052                                        // Carriage return - new line sequence
1053                                        p += 2;
1054                                        lastPos = p;
1055                                        assert( p <= (buf+length) );
1056                                }
1057                                else {
1058                                        // it was followed by something else...that is presumably characters again.
1059                                        ++p;
1060                                        lastPos = p;
1061                                        assert( p <= (buf+length) );
1062                                }
1063                        }
1064                        else {
1065                                ++p;
1066                        }
1067                }
1068                // Handle any left over characters.
1069                if ( p-lastPos ) {
1070                        data.append( lastPos, p-lastPos );
1071                }               
1072                delete [] buf;
1073                buf = 0;
1074
1075                Parse( data.c_str(), 0, encoding );
1076
1077                if (  Error() )
1078            return false;
1079        else
1080                        return true;
1081        }
1082        SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1083        return false;
1084}
1085
1086bool TiXmlDocument::SaveFile( const char * filename ) const
1087{
1088        // The old c stuff lives on...
1089        FILE* fp = fopen( filename, "w" );
1090        if ( fp )
1091        {
1092                if ( useMicrosoftBOM ) 
1093                {
1094                        const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
1095                        const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
1096                        const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
1097
1098                        fputc( TIXML_UTF_LEAD_0, fp );
1099                        fputc( TIXML_UTF_LEAD_1, fp );
1100                        fputc( TIXML_UTF_LEAD_2, fp );
1101                }
1102                Print( fp, 0 );
1103                fclose( fp );
1104                return true;
1105        }
1106        return false;
1107}
1108
1109
1110void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
1111{
1112        TiXmlNode::CopyTo( target );
1113
1114        target->error = error;
1115        target->errorDesc = errorDesc.c_str ();
1116
1117        TiXmlNode* node = 0;
1118        for ( node = firstChild; node; node = node->NextSibling() )
1119        {
1120                target->LinkEndChild( node->Clone() );
1121        }       
1122}
1123
1124
1125TiXmlNode* TiXmlDocument::Clone() const
1126{
1127        TiXmlDocument* clone = new TiXmlDocument();
1128        if ( !clone )
1129                return 0;
1130
1131        CopyTo( clone );
1132        return clone;
1133}
1134
1135
1136void TiXmlDocument::Print( FILE* cfile, int depth ) const
1137{
1138        const TiXmlNode* node;
1139        for ( node=FirstChild(); node; node=node->NextSibling() )
1140        {
1141                node->Print( cfile, depth );
1142                fprintf( cfile, "\n" );
1143        }
1144}
1145
1146void TiXmlDocument::StreamOut( TIXML_OSTREAM * out ) const
1147{
1148        const TiXmlNode* node;
1149        for ( node=FirstChild(); node; node=node->NextSibling() )
1150        {
1151                node->StreamOut( out );
1152
1153                // Special rule for streams: stop after the root element.
1154                // The stream in code will only read one element, so don't
1155                // write more than one.
1156                if ( node->ToElement() )
1157                        break;
1158        }
1159}
1160
1161
1162const TiXmlAttribute* TiXmlAttribute::Next() const
1163{
1164        // We are using knowledge of the sentinel. The sentinel
1165        // have a value or name.
1166        if ( next->value.empty() && next->name.empty() )
1167                return 0;
1168        return next;
1169}
1170
1171TiXmlAttribute* TiXmlAttribute::Next()
1172{
1173        // We are using knowledge of the sentinel. The sentinel
1174        // have a value or name.
1175        if ( next->value.empty() && next->name.empty() )
1176                return 0;
1177        return next;
1178}
1179
1180const TiXmlAttribute* TiXmlAttribute::Previous() const
1181{
1182        // We are using knowledge of the sentinel. The sentinel
1183        // have a value or name.
1184        if ( prev->value.empty() && prev->name.empty() )
1185                return 0;
1186        return prev;
1187}
1188
1189TiXmlAttribute* TiXmlAttribute::Previous()
1190{
1191        // We are using knowledge of the sentinel. The sentinel
1192        // have a value or name.
1193        if ( prev->value.empty() && prev->name.empty() )
1194                return 0;
1195        return prev;
1196}
1197
1198void TiXmlAttribute::Print( FILE* cfile, int /*depth*/ ) const
1199{
1200        TIXML_STRING n, v;
1201
1202        PutString( name, &n );
1203        PutString( value, &v );
1204
1205        if (value.find ('\"') == TIXML_STRING::npos)
1206                fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
1207        else
1208                fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
1209}
1210
1211
1212void TiXmlAttribute::StreamOut( TIXML_OSTREAM * stream ) const
1213{
1214        if (value.find( '\"' ) != TIXML_STRING::npos)
1215        {
1216                PutString( name, stream );
1217                (*stream) << "=" << "'";
1218                PutString( value, stream );
1219                (*stream) << "'";
1220        }
1221        else
1222        {
1223                PutString( name, stream );
1224                (*stream) << "=" << "\"";
1225                PutString( value, stream );
1226                (*stream) << "\"";
1227        }
1228}
1229
1230int TiXmlAttribute::QueryIntValue( int* ival ) const
1231{
1232        if ( sscanf( value.c_str(), "%d", ival ) == 1 )
1233                return TIXML_SUCCESS;
1234        return TIXML_WRONG_TYPE;
1235}
1236
1237int TiXmlAttribute::QueryDoubleValue( double* dval ) const
1238{
1239        if ( sscanf( value.c_str(), "%lf", dval ) == 1 )
1240                return TIXML_SUCCESS;
1241        return TIXML_WRONG_TYPE;
1242}
1243
1244void TiXmlAttribute::SetIntValue( int _value )
1245{
1246        char buf [64];
1247        #if defined(TIXML_SNPRINTF)             
1248                TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
1249        #else
1250                sprintf (buf, "%d", _value);
1251        #endif
1252        SetValue (buf);
1253}
1254
1255void TiXmlAttribute::SetDoubleValue( double _value )
1256{
1257        char buf [256];
1258        #if defined(TIXML_SNPRINTF)             
1259                TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
1260        #else
1261                sprintf (buf, "%lf", _value);
1262        #endif
1263        SetValue (buf);
1264}
1265
1266int TiXmlAttribute::IntValue() const
1267{
1268        return atoi (value.c_str ());
1269}
1270
1271double  TiXmlAttribute::DoubleValue() const
1272{
1273        return atof (value.c_str ());
1274}
1275
1276
1277TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
1278{
1279        copy.CopyTo( this );
1280}
1281
1282
1283void TiXmlComment::operator=( const TiXmlComment& base )
1284{
1285        Clear();
1286        base.CopyTo( this );
1287}
1288
1289
1290void TiXmlComment::Print( FILE* cfile, int depth ) const
1291{
1292        for ( int i=0; i<depth; i++ )
1293        {
1294                fputs( "    ", cfile );
1295        }
1296        fprintf( cfile, "<!--%s-->", value.c_str() );
1297}
1298
1299void TiXmlComment::StreamOut( TIXML_OSTREAM * stream ) const
1300{
1301        (*stream) << "<!--";
1302        //PutString( value, stream );
1303        (*stream) << value;
1304        (*stream) << "-->";
1305}
1306
1307
1308void TiXmlComment::CopyTo( TiXmlComment* target ) const
1309{
1310        TiXmlNode::CopyTo( target );
1311}
1312
1313
1314TiXmlNode* TiXmlComment::Clone() const
1315{
1316        TiXmlComment* clone = new TiXmlComment();
1317
1318        if ( !clone )
1319                return 0;
1320
1321        CopyTo( clone );
1322        return clone;
1323}
1324
1325
1326void TiXmlText::Print( FILE* cfile, int depth ) const
1327{
1328        if ( cdata )
1329        {
1330                int i;
1331                fprintf( cfile, "\n" );
1332                for ( i=0; i<depth; i++ ) {
1333                        fprintf( cfile, "    " );
1334                }
1335                fprintf( cfile, "<![CDATA[" );
1336                fprintf( cfile, "%s", value.c_str() );  // unformatted output
1337                fprintf( cfile, "]]>\n" );
1338        }
1339        else
1340        {
1341                TIXML_STRING buffer;
1342                PutString( value, &buffer );
1343                fprintf( cfile, "%s", buffer.c_str() );
1344        }
1345}
1346
1347
1348void TiXmlText::StreamOut( TIXML_OSTREAM * stream ) const
1349{
1350        if ( cdata )
1351        {
1352                (*stream) << "<![CDATA[" << value << "]]>";
1353        }
1354        else
1355        {
1356                PutString( value, stream );
1357        }
1358}
1359
1360
1361void TiXmlText::CopyTo( TiXmlText* target ) const
1362{
1363        TiXmlNode::CopyTo( target );
1364        target->cdata = cdata;
1365}
1366
1367
1368TiXmlNode* TiXmlText::Clone() const
1369{       
1370        TiXmlText* clone = 0;
1371        clone = new TiXmlText( "" );
1372
1373        if ( !clone )
1374                return 0;
1375
1376        CopyTo( clone );
1377        return clone;
1378}
1379
1380
1381TiXmlDeclaration::TiXmlDeclaration( const char * _version,
1382                                                                        const char * _encoding,
1383                                                                        const char * _standalone )
1384        : TiXmlNode( TiXmlNode::DECLARATION )
1385{
1386        version = _version;
1387        encoding = _encoding;
1388        standalone = _standalone;
1389}
1390
1391
1392#ifdef TIXML_USE_STL
1393TiXmlDeclaration::TiXmlDeclaration(     const std::string& _version,
1394                                                                        const std::string& _encoding,
1395                                                                        const std::string& _standalone )
1396        : TiXmlNode( TiXmlNode::DECLARATION )
1397{
1398        version = _version;
1399        encoding = _encoding;
1400        standalone = _standalone;
1401}
1402#endif
1403
1404
1405TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
1406        : TiXmlNode( TiXmlNode::DECLARATION )
1407{
1408        copy.CopyTo( this );   
1409}
1410
1411
1412void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
1413{
1414        Clear();
1415        copy.CopyTo( this );
1416}
1417
1418
1419void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/ ) const
1420{
1421        fprintf (cfile, "<?xml ");
1422
1423        if ( !version.empty() )
1424                fprintf (cfile, "version=\"%s\" ", version.c_str ());
1425        if ( !encoding.empty() )
1426                fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
1427        if ( !standalone.empty() )
1428                fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
1429        fprintf (cfile, "?>");
1430}
1431
1432void TiXmlDeclaration::StreamOut( TIXML_OSTREAM * stream ) const
1433{
1434        (*stream) << "<?xml ";
1435
1436        if ( !version.empty() )
1437        {
1438                (*stream) << "version=\"";
1439                PutString( version, stream );
1440                (*stream) << "\" ";
1441        }
1442        if ( !encoding.empty() )
1443        {
1444                (*stream) << "encoding=\"";
1445                PutString( encoding, stream );
1446                (*stream ) << "\" ";
1447        }
1448        if ( !standalone.empty() )
1449        {
1450                (*stream) << "standalone=\"";
1451                PutString( standalone, stream );
1452                (*stream) << "\" ";
1453        }
1454        (*stream) << "?>";
1455}
1456
1457
1458void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
1459{
1460        TiXmlNode::CopyTo( target );
1461
1462        target->version = version;
1463        target->encoding = encoding;
1464        target->standalone = standalone;
1465}
1466
1467
1468TiXmlNode* TiXmlDeclaration::Clone() const
1469{       
1470        TiXmlDeclaration* clone = new TiXmlDeclaration();
1471
1472        if ( !clone )
1473                return 0;
1474
1475        CopyTo( clone );
1476        return clone;
1477}
1478
1479
1480void TiXmlUnknown::Print( FILE* cfile, int depth ) const
1481{
1482        for ( int i=0; i<depth; i++ )
1483                fprintf( cfile, "    " );
1484        fprintf( cfile, "<%s>", value.c_str() );
1485}
1486
1487
1488void TiXmlUnknown::StreamOut( TIXML_OSTREAM * stream ) const
1489{
1490        (*stream) << "<" << value << ">";               // Don't use entities here! It is unknown.
1491}
1492
1493
1494void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
1495{
1496        TiXmlNode::CopyTo( target );
1497}
1498
1499
1500TiXmlNode* TiXmlUnknown::Clone() const
1501{
1502        TiXmlUnknown* clone = new TiXmlUnknown();
1503
1504        if ( !clone )
1505                return 0;
1506
1507        CopyTo( clone );
1508        return clone;
1509}
1510
1511
1512TiXmlAttributeSet::TiXmlAttributeSet()
1513{
1514        sentinel.next = &sentinel;
1515        sentinel.prev = &sentinel;
1516}
1517
1518
1519TiXmlAttributeSet::~TiXmlAttributeSet()
1520{
1521        assert( sentinel.next == &sentinel );
1522        assert( sentinel.prev == &sentinel );
1523}
1524
1525
1526void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
1527{
1528        assert( !Find( addMe->Name() ) );       // Shouldn't be multiply adding to the set.
1529
1530        addMe->next = &sentinel;
1531        addMe->prev = sentinel.prev;
1532
1533        sentinel.prev->next = addMe;
1534        sentinel.prev      = addMe;
1535}
1536
1537void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
1538{
1539        TiXmlAttribute* node;
1540
1541        for( node = sentinel.next; node != &sentinel; node = node->next )
1542        {
1543                if ( node == removeMe )
1544                {
1545                        node->prev->next = node->next;
1546                        node->next->prev = node->prev;
1547                        node->next = 0;
1548                        node->prev = 0;
1549                        return;
1550                }
1551        }
1552        assert( 0 );            // we tried to remove a non-linked attribute.
1553}
1554
1555const TiXmlAttribute* TiXmlAttributeSet::Find( const char * name ) const
1556{
1557        const TiXmlAttribute* node;
1558
1559        for( node = sentinel.next; node != &sentinel; node = node->next )
1560        {
1561                if ( node->name == name )
1562                        return node;
1563        }
1564        return 0;
1565}
1566
1567TiXmlAttribute* TiXmlAttributeSet::Find( const char * name )
1568{
1569        TiXmlAttribute* node;
1570
1571        for( node = sentinel.next; node != &sentinel; node = node->next )
1572        {
1573                if ( node->name == name )
1574                        return node;
1575        }
1576        return 0;
1577}
1578
1579#ifdef TIXML_USE_STL   
1580TIXML_ISTREAM & operator >> (TIXML_ISTREAM & in, TiXmlNode & base)
1581{
1582        TIXML_STRING tag;
1583        tag.reserve( 8 * 1000 );
1584        base.StreamIn( &in, &tag );
1585
1586        base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
1587        return in;
1588}
1589#endif
1590
1591
1592TIXML_OSTREAM & operator<< (TIXML_OSTREAM & out, const TiXmlNode & base)
1593{
1594        base.StreamOut (& out);
1595        return out;
1596}
1597
1598
1599#ifdef TIXML_USE_STL   
1600std::string & operator<< (std::string& out, const TiXmlNode& base )
1601{
1602   std::ostringstream os_stream( std::ostringstream::out );
1603   base.StreamOut( &os_stream );
1604   
1605   out.append( os_stream.str() );
1606   return out;
1607}
1608#endif
1609
1610
1611TiXmlHandle TiXmlHandle::FirstChild() const
1612{
1613        if ( node )
1614        {
1615                TiXmlNode* child = node->FirstChild();
1616                if ( child )
1617                        return TiXmlHandle( child );
1618        }
1619        return TiXmlHandle( 0 );
1620}
1621
1622
1623TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
1624{
1625        if ( node )
1626        {
1627                TiXmlNode* child = node->FirstChild( value );
1628                if ( child )
1629                        return TiXmlHandle( child );
1630        }
1631        return TiXmlHandle( 0 );
1632}
1633
1634
1635TiXmlHandle TiXmlHandle::FirstChildElement() const
1636{
1637        if ( node )
1638        {
1639                TiXmlElement* child = node->FirstChildElement();
1640                if ( child )
1641                        return TiXmlHandle( child );
1642        }
1643        return TiXmlHandle( 0 );
1644}
1645
1646
1647TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
1648{
1649        if ( node )
1650        {
1651                TiXmlElement* child = node->FirstChildElement( value );
1652                if ( child )
1653                        return TiXmlHandle( child );
1654        }
1655        return TiXmlHandle( 0 );
1656}
1657
1658
1659TiXmlHandle TiXmlHandle::Child( int count ) const
1660{
1661        if ( node )
1662        {
1663                int i;
1664                TiXmlNode* child = node->FirstChild();
1665                for (   i=0;
1666                                child && i<count;
1667                                child = child->NextSibling(), ++i )
1668                {
1669                        // nothing
1670                }
1671                if ( child )
1672                        return TiXmlHandle( child );
1673        }
1674        return TiXmlHandle( 0 );
1675}
1676
1677
1678TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
1679{
1680        if ( node )
1681        {
1682                int i;
1683                TiXmlNode* child = node->FirstChild( value );
1684                for (   i=0;
1685                                child && i<count;
1686                                child = child->NextSibling( value ), ++i )
1687                {
1688                        // nothing
1689                }
1690                if ( child )
1691                        return TiXmlHandle( child );
1692        }
1693        return TiXmlHandle( 0 );
1694}
1695
1696
1697TiXmlHandle TiXmlHandle::ChildElement( int count ) const
1698{
1699        if ( node )
1700        {
1701                int i;
1702                TiXmlElement* child = node->FirstChildElement();
1703                for (   i=0;
1704                                child && i<count;
1705                                child = child->NextSiblingElement(), ++i )
1706                {
1707                        // nothing
1708                }
1709                if ( child )
1710                        return TiXmlHandle( child );
1711        }
1712        return TiXmlHandle( 0 );
1713}
1714
1715
1716TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
1717{
1718        if ( node )
1719        {
1720                int i;
1721                TiXmlElement* child = node->FirstChildElement( value );
1722                for (   i=0;
1723                                child && i<count;
1724                                child = child->NextSiblingElement( value ), ++i )
1725                {
1726                        // nothing
1727                }
1728                if ( child )
1729                        return TiXmlHandle( child );
1730        }
1731        return TiXmlHandle( 0 );
1732}
Note: See TracBrowser for help on using the repository browser.