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