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