1 /*
2 * Copyright 2010 Inalogic�� Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, as
6 * published by the Free Software Foundation; either version 2.1 or 3.0
7 * of the License.
8 *
9 * This program is distributed in the hope that it will be useful, but
10 * WITHOUT ANY WARRANTY; without even the implied warranties of
11 * MERCHANTABILITY, SATISFACTORY QUALITY or FITNESS FOR A PARTICULAR
12 * PURPOSE. See the applicable version of the GNU Lesser General Public
13 * License for more details.
14 *
15 * You should have received a copy of both the GNU Lesser General Public
16 * License along with this program. If not, see <http://www.gnu.org/licenses/>
17 *
18 * Authored by: Jay Taoko <jaytaoko@inalogic.com>
19 *
20 */
21
22
23 /*
24 www.sourceforge.net/projects/tinyxml
25 Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
26
27 This software is provided 'as-is', without any express or implied
28 warranty. In no event will the authors be held liable for any
29 damages arising from the use of this software.
30
31 Permission is granted to anyone to use this software for any
32 purpose, including commercial applications, and to alter it and
33 redistribute it freely, subject to the following restrictions:
34
35 1. The origin of this software must not be misrepresented; you must
36 not claim that you wrote the original software. If you use this
37 software in a product, an acknowledgment in the product documentation
38 would be appreciated but is not required.
39
40 2. Altered source versions must be plainly marked as such, and
41 must not be misrepresented as being the original software.
42
43 3. This notice may not be removed or altered from any source
44 distribution.
45 */
46
47 #include <ctype.h>
48
49 #ifdef TIXML_USE_STL
50 #include <sstream>
51 #include <iostream>
52 #endif
53
54 #include "tinyxml.h"
55
56
57 bool TiXmlBase::condenseWhiteSpace = true;
58
59 // Microsoft compiler security
60 FILE *TiXmlFOpen ( const char *filename, const char *mode )
61 {
62 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
63 FILE *fp = 0;
64 errno_t err = fopen_s ( &fp, filename, mode );
65
66 if ( !err && fp )
67 return fp;
68
69 return 0;
70 #else
71 return fopen ( filename, mode );
72 #endif
73 }
74
75 void TiXmlBase::EncodeString ( const TIXML_STRING &str, TIXML_STRING *outString )
76 {
77 int i = 0;
78
79 while ( i < (int) str.length() )
80 {
81 unsigned char c = (unsigned char) str[i];
82
83 if ( c == '&'
84 && i < ( (int) str.length() - 2 )
85 && str[i+1] == '#'
86 && str[i+2] == 'x' )
87 {
88 // Hexadecimal character reference.
89 // Pass through unchanged.
90 // © -- copyright symbol, for example.
91 //
92 // The -1 is a bug fix from Rob Laveaux. It keeps
93 // an overflow from happening if there is no ';'.
94 // There are actually 2 ways to exit this loop -
95 // while fails (error case) and break (semicolon found).
96 // However, there is no mechanism (currently) for
97 // this function to return an error.
98 while ( i < (int) str.length() - 1 )
99 {
100 outString->append ( str.c_str() + i, 1 );
101 ++i;
102
103 if ( str[i] == ';' )
104 break;
105 }
106 }
107 else if ( c == '&' )
108 {
109 outString->append ( entity[0].str, entity[0].strLength );
110 ++i;
111 }
112 else if ( c == '<' )
113 {
114 outString->append ( entity[1].str, entity[1].strLength );
115 ++i;
116 }
117 else if ( c == '>' )
118 {
119 outString->append ( entity[2].str, entity[2].strLength );
120 ++i;
121 }
122 else if ( c == '\"' )
123 {
124 outString->append ( entity[3].str, entity[3].strLength );
125 ++i;
126 }
127 else if ( c == '\'' )
128 {
129 outString->append ( entity[4].str, entity[4].strLength );
130 ++i;
131 }
132 else if ( c < 32 )
133 {
134 // Easy pass at non-alpha/numeric/symbol
135 // Below 32 is symbolic.
136 char buf[ 32 ];
137
138 #if defined(TIXML_SNPRINTF)
139 TIXML_SNPRINTF ( buf, sizeof (buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
140 #else
141 sprintf ( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
142 #endif
143
144 //*ME: warning C4267: convert 'size_t' to 'int'
145 //*ME: Int-Cast to make compiler happy ...
146 outString->append ( buf, (int) strlen ( buf ) );
147 ++i;
148 }
149 else
150 {
151 //char realc = (char) c;
152 //outString->append( &realc, 1 );
153 *outString += (char) c; // somewhat more efficient function call.
154 ++i;
155 }
156 }
157 }
158
159
160 TiXmlNode::TiXmlNode ( NodeType _type ) : TiXmlBase()
161 {
162 parent = 0;
163 type = _type;
164 firstChild = 0;
165 lastChild = 0;
166 prev = 0;
167 next = 0;
168 }
169
170
171 TiXmlNode::~TiXmlNode()
172 {
173 TiXmlNode *node = firstChild;
174 TiXmlNode *temp = 0;
175
176 while ( node )
177 {
178 temp = node;
179 node = node->next;
180 delete temp;
181 }
182 }
183
184
185 void TiXmlNode::CopyTo ( TiXmlNode *target ) const
186 {
187 target->SetValue (value.c_str() );
188 target->userData = userData;
189 }
190
191
192 void TiXmlNode::Clear()
193 {
194 TiXmlNode *node = firstChild;
195 TiXmlNode *temp = 0;
196
197 while ( node )
198 {
199 temp = node;
200 node = node->next;
201 delete temp;
202 }
203
204 firstChild = 0;
205 lastChild = 0;
206 }
207
208
209 TiXmlNode *TiXmlNode::LinkEndChild ( TiXmlNode *node )
210 {
211 assert ( node->parent == 0 || node->parent == this );
212 assert ( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
213
214 if ( node->Type() == TiXmlNode::DOCUMENT )
215 {
216 delete node;
217 node = 0;
218
219 if ( GetDocument() ) GetDocument()->SetError ( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
220
221 return 0;
222 }
223
224 node->parent = this;
225
226 node->prev = lastChild;
227 node->next = 0;
228
229 if ( lastChild )
230 lastChild->next = node;
231 else
232 firstChild = node; // it was an empty list.
233
234 lastChild = node;
235 return node;
236 }
237
238
239 TiXmlNode *TiXmlNode::InsertEndChild ( const TiXmlNode &addThis )
240 {
241 if ( addThis.Type() == TiXmlNode::DOCUMENT )
242 {
243 if ( GetDocument() ) GetDocument()->SetError ( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
244
245 return 0;
246 }
247
248 TiXmlNode *node = addThis.Clone();
249
250 if ( !node )
251 return 0;
252
253 return LinkEndChild ( node );
254 }
255
256
257 TiXmlNode *TiXmlNode::InsertBeforeChild ( TiXmlNode *beforeThis, const TiXmlNode &addThis )
258 {
259 if ( !beforeThis || beforeThis->parent != this )
260 {
261 return 0;
262 }
263
264 if ( addThis.Type() == TiXmlNode::DOCUMENT )
265 {
266 if ( GetDocument() ) GetDocument()->SetError ( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
267
268 return 0;
269 }
270
271 TiXmlNode *node = addThis.Clone();
272
273 if ( !node )
274 return 0;
275
276 node->parent = this;
277
278 node->next = beforeThis;
279 node->prev = beforeThis->prev;
280
281 if ( beforeThis->prev )
282 {
283 beforeThis->prev->next = node;
284 }
285 else
286 {
287 assert ( firstChild == beforeThis );
288 firstChild = node;
289 }
290
291 beforeThis->prev = node;
292 return node;
293 }
294
295
296 TiXmlNode *TiXmlNode::InsertAfterChild ( TiXmlNode *afterThis, const TiXmlNode &addThis )
297 {
298 if ( !afterThis || afterThis->parent != this )
299 {
300 return 0;
301 }
302
303 if ( addThis.Type() == TiXmlNode::DOCUMENT )
304 {
305 if ( GetDocument() ) GetDocument()->SetError ( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
306
307 return 0;
308 }
309
310 TiXmlNode *node = addThis.Clone();
311
312 if ( !node )
313 return 0;
314
315 node->parent = this;
316
317 node->prev = afterThis;
318 node->next = afterThis->next;
319
320 if ( afterThis->next )
321 {
322 afterThis->next->prev = node;
323 }
324 else
325 {
326 assert ( lastChild == afterThis );
327 lastChild = node;
328 }
329
330 afterThis->next = node;
331 return node;
332 }
333
334
335 TiXmlNode *TiXmlNode::ReplaceChild ( TiXmlNode *replaceThis, const TiXmlNode &withThis )
336 {
337 if ( replaceThis->parent != this )
338 return 0;
339
340 TiXmlNode *node = withThis.Clone();
341
342 if ( !node )
343 return 0;
344
345 node->next = replaceThis->next;
346 node->prev = replaceThis->prev;
347
348 if ( replaceThis->next )
349 replaceThis->next->prev = node;
350 else
351 lastChild = node;
352
353 if ( replaceThis->prev )
354 replaceThis->prev->next = node;
355 else
356 firstChild = node;
357
358 delete replaceThis;
359 node->parent = this;
360 return node;
361 }
362
363
364 bool TiXmlNode::RemoveChild ( TiXmlNode *removeThis )
365 {
366 if ( removeThis->parent != this )
367 {
368 assert ( 0 );
369 return false;
370 }
371
372 if ( removeThis->next )
373 removeThis->next->prev = removeThis->prev;
374 else
375 lastChild = removeThis->prev;
376
377 if ( removeThis->prev )
378 removeThis->prev->next = removeThis->next;
379 else
380 firstChild = removeThis->next;
381
382 delete removeThis;
383 return true;
384 }
385
386 const TiXmlNode *TiXmlNode::FirstChild ( const char *_value ) const
387 {
388 const TiXmlNode *node;
389
390 for ( node = firstChild; node; node = node->next )
391 {
392 if ( strcmp ( node->Value(), _value ) == 0 )
393 return node;
394 }
395
396 return 0;
397 }
398
399
400 const TiXmlNode *TiXmlNode::LastChild ( const char *_value ) const
401 {
402 const TiXmlNode *node;
403
404 for ( node = lastChild; node; node = node->prev )
405 {
406 if ( strcmp ( node->Value(), _value ) == 0 )
407 return node;
408 }
409
410 return 0;
411 }
412
413
414 const TiXmlNode *TiXmlNode::IterateChildren ( const TiXmlNode *previous ) const
415 {
416 if ( !previous )
417 {
418 return FirstChild();
419 }
420 else
421 {
422 assert ( previous->parent == this );
423 return previous->NextSibling();
424 }
425 }
426
427
428 const TiXmlNode *TiXmlNode::IterateChildren ( const char *val, const TiXmlNode *previous ) const
429 {
430 if ( !previous )
431 {
432 return FirstChild ( val );
433 }
434 else
435 {
436 assert ( previous->parent == this );
437 return previous->NextSibling ( val );
438 }
439 }
440
441
442 const TiXmlNode *TiXmlNode::NextSibling ( const char *_value ) const
443 {
444 const TiXmlNode *node;
445
446 for ( node = next; node; node = node->next )
447 {
448 if ( strcmp ( node->Value(), _value ) == 0 )
449 return node;
450 }
451
452 return 0;
453 }
454
455
456 const TiXmlNode *TiXmlNode::PreviousSibling ( const char *_value ) const
457 {
458 const TiXmlNode *node;
459
460 for ( node = prev; node; node = node->prev )
461 {
462 if ( strcmp ( node->Value(), _value ) == 0 )
463 return node;
464 }
465
466 return 0;
467 }
468
469
470 void TiXmlElement::RemoveAttribute ( const char *name )
471 {
472 #ifdef TIXML_USE_STL
473 TIXML_STRING str ( name );
474 TiXmlAttribute *node = attributeSet.Find ( str );
475 #else
476 TiXmlAttribute *node = attributeSet.Find ( name );
477 #endif
478
479 if ( node )
480 {
481 attributeSet.Remove ( node );
482 delete node;
483 }
484 }
485
486 const TiXmlElement *TiXmlNode::FirstChildElement() const
487 {
488 const TiXmlNode *node;
489
490 for ( node = FirstChild();
491 node;
492 node = node->NextSibling() )
493 {
494 if ( node->ToElement() )
495 return node->ToElement();
496 }
497
498 return 0;
499 }
500
501
502 const 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
514 return 0;
515 }
516
517
518 const TiXmlElement *TiXmlNode::NextSiblingElement() const
519 {
520 const TiXmlNode *node;
521
522 for ( node = NextSibling();
523 node;
524 node = node->NextSibling() )
525 {
526 if ( node->ToElement() )
527 return node->ToElement();
528 }
529
530 return 0;
531 }
532
533
534 const TiXmlElement *TiXmlNode::NextSiblingElement ( const char *_value ) const
535 {
536 const TiXmlNode *node;
537
538 for ( node = NextSibling ( _value );
539 node;
540 node = node->NextSibling ( _value ) )
541 {
542 if ( node->ToElement() )
543 return node->ToElement();
544 }
545
546 return 0;
547 }
548
549
550 const TiXmlDocument *TiXmlNode::GetDocument() const
551 {
552 const TiXmlNode *node;
553
554 for ( node = this; node; node = node->parent )
555 {
556 if ( node->ToDocument() )
557 return node->ToDocument();
558 }
559
560 return 0;
561 }
562
563
564 TiXmlElement::TiXmlElement (const char *_value)
565 : TiXmlNode ( TiXmlNode::ELEMENT )
566 {
567 firstChild = lastChild = 0;
568 value = _value;
569 }
570
571
572 #ifdef TIXML_USE_STL
573 TiXmlElement::TiXmlElement ( const std::string &_value )
574 : TiXmlNode ( TiXmlNode::ELEMENT )
575 {
576 firstChild = lastChild = 0;
577 value = _value;
578 }
579 #endif
580
581
582 TiXmlElement::TiXmlElement ( const TiXmlElement ©)
583 : TiXmlNode ( TiXmlNode::ELEMENT )
584 {
585 firstChild = lastChild = 0;
586 copy.CopyTo ( this );
587 }
588
589
590 void TiXmlElement::operator= ( const TiXmlElement &base )
591 {
592 ClearThis();
593 base.CopyTo ( this );
594 }
595
596
597 TiXmlElement::~TiXmlElement()
598 {
599 ClearThis();
600 }
601
602
603 void TiXmlElement::ClearThis()
604 {
605 Clear();
606
607 while ( attributeSet.First() )
608 {
609 TiXmlAttribute *node = attributeSet.First();
610 attributeSet.Remove ( node );
611 delete node;
612 }
613 }
614
615
616 const char *TiXmlElement::Attribute ( const char *name ) const
617 {
618 const TiXmlAttribute *node = attributeSet.Find ( name );
619
620 if ( node )
621 return node->Value();
622
623 return 0;
624 }
625
626
627 #ifdef TIXML_USE_STL
628 const std::string *TiXmlElement::Attribute ( const std::string &name ) const
629 {
630 const TiXmlAttribute *node = attributeSet.Find ( name );
631
632 if ( node )
633 return &node->ValueStr();
634
635 return 0;
636 }
637 #endif
638
639
640 const char *TiXmlElement::Attribute ( const char *name, int *i ) const
641 {
642 const char *s = Attribute ( name );
643
644 if ( i )
645 {
646 if ( s )
647 {
648 *i = atoi ( s );
649 }
650 else
651 {
652 *i = 0;
653 }
654 }
655
656 return s;
657 }
658
659
660 #ifdef TIXML_USE_STL
661 const std::string *TiXmlElement::Attribute ( const std::string &name, int *i ) const
662 {
663 const std::string *s = Attribute ( name );
664
665 if ( i )
666 {
667 if ( s )
668 {
669 *i = atoi ( s->c_str() );
670 }
671 else
672 {
673 *i = 0;
674 }
675 }
676
677 return s;
678 }
679 #endif
680
681
682 const char *TiXmlElement::Attribute ( const char *name, double *d ) const
683 {
684 const char *s = Attribute ( name );
685
686 if ( d )
687 {
688 if ( s )
689 {
690 *d = atof ( s );
691 }
692 else
693 {
694 *d = 0;
695 }
696 }
697
698 return s;
699 }
700
701
702 #ifdef TIXML_USE_STL
703 const std::string *TiXmlElement::Attribute ( const std::string &name, double *d ) const
704 {
705 const std::string *s = Attribute ( name );
706
707 if ( d )
708 {
709 if ( s )
710 {
711 *d = atof ( s->c_str() );
712 }
713 else
714 {
715 *d = 0;
716 }
717 }
718
719 return s;
720 }
721 #endif
722
723
724 int TiXmlElement::QueryIntAttribute ( const char *name, int *ival ) const
725 {
726 const TiXmlAttribute *node = attributeSet.Find ( name );
727
728 if ( !node )
729 return TIXML_NO_ATTRIBUTE;
730
731 return node->QueryIntValue ( ival );
732 }
733
734
735 #ifdef TIXML_USE_STL
736 int TiXmlElement::QueryIntAttribute ( const std::string &name, int *ival ) const
737 {
738 const TiXmlAttribute *node = attributeSet.Find ( name );
739
740 if ( !node )
741 return TIXML_NO_ATTRIBUTE;
742
743 return node->QueryIntValue ( ival );
744 }
745 #endif
746
747
748 int TiXmlElement::QueryDoubleAttribute ( const char *name, double *dval ) const
749 {
750 const TiXmlAttribute *node = attributeSet.Find ( name );
751
752 if ( !node )
753 return TIXML_NO_ATTRIBUTE;
754
755 return node->QueryDoubleValue ( dval );
756 }
757
758
759 #ifdef TIXML_USE_STL
760 int TiXmlElement::QueryDoubleAttribute ( const std::string &name, double *dval ) const
761 {
762 const TiXmlAttribute *node = attributeSet.Find ( name );
763
764 if ( !node )
765 return TIXML_NO_ATTRIBUTE;
766
767 return node->QueryDoubleValue ( dval );
768 }
769 #endif
770
771
772 void TiXmlElement::SetAttribute ( const char *name, int val )
773 {
774 char buf[64];
775 #if defined(TIXML_SNPRINTF)
776 TIXML_SNPRINTF ( buf, sizeof (buf), "%d", val );
777 #else
778 sprintf ( buf, "%d", val );
779 #endif
780 SetAttribute ( name, buf );
781 }
782
783
784 #ifdef TIXML_USE_STL
785 void TiXmlElement::SetAttribute ( const std::string &name, int val )
786 {
787 std::ostringstream oss;
788 oss << val;
789 SetAttribute ( name, oss.str() );
790 }
791 #endif
792
793
794 void TiXmlElement::SetDoubleAttribute ( const char *name, double val )
795 {
796 char buf[256];
797 #if defined(TIXML_SNPRINTF)
798 TIXML_SNPRINTF ( buf, sizeof (buf), "%f", val );
799 #else
800 sprintf ( buf, "%f", val );
801 #endif
802 SetAttribute ( name, buf );
803 }
804
805
806 void TiXmlElement::SetAttribute ( const char *cname, const char *cvalue )
807 {
808 #ifdef TIXML_USE_STL
809 TIXML_STRING _name ( cname );
810 TIXML_STRING _value ( cvalue );
811 #else
812 const char *_name = cname;
813 const char *_value = cvalue;
814 #endif
815
816 TiXmlAttribute *node = attributeSet.Find ( _name );
817
818 if ( node )
819 {
820 node->SetValue ( _value );
821 return;
822 }
823
824 TiXmlAttribute *attrib = new TiXmlAttribute ( cname, cvalue );
825
826 if ( attrib )
827 {
828 attributeSet.Add ( attrib );
829 }
830 else
831 {
832 TiXmlDocument *document = GetDocument();
833
834 if ( document ) document->SetError ( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
835 }
836 }
837
838
839 #ifdef TIXML_USE_STL
840 void TiXmlElement::SetAttribute ( const std::string &name, const std::string &_value )
841 {
842 TiXmlAttribute *node = attributeSet.Find ( name );
843
844 if ( node )
845 {
846 node->SetValue ( _value );
847 return;
848 }
849
850 TiXmlAttribute *attrib = new TiXmlAttribute ( name, _value );
851
852 if ( attrib )
853 {
854 attributeSet.Add ( attrib );
855 }
856 else
857 {
858 TiXmlDocument *document = GetDocument();
859
860 if ( document ) document->SetError ( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
861 }
862 }
863 #endif
864
865
866 void TiXmlElement::Print ( FILE *cfile, int depth ) const
867 {
868 int i;
869 assert ( cfile );
870
871 for ( i = 0; i < depth; i++ )
872 {
873 fprintf ( cfile, " " );
874 }
875
876 fprintf ( cfile, "<%s", value.c_str() );
877
878 const TiXmlAttribute *attrib;
879
880 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
881 {
882 fprintf ( cfile, " " );
883 attrib->Print ( cfile, depth );
884 }
885
886 // There are 3 different formatting approaches:
887 // 1) An element without children is printed as a <foo /> node
888 // 2) An element with only a text child is printed as <foo> text </foo>
889 // 3) An element with children is printed on multiple lines.
890 TiXmlNode *node;
891
892 if ( !firstChild )
893 {
894 fprintf ( cfile, " />" );
895 }
896 else if ( firstChild == lastChild && firstChild->ToText() )
897 {
898 fprintf ( cfile, ">" );
899 firstChild->Print ( cfile, depth + 1 );
900 fprintf ( cfile, "</%s>", value.c_str() );
901 }
902 else
903 {
904 fprintf ( cfile, ">" );
905
906 for ( node = firstChild; node; node = node->NextSibling() )
907 {
908 if ( !node->ToText() )
909 {
910 fprintf ( cfile, "\n" );
911 }
912
913 node->Print ( cfile, depth + 1 );
914 }
915
916 fprintf ( cfile, "\n" );
917
918 for ( i = 0; i < depth; ++i )
919 {
920 fprintf ( cfile, " " );
921 }
922
923 fprintf ( cfile, "</%s>", value.c_str() );
924 }
925 }
926
927
928 void TiXmlElement::CopyTo ( TiXmlElement *target ) const
929 {
930 // superclass:
931 TiXmlNode::CopyTo ( target );
932
933 // Element class:
934 // Clone the attributes, then clone the children.
935 const TiXmlAttribute *attribute = 0;
936
937 for ( attribute = attributeSet.First();
938 attribute;
939 attribute = attribute->Next() )
940 {
941 target->SetAttribute ( attribute->Name(), attribute->Value() );
942 }
943
944 TiXmlNode *node = 0;
945
946 for ( node = firstChild; node; node = node->NextSibling() )
947 {
948 target->LinkEndChild ( node->Clone() );
949 }
950 }
951
952 bool TiXmlElement::Accept ( TiXmlVisitor *visitor ) const
953 {
954 if ( visitor->VisitEnter ( *this, attributeSet.First() ) )
955 {
956 for ( const TiXmlNode *node = FirstChild(); node; node = node->NextSibling() )
957 {
958 if ( !node->Accept ( visitor ) )
959 break;
960 }
961 }
962
963 return visitor->VisitExit ( *this );
964 }
965
966
967 TiXmlNode *TiXmlElement::Clone() const
968 {
969 TiXmlElement *clone = new TiXmlElement ( Value() );
970
971 if ( !clone )
972 return 0;
973
974 CopyTo ( clone );
975 return clone;
976 }
977
978
979 const char *TiXmlElement::GetText() const
980 {
981 const TiXmlNode *child = this->FirstChild();
982
983 if ( child )
984 {
985 const TiXmlText *childText = child->ToText();
986
987 if ( childText )
988 {
989 return childText->Value();
990 }
991 }
992
993 return 0;
994 }
995
996
997 TiXmlDocument::TiXmlDocument() : TiXmlNode ( TiXmlNode::DOCUMENT )
998 {
999 tabsize = 4;
1000 useMicrosoftBOM = false;
1001 ClearError();
1002 }
1003
1004 TiXmlDocument::TiXmlDocument ( const char *documentName ) : TiXmlNode ( TiXmlNode::DOCUMENT )
1005 {
1006 tabsize = 4;
1007 useMicrosoftBOM = false;
1008 value = documentName;
1009 ClearError();
1010 }
1011
1012
1013 #ifdef TIXML_USE_STL
1014 TiXmlDocument::TiXmlDocument ( const std::string &documentName ) : TiXmlNode ( TiXmlNode::DOCUMENT )
1015 {
1016 tabsize = 4;
1017 useMicrosoftBOM = false;
1018 value = documentName;
1019 ClearError();
1020 }
1021 #endif
1022
1023
1024 TiXmlDocument::TiXmlDocument ( const TiXmlDocument © ) : TiXmlNode ( TiXmlNode::DOCUMENT )
1025 {
1026 copy.CopyTo ( this );
1027 }
1028
1029
1030 void TiXmlDocument::operator= ( const TiXmlDocument © )
1031 {
1032 Clear();
1033 copy.CopyTo ( this );
1034 }
1035
1036
1037 bool TiXmlDocument::LoadFile ( TiXmlEncoding encoding )
1038 {
1039 // See STL_STRING_BUG below.
1040 //StringToBuffer buf( value );
1041
1042 return LoadFile ( Value(), encoding );
1043 }
1044
1045
1046 bool TiXmlDocument::SaveFile() const
1047 {
1048 // See STL_STRING_BUG below.
1049 // StringToBuffer buf( value );
1050 //
1051 // if ( buf.buffer && SaveFile( buf.buffer ) )
1052 // return true;
1053 //
1054 // return false;
1055 return SaveFile ( Value() );
1056 }
1057
1058 bool TiXmlDocument::LoadFile ( const char *_filename, TiXmlEncoding encoding )
1059 {
1060 // There was a really terrifying little bug here. The code:
1061 // value = filename
1062 // in the STL case, cause the assignment method of the std::string to
1063 // be called. What is strange, is that the std::string had the same
1064 // address as it's c_str() method, and so bad things happen. Looks
1065 // like a bug in the Microsoft STL implementation.
1066 // Add an extra string to avoid the crash.
1067 TIXML_STRING filename ( _filename );
1068 value = filename;
1069
1070 // reading in binary mode so that tinyxml can normalize the EOL
1071 FILE *file = TiXmlFOpen ( value.c_str (), "rb" );
1072
1073 if ( file )
1074 {
1075 bool result = LoadFile ( file, encoding );
1076 fclose ( file );
1077 return result;
1078 }
1079 else
1080 {
1081 SetError ( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1082 return false;
1083 }
1084 }
1085
1086 bool TiXmlDocument::LoadFile ( FILE *file, TiXmlEncoding encoding )
1087 {
1088 if ( !file )
1089 {
1090 SetError ( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1091 return false;
1092 }
1093
1094 // Delete the existing data:
1095 Clear();
1096 location.Clear();
1097
1098 // Get the file size, so we can pre-allocate the string. HUGE speed impact.
1099 long length = 0;
1100 fseek ( file, 0, SEEK_END );
1101 length = ftell ( file );
1102 fseek ( file, 0, SEEK_SET );
1103
1104 // Strange case, but good to handle up front.
1105 if ( length <= 0 )
1106 {
1107 SetError ( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
1108 return false;
1109 }
1110
1111 // If we have a file, assume it is all one big XML file, and read it in.
1112 // The document parser may decide the document ends sooner than the entire file, however.
1113 TIXML_STRING data;
1114 data.reserve ( length );
1115
1116 // Subtle bug here. TinyXml did use fgets. But from the XML spec:
1117 // 2.11 End-of-Line Handling
1118 // <snip>
1119 // <quote>
1120 // ...the XML processor MUST behave as if it normalized all line breaks in external
1121 // parsed entities (including the document entity) on input, before parsing, by translating
1122 // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
1123 // a single #xA character.
1124 // </quote>
1125 //
1126 // It is not clear fgets does that, and certainly isn't clear it works cross platform.
1127 // Generally, you expect fgets to translate from the convention of the OS to the c/unix
1128 // convention, and not work generally.
1129
1130 /*
1131 while( fgets( buf, sizeof(buf), file ) )
1132 {
1133 data += buf;
1134 }
1135 */
1136
1137 char *buf = new char[ length+1 ];
1138 buf[0] = 0;
1139
1140 if ( fread ( buf, length, 1, file ) != 1 )
1141 {
1142 delete [] buf;
1143 SetError ( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1144 return false;
1145 }
1146
1147 const char *lastPos = buf;
1148
1149 const char *p = buf;
1150
1151 buf[length] = 0;
1152
1153 while ( *p )
1154 {
1155 assert ( p < (buf + length) );
1156
1157 if ( *p == 0xa )
1158 {
1159 // Newline character. No special rules for this. Append all the characters
1160 // since the last string, and include the newline.
1161 data.append ( lastPos, (p - lastPos + 1) ); // append, include the newline
1162 ++p; // move past the newline
1163 lastPos = p; // and point to the new buffer (may be 0)
1164 assert ( p <= (buf + length) );
1165 }
1166 else if ( *p == 0xd )
1167 {
1168 // Carriage return. Append what we have so far, then
1169 // handle moving forward in the buffer.
1170 if ( (p - lastPos) > 0 )
1171 {
1172 data.append ( lastPos, p - lastPos ); // do not add the CR
1173 }
1174
1175 data += (char) 0xa; // a proper newline
1176
1177 if ( * (p + 1) == 0xa )
1178 {
1179 // Carriage return - new line sequence
1180 p += 2;
1181 lastPos = p;
1182 assert ( p <= (buf + length) );
1183 }
1184 else
1185 {
1186 // it was followed by something else...that is presumably characters again.
1187 ++p;
1188 lastPos = p;
1189 assert ( p <= (buf + length) );
1190 }
1191 }
1192 else
1193 {
1194 ++p;
1195 }
1196 }
1197
1198 // Handle any left over characters.
1199 if ( p - lastPos )
1200 {
1201 data.append ( lastPos, p - lastPos );
1202 }
1203
1204 delete [] buf;
1205 buf = 0;
1206
1207 Parse ( data.c_str(), 0, encoding );
1208
1209 if ( Error() )
1210 return false;
1211 else
1212 return true;
1213 }
1214
1215
1216 bool TiXmlDocument::SaveFile ( const char *filename ) const
1217 {
1218 // The old c stuff lives on...
1219 FILE *fp = TiXmlFOpen ( filename, "w" );
1220
1221 if ( fp )
1222 {
1223 bool result = SaveFile ( fp );
1224 fclose ( fp );
1225 return result;
1226 }
1227
1228 return false;
1229 }
1230
1231
1232 bool TiXmlDocument::SaveFile ( FILE *fp ) const
1233 {
1234 if ( useMicrosoftBOM )
1235 {
1236 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
1237 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
1238 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
1239
1240 fputc ( TIXML_UTF_LEAD_0, fp );
1241 fputc ( TIXML_UTF_LEAD_1, fp );
1242 fputc ( TIXML_UTF_LEAD_2, fp );
1243 }
1244
1245 Print ( fp, 0 );
1246 return (ferror (fp) == 0);
1247 }
1248
1249
1250 void TiXmlDocument::CopyTo ( TiXmlDocument *target ) const
1251 {
1252 TiXmlNode::CopyTo ( target );
1253
1254 target->error = error;
1255 target->errorId = errorId;
1256 target->errorDesc = errorDesc;
1257 target->tabsize = tabsize;
1258 target->errorLocation = errorLocation;
1259 target->useMicrosoftBOM = useMicrosoftBOM;
1260
1261 TiXmlNode *node = 0;
1262
1263 for ( node = firstChild; node; node = node->NextSibling() )
1264 {
1265 target->LinkEndChild ( node->Clone() );
1266 }
1267 }
1268
1269
1270 TiXmlNode *TiXmlDocument::Clone() const
1271 {
1272 TiXmlDocument *clone = new TiXmlDocument();
1273
1274 if ( !clone )
1275 return 0;
1276
1277 CopyTo ( clone );
1278 return clone;
1279 }
1280
1281
1282 void TiXmlDocument::Print ( FILE *cfile, int depth ) const
1283 {
1284 assert ( cfile );
1285
1286 for ( const TiXmlNode *node = FirstChild(); node; node = node->NextSibling() )
1287 {
1288 node->Print ( cfile, depth );
1289 fprintf ( cfile, "\n" );
1290 }
1291 }
1292
1293
1294 bool TiXmlDocument::Accept ( TiXmlVisitor *visitor ) const
1295 {
1296 if ( visitor->VisitEnter ( *this ) )
1297 {
1298 for ( const TiXmlNode *node = FirstChild(); node; node = node->NextSibling() )
1299 {
1300 if ( !node->Accept ( visitor ) )
1301 break;
1302 }
1303 }
1304
1305 return visitor->VisitExit ( *this );
1306 }
1307
1308
1309 const TiXmlAttribute *TiXmlAttribute::Next() const
1310 {
1311 // We are using knowledge of the sentinel. The sentinel
1312 // have a value or name.
1313 if ( next->value.empty() && next->name.empty() )
1314 return 0;
1315
1316 return next;
1317 }
1318
1319 /*
1320 TiXmlAttribute* TiXmlAttribute::Next()
1321 {
1322 // We are using knowledge of the sentinel. The sentinel
1323 // have a value or name.
1324 if ( next->value.empty() && next->name.empty() )
1325 return 0;
1326 return next;
1327 }
1328 */
1329
1330 const TiXmlAttribute *TiXmlAttribute::Previous() const
1331 {
1332 // We are using knowledge of the sentinel. The sentinel
1333 // have a value or name.
1334 if ( prev->value.empty() && prev->name.empty() )
1335 return 0;
1336
1337 return prev;
1338 }
1339
1340 /*
1341 TiXmlAttribute* TiXmlAttribute::Previous()
1342 {
1343 // We are using knowledge of the sentinel. The sentinel
1344 // have a value or name.
1345 if ( prev->value.empty() && prev->name.empty() )
1346 return 0;
1347 return prev;
1348 }
1349 */
1350
1351 void TiXmlAttribute::Print ( FILE *cfile, int /*depth*/, TIXML_STRING *str ) const
1352 {
1353 TIXML_STRING n, v;
1354
1355 EncodeString ( name, &n );
1356 EncodeString ( value, &v );
1357
1358 if (value.find ('\"') == TIXML_STRING::npos)
1359 {
1360 if ( cfile )
1361 {
1362 fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
1363 }
1364
1365 if ( str )
1366 {
1367 (*str) += n;
1368 (*str) += "=\"";
1369 (*str) += v;
1370 (*str) += "\"";
1371 }
1372 }
1373 else
1374 {
1375 if ( cfile )
1376 {
1377 fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
1378 }
1379
1380 if ( str )
1381 {
1382 (*str) += n;
1383 (*str) += "='";
1384 (*str) += v;
1385 (*str) += "'";
1386 }
1387 }
1388 }
1389
1390
1391 int TiXmlAttribute::QueryIntValue ( int *ival ) const
1392 {
1393 if ( TIXML_SSCANF ( value.c_str(), "%d", ival ) == 1 )
1394 return TIXML_SUCCESS;
1395
1396 return TIXML_WRONG_TYPE;
1397 }
1398
1399 int TiXmlAttribute::QueryDoubleValue ( double *dval ) const
1400 {
1401 if ( TIXML_SSCANF ( value.c_str(), "%lf", dval ) == 1 )
1402 return TIXML_SUCCESS;
1403
1404 return TIXML_WRONG_TYPE;
1405 }
1406
1407 void TiXmlAttribute::SetIntValue ( int _value )
1408 {
1409 char buf [64];
1410 #if defined(TIXML_SNPRINTF)
1411 TIXML_SNPRINTF (buf, sizeof (buf), "%d", _value);
1412 #else
1413 sprintf (buf, "%d", _value);
1414 #endif
1415 SetValue (buf);
1416 }
1417
1418 void TiXmlAttribute::SetDoubleValue ( double _value )
1419 {
1420 char buf [256];
1421 #if defined(TIXML_SNPRINTF)
1422 TIXML_SNPRINTF ( buf, sizeof (buf), "%lf", _value);
1423 #else
1424 sprintf (buf, "%lf", _value);
1425 #endif
1426 SetValue (buf);
1427 }
1428
1429 int TiXmlAttribute::IntValue() const
1430 {
1431 return atoi (value.c_str () );
1432 }
1433
1434 double TiXmlAttribute::DoubleValue() const
1435 {
1436 return atof (value.c_str () );
1437 }
1438
1439
1440 TiXmlComment::TiXmlComment ( const TiXmlComment © ) : TiXmlNode ( TiXmlNode::COMMENT )
1441 {
1442 copy.CopyTo ( this );
1443 }
1444
1445
1446 void TiXmlComment::operator= ( const TiXmlComment &base )
1447 {
1448 Clear();
1449 base.CopyTo ( this );
1450 }
1451
1452
1453 void TiXmlComment::Print ( FILE *cfile, int depth ) const
1454 {
1455 assert ( cfile );
1456
1457 for ( int i = 0; i < depth; i++ )
1458 {
1459 fprintf ( cfile, " " );
1460 }
1461
1462 fprintf ( cfile, "<!--%s-->", value.c_str() );
1463 }
1464
1465
1466 void TiXmlComment::CopyTo ( TiXmlComment *target ) const
1467 {
1468 TiXmlNode::CopyTo ( target );
1469 }
1470
1471
1472 bool TiXmlComment::Accept ( TiXmlVisitor *visitor ) const
1473 {
1474 return visitor->Visit ( *this );
1475 }
1476
1477
1478 TiXmlNode *TiXmlComment::Clone() const
1479 {
1480 TiXmlComment *clone = new TiXmlComment();
1481
1482 if ( !clone )
1483 return 0;
1484
1485 CopyTo ( clone );
1486 return clone;
1487 }
1488
1489
1490 void TiXmlText::Print ( FILE *cfile, int depth ) const
1491 {
1492 assert ( cfile );
1493
1494 if ( cdata )
1495 {
1496 int i;
1497 fprintf ( cfile, "\n" );
1498
1499 for ( i = 0; i < depth; i++ )
1500 {
1501 fprintf ( cfile, " " );
1502 }
1503
1504 fprintf ( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output
1505 }
1506 else
1507 {
1508 TIXML_STRING buffer;
1509 EncodeString ( value, &buffer );
1510 fprintf ( cfile, "%s", buffer.c_str() );
1511 }
1512 }
1513
1514
1515 void TiXmlText::CopyTo ( TiXmlText *target ) const
1516 {
1517 TiXmlNode::CopyTo ( target );
1518 target->cdata = cdata;
1519 }
1520
1521
1522 bool TiXmlText::Accept ( TiXmlVisitor *visitor ) const
1523 {
1524 return visitor->Visit ( *this );
1525 }
1526
1527
1528 TiXmlNode *TiXmlText::Clone() const
1529 {
1530 TiXmlText *clone = 0;
1531 clone = new TiXmlText ( "" );
1532
1533 if ( !clone )
1534 return 0;
1535
1536 CopyTo ( clone );
1537 return clone;
1538 }
1539
1540
1541 TiXmlDeclaration::TiXmlDeclaration ( const char *_version,
1542 const char *_encoding,
1543 const char *_standalone )
1544 : TiXmlNode ( TiXmlNode::DECLARATION )
1545 {
1546 version = _version;
1547 encoding = _encoding;
1548 standalone = _standalone;
1549 }
1550
1551
1552 #ifdef TIXML_USE_STL
1553 TiXmlDeclaration::TiXmlDeclaration ( const std::string &_version,
1554 const std::string &_encoding,
1555 const std::string &_standalone )
1556 : TiXmlNode ( TiXmlNode::DECLARATION )
1557 {
1558 version = _version;
1559 encoding = _encoding;
1560 standalone = _standalone;
1561 }
1562 #endif
1563
1564
1565 TiXmlDeclaration::TiXmlDeclaration ( const TiXmlDeclaration © )
1566 : TiXmlNode ( TiXmlNode::DECLARATION )
1567 {
1568 copy.CopyTo ( this );
1569 }
1570
1571
1572 void TiXmlDeclaration::operator= ( const TiXmlDeclaration © )
CID 10639 - ASSIGN_NOT_RETURNING_STAR_THIS
Assignment operator with void return type.
1573 {
1574 Clear();
1575 copy.CopyTo ( this );
1576 }
1577
1578
1579 void TiXmlDeclaration::Print ( FILE *cfile, int /*depth*/, TIXML_STRING *str ) const
1580 {
1581 if ( cfile ) fprintf ( cfile, "<?xml " );
1582
1583 if ( str ) (*str) += "<?xml ";
1584
1585 if ( !version.empty() )
1586 {
1587 if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str () );
1588
1589 if ( str )
1590 {
1591 (*str) += "version=\"";
1592 (*str) += version;
1593 (*str) += "\" ";
1594 }
1595 }
1596
1597 if ( !encoding.empty() )
1598 {
1599 if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str () );
1600
1601 if ( str )
1602 {
1603 (*str) += "encoding=\"";
1604 (*str) += encoding;
1605 (*str) += "\" ";
1606 }
1607 }
1608
1609 if ( !standalone.empty() )
1610 {
1611 if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str () );
1612
1613 if ( str )
1614 {
1615 (*str) += "standalone=\"";
1616 (*str) += standalone;
1617 (*str) += "\" ";
1618 }
1619 }
1620
1621 if ( cfile ) fprintf ( cfile, "?>" );
1622
1623 if ( str ) (*str) += "?>";
1624 }
1625
1626
1627 void TiXmlDeclaration::CopyTo ( TiXmlDeclaration *target ) const
1628 {
1629 TiXmlNode::CopyTo ( target );
1630
1631 target->version = version;
1632 target->encoding = encoding;
1633 target->standalone = standalone;
1634 }
1635
1636
1637 bool TiXmlDeclaration::Accept ( TiXmlVisitor *visitor ) const
1638 {
1639 return visitor->Visit ( *this );
1640 }
1641
1642
1643 TiXmlNode *TiXmlDeclaration::Clone() const
1644 {
1645 TiXmlDeclaration *clone = new TiXmlDeclaration();
1646
1647 if ( !clone )
1648 return 0;
1649
1650 CopyTo ( clone );
1651 return clone;
1652 }
1653
1654
1655 void TiXmlUnknown::Print ( FILE *cfile, int depth ) const
1656 {
1657 for ( int i = 0; i < depth; i++ )
1658 fprintf ( cfile, " " );
1659
1660 fprintf ( cfile, "<%s>", value.c_str() );
1661 }
1662
1663
1664 void TiXmlUnknown::CopyTo ( TiXmlUnknown *target ) const
1665 {
1666 TiXmlNode::CopyTo ( target );
1667 }
1668
1669
1670 bool TiXmlUnknown::Accept ( TiXmlVisitor *visitor ) const
1671 {
1672 return visitor->Visit ( *this );
1673 }
1674
1675
1676 TiXmlNode *TiXmlUnknown::Clone() const
1677 {
1678 TiXmlUnknown *clone = new TiXmlUnknown();
1679
1680 if ( !clone )
1681 return 0;
1682
1683 CopyTo ( clone );
1684 return clone;
1685 }
1686
1687
1688 TiXmlAttributeSet::TiXmlAttributeSet()
1689 {
1690 sentinel.next = &sentinel;
1691 sentinel.prev = &sentinel;
1692 }
1693
1694
1695 TiXmlAttributeSet::~TiXmlAttributeSet()
1696 {
1697 assert ( sentinel.next == &sentinel );
1698 assert ( sentinel.prev == &sentinel );
1699 }
1700
1701
1702 void TiXmlAttributeSet::Add ( TiXmlAttribute *addMe )
1703 {
1704 #ifdef TIXML_USE_STL
1705 assert ( !Find ( TIXML_STRING ( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set.
1706 #else
1707 assert ( !Find ( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
1708 #endif
1709
1710 addMe->next = &sentinel;
1711 addMe->prev = sentinel.prev;
1712
1713 sentinel.prev->next = addMe;
1714 sentinel.prev = addMe;
1715 }
1716
1717 void TiXmlAttributeSet::Remove ( TiXmlAttribute *removeMe )
1718 {
1719 TiXmlAttribute *node;
1720
1721 for ( node = sentinel.next; node != &sentinel; node = node->next )
1722 {
1723 if ( node == removeMe )
1724 {
1725 node->prev->next = node->next;
1726 node->next->prev = node->prev;
1727 node->next = 0;
1728 node->prev = 0;
1729 return;
1730 }
1731 }
1732
1733 assert ( 0 ); // we tried to remove a non-linked attribute.
1734 }
1735
1736
1737 #ifdef TIXML_USE_STL
1738 const TiXmlAttribute *TiXmlAttributeSet::Find ( const std::string &name ) const
1739 {
1740 for ( const TiXmlAttribute *node = sentinel.next; node != &sentinel; node = node->next )
1741 {
1742 if ( node->name == name )
1743 return node;
1744 }
1745
1746 return 0;
1747 }
1748
1749 /*
1750 TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name )
1751 {
1752 for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1753 {
1754 if ( node->name == name )
1755 return node;
1756 }
1757 return 0;
1758 }
1759 */
1760 #endif
1761
1762
1763 const TiXmlAttribute *TiXmlAttributeSet::Find ( const char *name ) const
1764 {
1765 for ( const TiXmlAttribute *node = sentinel.next; node != &sentinel; node = node->next )
1766 {
1767 if ( strcmp ( node->name.c_str(), name ) == 0 )
1768 return node;
1769 }
1770
1771 return 0;
1772 }
1773
1774 /*
1775 TiXmlAttribute* TiXmlAttributeSet::Find( const char* name )
1776 {
1777 for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1778 {
1779 if ( strcmp( node->name.c_str(), name ) == 0 )
1780 return node;
1781 }
1782 return 0;
1783 }
1784 */
1785
1786 #ifdef TIXML_USE_STL
1787 std::istream &operator>> (std::istream &in, TiXmlNode &base)
1788 {
1789 TIXML_STRING tag;
1790 tag.reserve ( 8 * 1000 );
1791 base.StreamIn ( &in, &tag );
1792
1793 base.Parse ( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
1794 return in;
1795 }
1796 #endif
1797
1798
1799 #ifdef TIXML_USE_STL
1800 std::ostream &operator<< (std::ostream &out, const TiXmlNode &base)
1801 {
1802 TiXmlPrinter printer;
1803 printer.SetStreamPrinting();
1804 base.Accept ( &printer );
1805 out << printer.Str();
1806
1807 return out;
1808 }
1809
1810
1811 std::string &operator<< (std::string &out, const TiXmlNode &base )
1812 {
1813 TiXmlPrinter printer;
1814 printer.SetStreamPrinting();
1815 base.Accept ( &printer );
1816 out.append ( printer.Str() );
1817
1818 return out;
1819 }
1820 #endif
1821
1822
1823 TiXmlHandle TiXmlHandle::FirstChild() const
1824 {
1825 if ( node )
1826 {
1827 TiXmlNode *child = node->FirstChild();
1828
1829 if ( child )
1830 return TiXmlHandle ( child );
1831 }
1832
1833 return TiXmlHandle ( 0 );
1834 }
1835
1836
1837 TiXmlHandle TiXmlHandle::FirstChild ( const char *value ) const
1838 {
1839 if ( node )
1840 {
1841 TiXmlNode *child = node->FirstChild ( value );
1842
1843 if ( child )
1844 return TiXmlHandle ( child );
1845 }
1846
1847 return TiXmlHandle ( 0 );
1848 }
1849
1850
1851 TiXmlHandle TiXmlHandle::FirstChildElement() const
1852 {
1853 if ( node )
1854 {
1855 TiXmlElement *child = node->FirstChildElement();
1856
1857 if ( child )
1858 return TiXmlHandle ( child );
1859 }
1860
1861 return TiXmlHandle ( 0 );
1862 }
1863
1864
1865 TiXmlHandle TiXmlHandle::FirstChildElement ( const char *value ) const
1866 {
1867 if ( node )
1868 {
1869 TiXmlElement *child = node->FirstChildElement ( value );
1870
1871 if ( child )
1872 return TiXmlHandle ( child );
1873 }
1874
1875 return TiXmlHandle ( 0 );
1876 }
1877
1878
1879 TiXmlHandle TiXmlHandle::Child ( int count ) const
1880 {
1881 if ( node )
1882 {
1883 int i;
1884 TiXmlNode *child = node->FirstChild();
1885
1886 for ( i = 0;
1887 child && i < count;
1888 child = child->NextSibling(), ++i )
1889 {
1890 // nothing
1891 }
1892
1893 if ( child )
1894 return TiXmlHandle ( child );
1895 }
1896
1897 return TiXmlHandle ( 0 );
1898 }
1899
1900
1901 TiXmlHandle TiXmlHandle::Child ( const char *value, int count ) const
1902 {
1903 if ( node )
1904 {
1905 int i;
1906 TiXmlNode *child = node->FirstChild ( value );
1907
1908 for ( i = 0;
1909 child && i < count;
1910 child = child->NextSibling ( value ), ++i )
1911 {
1912 // nothing
1913 }
1914
1915 if ( child )
1916 return TiXmlHandle ( child );
1917 }
1918
1919 return TiXmlHandle ( 0 );
1920 }
1921
1922
1923 TiXmlHandle TiXmlHandle::ChildElement ( int count ) const
1924 {
1925 if ( node )
1926 {
1927 int i;
1928 TiXmlElement *child = node->FirstChildElement();
1929
1930 for ( i = 0;
1931 child && i < count;
1932 child = child->NextSiblingElement(), ++i )
1933 {
1934 // nothing
1935 }
1936
1937 if ( child )
1938 return TiXmlHandle ( child );
1939 }
1940
1941 return TiXmlHandle ( 0 );
1942 }
1943
1944
1945 TiXmlHandle TiXmlHandle::ChildElement ( const char *value, int count ) const
1946 {
1947 if ( node )
1948 {
1949 int i;
1950 TiXmlElement *child = node->FirstChildElement ( value );
1951
1952 for ( i = 0;
1953 child && i < count;
1954 child = child->NextSiblingElement ( value ), ++i )
1955 {
1956 // nothing
1957 }
1958
1959 if ( child )
1960 return TiXmlHandle ( child );
1961 }
1962
1963 return TiXmlHandle ( 0 );
1964 }
1965
1966
1967 bool TiXmlPrinter::VisitEnter ( const TiXmlDocument & )
1968 {
1969 return true;
1970 }
1971
1972 bool TiXmlPrinter::VisitExit ( const TiXmlDocument & )
1973 {
1974 return true;
1975 }
1976
1977 bool TiXmlPrinter::VisitEnter ( const TiXmlElement &element, const TiXmlAttribute *firstAttribute )
1978 {
1979 DoIndent();
1980 buffer += "<";
1981 buffer += element.Value();
1982
1983 for ( const TiXmlAttribute *attrib = firstAttribute; attrib; attrib = attrib->Next() )
1984 {
1985 buffer += " ";
1986 attrib->Print ( 0, 0, &buffer );
1987 }
1988
1989 if ( !element.FirstChild() )
1990 {
1991 buffer += " />";
1992 DoLineBreak();
1993 }
1994 else
1995 {
1996 buffer += ">";
1997
1998 if ( element.FirstChild()->ToText()
1999 && element.LastChild() == element.FirstChild()
2000 && element.FirstChild()->ToText()->CDATA() == false )
2001 {
2002 simpleTextPrint = true;
2003 // no DoLineBreak()!
2004 }
2005 else
2006 {
2007 DoLineBreak();
2008 }
2009 }
2010
2011 ++depth;
2012 return true;
2013 }
2014
2015
2016 bool TiXmlPrinter::VisitExit ( const TiXmlElement &element )
2017 {
2018 --depth;
2019
2020 if ( !element.FirstChild() )
2021 {
2022 // nothing.
2023 }
2024 else
2025 {
2026 if ( simpleTextPrint )
2027 {
2028 simpleTextPrint = false;
2029 }
2030 else
2031 {
2032 DoIndent();
2033 }
2034
2035 buffer += "</";
2036 buffer += element.Value();
2037 buffer += ">";
2038 DoLineBreak();
2039 }
2040
2041 return true;
2042 }
2043
2044
2045 bool TiXmlPrinter::Visit ( const TiXmlText &text )
2046 {
2047 if ( text.CDATA() )
2048 {
2049 DoIndent();
2050 buffer += "<![CDATA[";
2051 buffer += text.Value();
2052 buffer += "]]>";
2053 DoLineBreak();
2054 }
2055 else if ( simpleTextPrint )
2056 {
2057 TIXML_STRING str;
2058 TiXmlBase::EncodeString ( text.ValueTStr(), &str );
2059 buffer += str;
2060 }
2061 else
2062 {
2063 DoIndent();
2064 TIXML_STRING str;
2065 TiXmlBase::EncodeString ( text.ValueTStr(), &str );
2066 buffer += str;
2067 DoLineBreak();
2068 }
2069
2070 return true;
2071 }
2072
2073
2074 bool TiXmlPrinter::Visit ( const TiXmlDeclaration &declaration )
2075 {
2076 DoIndent();
2077 declaration.Print ( 0, 0, &buffer );
2078 DoLineBreak();
2079 return true;
2080 }
2081
2082
2083 bool TiXmlPrinter::Visit ( const TiXmlComment &comment )
2084 {
2085 DoIndent();
2086 buffer += "<!--";
2087 buffer += comment.Value();
2088 buffer += "-->";
2089 DoLineBreak();
2090 return true;
2091 }
2092
2093
2094 bool TiXmlPrinter::Visit ( const TiXmlUnknown &unknown )
2095 {
2096 DoIndent();
2097 buffer += "<";
2098 buffer += unknown.Value();
2099 buffer += ">";
2100 DoLineBreak();
2101 return true;
2102 }