Date:2010-06-17 19:37:21 (3 years 10 months ago)
Author:Maarten ter Huurne
Commit:dae5627091bfb69f3336b35d8c78492d1f069beb
Message:Removed PXML support.

PXML is the metadata format for Pandora packages. It is not used on the
NanoNote or under Dingux.
Ideally it would be a compilation option, but without an active upstream it
would not receive any testing and therefore likely be broken. So in my
opinion it is more time efficient to remove it now and re-add if it is ever
wanted again.
Files: src/Makefile.am (3 diffs)
src/menu.cpp (4 diffs)
src/pxml.cpp (1 diff)
src/pxml.h (1 diff)
src/tinyxml/tinystr.cpp (1 diff)
src/tinyxml/tinystr.h (1 diff)
src/tinyxml/tinyxml.cpp (1 diff)
src/tinyxml/tinyxml.h (1 diff)
src/tinyxml/tinyxmlerror.cpp (1 diff)
src/tinyxml/tinyxmlparser.cpp (1 diff)

Change Details

src/Makefile.am
11bin_PROGRAMS = gmenu2x
2#
2
33gmenu2x_SOURCES = asfont.cpp button.cpp cpu.cpp dirdialog.cpp filedialog.cpp \
44    filelister.cpp gmenu2x.cpp iconbutton.cpp imagedialog.cpp inputdialog.cpp \
55    inputmanager.cpp linkaction.cpp linkapp.cpp link.cpp listviewitem.cpp \
66    menu.cpp menusettingbool.cpp menusetting.cpp menusettingdir.cpp \
77    menusettingfile.cpp menusettingimage.cpp menusettingint.cpp \
88    menusettingmultistring.cpp menusettingrgba.cpp menusettingstring.cpp \
9    messagebox.cpp pxml.cpp selector.cpp selectordetector.cpp \
9    messagebox.cpp selector.cpp selectordetector.cpp \
1010    settingsdialog.cpp sfontplus.cpp surfacecollection.cpp surface.cpp \
1111    textdialog.cpp textmanualdialog.cpp touchscreen.cpp translator.cpp \
12    utilities.cpp wallpaperdialog.cpp listview.cpp tinyxml/tinystr.cpp \
13    tinyxml/tinyxml.cpp tinyxml/tinyxmlerror.cpp tinyxml/tinyxmlparser.cpp \
12    utilities.cpp wallpaperdialog.cpp listview.cpp \
1413    browsedialog.cpp buttonbox.cpp dialog.cpp
1514
1615noinst_HEADERS = asfont.h button.h cpu.h dirdialog.h FastDelegate.h \
...... 
1918    listview.h listviewitem.h menu.h menusettingbool.h menusettingdir.h \
2019    menusettingfile.h menusetting.h menusettingimage.h menusettingint.h \
2120    menusettingmultistring.h menusettingrgba.h menusettingstring.h \
22    messagebox.h pxml.h selectordetector.h selector.h settingsdialog.h \
21    messagebox.h selectordetector.h selector.h settingsdialog.h \
2322    sfontplus.h surfacecollection.h surface.h textdialog.h textmanualdialog.h \
2423    touchscreen.h translator.h utilities.h wallpaperdialog.h \
25    tinyxml/tinystr.h tinyxml/tinyxml.h browsedialog.h buttonbox.h dialog.h
24    browsedialog.h buttonbox.h dialog.h
2625
2726AM_CFLAGS= @CFLAGS@ @SDL_CFLAGS@
2827
...... 
3029
3130gmenu2x_LDADD = @LIBS@ @SDL_LIBS@ -lfreetype -lSDL_image -lSDL_ttf -lSDL_gfx -lSDL -ljpeg -lpng12 -lz -ldl -lpthread
3231
33gmenu2x_LDFLAGS = -L./tinyxml -lfreetype -lSDL_image -lSDL_ttf -lSDL_gfx -lSDL -ljpeg -lpng12 -lz -ldl -lpthread
32gmenu2x_LDFLAGS = -lfreetype -lSDL_image -lSDL_ttf -lSDL_gfx -lSDL -ljpeg -lpng12 -lz -ldl -lpthread
3433
3534gmenu2x_LIBS = @LIBS@ @SDL_LIBS@ -lfreetype -lSDL_image -lSDL_ttf -lSDL_gfx -lSDL -ljpeg -lpng12 -lz -ldl -lpthread
src/menu.cpp
3030#include "menu.h"
3131#include "filelister.h"
3232#include "utilities.h"
33#include "pxml.h"
3433
3534using namespace std;
3635
...... 
185184    }
186185
187186    //if the extension is not equal to gpu or dge then enable the wrapepr by default
188    bool wrapper = false, pxml = false;
187    bool wrapper = false;
189188
190189    //strip the extension from the filename
191190    string title = file;
...... 
194193        string ext = title.substr(pos, title.length());
195194        transform(ext.begin(), ext.end(), ext.begin(), (int(*)(int)) tolower);
196195        if (ext == ".gpu" || ext == ".dge") wrapper = false;
197        else if (ext == ".pxml") pxml = true;
198196        title = title.substr(0, pos);
199197    }
200198
...... 
246244    cout << "\033[0;34mGMENU2X:\033[0m Manual: " << manual << endl;
247245#endif
248246
249    // Read pxml
250    string shorttitle="", description="", exec="", icon="";
251    if (pxml) {
252        PXml pxmlDoc(path+file);
253        if (pxmlDoc.isValid()) {
254            shorttitle = pxmlDoc.getTitle();
255            description = pxmlDoc.getDescription();
256            exec = pxmlDoc.getExec();
257            if (!exec.empty() && exec[0]!='/')
258                exec = path+exec;
259            icon = pxmlDoc.getIcon();
260            if (!icon.empty() && icon[0]!='/')
261                icon = path+icon;
262        } else {
263#ifdef DEBUG
264            cout << "\033[0;34mGMENU2X:\033[0m Error loading pxml " << file << ": " << pxmlDoc.getError() << endl;
265#endif
266            return false;
267        }
268    } else {
269        shorttitle = title;
270        exec = path+file;
271    }
247    string shorttitle=title, description="", exec=path+file, icon="";
272248
273249    //Reduce title lenght to fit the link width
274250    if (gmenu2x->font->getTextWidth(shorttitle)>gmenu2x->skinConfInt["linkWidth"]) {
src/pxml.cpp
1#include "pxml.h"
2#include "tinyxml/tinyxml.h"
3
4#include <sstream>
5
6using namespace std;
7
8PXml::PXml(string file) {
9    valid = false;
10    error = title = description = authorName = authorWebsite = category = exec = icon = "";
11    version = osVersion = (SoftwareVersion){0,0,0,0};
12
13    TiXmlDocument doc(file.c_str());
14    if (doc.LoadFile()) {
15        TiXmlHandle hDoc(&doc);
16        TiXmlElement* pElem;
17
18        pElem = hDoc.FirstChildElement().Element();
19        TiXmlHandle hPXML(pElem);
20        if (pElem) pElem = hPXML.FirstChildElement( "title" ).Element();
21        if (pElem) {
22            title = pElem->GetText();
23            pElem = hPXML.FirstChildElement( "description" ).Element();
24        }
25        if (pElem) {
26            description = pElem->GetText();
27            pElem = hPXML.FirstChildElement( "author" ).Element();
28        }
29        if (pElem) {
30            authorName = pElem->Attribute("name");
31            authorWebsite = pElem->Attribute("website");
32
33            pElem = hPXML.FirstChildElement( "version" ).Element();
34        }
35        if (pElem) {
36            pElem->QueryIntAttribute("major", &version.major);
37            pElem->QueryIntAttribute("minor", &version.minor);
38            pElem->QueryIntAttribute("release", &version.release);
39            pElem->QueryIntAttribute("build", &version.build);
40
41            pElem = hPXML.FirstChildElement( "exec" ).Element();
42        }
43        if (pElem) {
44            exec = pElem->GetText();
45
46            pElem = hPXML.FirstChildElement( "category" ).Element();
47        }
48        if (pElem) {
49            category = pElem->GetText();
50
51            valid = true;
52
53            //All required fields have been found, parsing optional fields
54            pElem = hPXML.FirstChildElement("icon").Element();
55            if (pElem) icon = pElem->GetText();
56
57            pElem = hPXML.FirstChildElement( "osversion" ).Element();
58            if (pElem) {
59                pElem->QueryIntAttribute("major", &osVersion.major);
60                pElem->QueryIntAttribute("minor", &osVersion.minor);
61                pElem->QueryIntAttribute("release", &osVersion.release);
62                pElem->QueryIntAttribute("build", &osVersion.build);
63            }
64        }
65    } else {
66        error = doc.ErrorDesc();
67    }
68}
69
70bool PXml::isValid() {
71    return valid;
72}
73
74string PXml::getTitle() {
75    return title;
76}
77
78string PXml::getDescription() {
79    return description;
80}
81
82string PXml::getAuthorName() {
83    return authorName;
84}
85
86string PXml::getAuthorWebsite() {
87    return authorWebsite;
88}
89
90string PXml::getCategory() {
91    return category;
92}
93
94string PXml::getExec() {
95    return exec;
96}
97
98string PXml::getIcon() {
99    return icon;
100}
101
102SoftwareVersion PXml::getVersion() {
103    return version;
104}
105
106string PXml::getVersionString() {
107    string versionString = "";
108    stringstream ss;
109    ss << version.major << "." << version.minor << "." << version.release << "." << version.build;
110    ss >> versionString;
111    return versionString;
112}
113
114SoftwareVersion PXml::getOsVersion() {
115    return osVersion;
116}
117
118string PXml::getOsVersionString() {
119    string versionString = "";
120    stringstream ss;
121    ss << osVersion.major << "." << osVersion.minor << "." << osVersion.release << "." << osVersion.build;
122    ss >> versionString;
123    return versionString;
124}
125
126string PXml::getError() {
127    return error;
128}
src/pxml.h
1/***************************************************************************
2 * Copyright (C) 2006 by Massimiliano Torromeo *
3 * massimiliano.torromeo@gmail.com *
4 * *
5 * This program is free software; you can redistribute it and/or modify *
6 * it under the terms of the GNU General Public License as published by *
7 * the Free Software Foundation; either version 2 of the License, or *
8 * (at your option) any later version. *
9 * *
10 * This program is distributed in the hope that it will be useful, *
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13 * GNU General Public License for more details. *
14 * *
15 * You should have received a copy of the GNU General Public License *
16 * along with this program; if not, write to the *
17 * Free Software Foundation, Inc., *
18 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19 ***************************************************************************/
20
21#ifndef PXML_H_
22#define PXML_H_
23
24#include <string>
25
26using std::string;
27
28struct SoftwareVersion {
29    int major, minor, release, build;
30};
31
32class PXml {
33private:
34    bool valid;
35    string title, description, error, authorName, authorWebsite, category, exec, icon;
36    SoftwareVersion version, osVersion;
37
38public:
39    PXml(string file);
40
41    bool isValid();
42
43    string getTitle();
44    string getDescription();
45    string getAuthorName();
46    string getAuthorWebsite();
47    string getCategory();
48    string getExec();
49    string getIcon();
50
51    SoftwareVersion getVersion();
52    string getVersionString();
53    SoftwareVersion getOsVersion();
54    string getOsVersionString();
55
56    string getError();
57};
58
59#endif /*PXML_H_*/
src/tinyxml/tinystr.cpp
1/*
2www.sourceforge.net/projects/tinyxml
3Original file by Yves Berquin.
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any
7damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any
10purpose, including commercial applications, and to alter it and
11redistribute it freely, subject to the following restrictions:
12
131. The origin of this software must not be misrepresented; you must
14not claim that you wrote the original software. If you use this
15software in a product, an acknowledgment in the product documentation
16would be appreciated but is not required.
17
182. Altered source versions must be plainly marked as such, and
19must not be misrepresented as being the original software.
20
213. This notice may not be removed or altered from any source
22distribution.
23*/
24
25/*
26 * THIS FILE WAS ALTERED BY Tyge LÝvset, 7. April 2005.
27 */
28
29
30#ifndef TIXML_USE_STL
31
32#include "tinystr.h"
33
34// Error value for find primitive
35const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
36
37
38// Null rep.
39TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
40
41
42void TiXmlString::reserve (size_type cap)
43{
44    if (cap > capacity())
45    {
46        TiXmlString tmp;
47        tmp.init(length(), cap);
48        memcpy(tmp.start(), data(), length());
49        swap(tmp);
50    }
51}
52
53
54TiXmlString& TiXmlString::assign(const char* str, size_type len)
55{
56    size_type cap = capacity();
57    if (len > cap || cap > 3*(len + 8))
58    {
59        TiXmlString tmp;
60        tmp.init(len);
61        memcpy(tmp.start(), str, len);
62        swap(tmp);
63    }
64    else
65    {
66        memmove(start(), str, len);
67        set_size(len);
68    }
69    return *this;
70}
71
72
73TiXmlString& TiXmlString::append(const char* str, size_type len)
74{
75    size_type newsize = length() + len;
76    if (newsize > capacity())
77    {
78        reserve (newsize + capacity());
79    }
80    memmove(finish(), str, len);
81    set_size(newsize);
82    return *this;
83}
84
85
86TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
87{
88    TiXmlString tmp;
89    tmp.reserve(a.length() + b.length());
90    tmp += a;
91    tmp += b;
92    return tmp;
93}
94
95TiXmlString operator + (const TiXmlString & a, const char* b)
96{
97    TiXmlString tmp;
98    TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
99    tmp.reserve(a.length() + b_len);
100    tmp += a;
101    tmp.append(b, b_len);
102    return tmp;
103}
104
105TiXmlString operator + (const char* a, const TiXmlString & b)
106{
107    TiXmlString tmp;
108    TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
109    tmp.reserve(a_len + b.length());
110    tmp.append(a, a_len);
111    tmp += b;
112    return tmp;
113}
114
115
116#endif // TIXML_USE_STL
src/tinyxml/tinystr.h
1/*
2www.sourceforge.net/projects/tinyxml
3Original file by Yves Berquin.
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any
7damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any
10purpose, including commercial applications, and to alter it and
11redistribute it freely, subject to the following restrictions:
12
131. The origin of this software must not be misrepresented; you must
14not claim that you wrote the original software. If you use this
15software in a product, an acknowledgment in the product documentation
16would be appreciated but is not required.
17
182. Altered source versions must be plainly marked as such, and
19must not be misrepresented as being the original software.
20
213. This notice may not be removed or altered from any source
22distribution.
23*/
24
25/*
26 * THIS FILE WAS ALTERED BY Tyge Lovset, 7. April 2005.
27 *
28 * - completely rewritten. compact, clean, and fast implementation.
29 * - sizeof(TiXmlString) = pointer size (4 bytes on 32-bit systems)
30 * - fixed reserve() to work as per specification.
31 * - fixed buggy compares operator==(), operator<(), and operator>()
32 * - fixed operator+=() to take a const ref argument, following spec.
33 * - added "copy" constructor with length, and most compare operators.
34 * - added swap(), clear(), size(), capacity(), operator+().
35 */
36
37#ifndef TIXML_USE_STL
38
39#ifndef TIXML_STRING_INCLUDED
40#define TIXML_STRING_INCLUDED
41
42#include <assert.h>
43#include <string.h>
44
45/* The support for explicit isn't that universal, and it isn't really
46    required - it is used to check that the TiXmlString class isn't incorrectly
47    used. Be nice to old compilers and macro it here:
48*/
49#if defined(_MSC_VER) && (_MSC_VER >= 1200 )
50    // Microsoft visual studio, version 6 and higher.
51    #define TIXML_EXPLICIT explicit
52#elif defined(__GNUC__) && (__GNUC__ >= 3 )
53    // GCC version 3 and higher.s
54    #define TIXML_EXPLICIT explicit
55#else
56    #define TIXML_EXPLICIT
57#endif
58
59
60/*
61   TiXmlString is an emulation of a subset of the std::string template.
62   Its purpose is to allow compiling TinyXML on compilers with no or poor STL support.
63   Only the member functions relevant to the TinyXML project have been implemented.
64   The buffer allocation is made by a simplistic power of 2 like mechanism : if we increase
65   a string and there's no more room, we allocate a buffer twice as big as we need.
66*/
67class TiXmlString
68{
69  public :
70    // The size type used
71      typedef size_t size_type;
72
73    // Error value for find primitive
74    static const size_type npos; // = -1;
75
76
77    // TiXmlString empty constructor
78    TiXmlString () : rep_(&nullrep_)
79    {
80    }
81
82    // TiXmlString copy constructor
83    TiXmlString ( const TiXmlString & copy) : rep_(0)
84    {
85        init(copy.length());
86        memcpy(start(), copy.data(), length());
87    }
88
89    // TiXmlString constructor, based on a string
90    TIXML_EXPLICIT TiXmlString ( const char * copy) : rep_(0)
91    {
92        init( static_cast<size_type>( strlen(copy) ));
93        memcpy(start(), copy, length());
94    }
95
96    // TiXmlString constructor, based on a string
97    TIXML_EXPLICIT TiXmlString ( const char * str, size_type len) : rep_(0)
98    {
99        init(len);
100        memcpy(start(), str, len);
101    }
102
103    // TiXmlString destructor
104    ~TiXmlString ()
105    {
106        quit();
107    }
108
109    // = operator
110    TiXmlString& operator = (const char * copy)
111    {
112        return assign( copy, (size_type)strlen(copy));
113    }
114
115    // = operator
116    TiXmlString& operator = (const TiXmlString & copy)
117    {
118        return assign(copy.start(), copy.length());
119    }
120
121
122    // += operator. Maps to append
123    TiXmlString& operator += (const char * suffix)
124    {
125        return append(suffix, static_cast<size_type>( strlen(suffix) ));
126    }
127
128    // += operator. Maps to append
129    TiXmlString& operator += (char single)
130    {
131        return append(&single, 1);
132    }
133
134    // += operator. Maps to append
135    TiXmlString& operator += (const TiXmlString & suffix)
136    {
137        return append(suffix.data(), suffix.length());
138    }
139
140
141    // Convert a TiXmlString into a null-terminated char *
142    const char * c_str () const { return rep_->str; }
143
144    // Convert a TiXmlString into a char * (need not be null terminated).
145    const char * data () const { return rep_->str; }
146
147    // Return the length of a TiXmlString
148    size_type length () const { return rep_->size; }
149
150    // Alias for length()
151    size_type size () const { return rep_->size; }
152
153    // Checks if a TiXmlString is empty
154    bool empty () const { return rep_->size == 0; }
155
156    // Return capacity of string
157    size_type capacity () const { return rep_->capacity; }
158
159
160    // single char extraction
161    const char& at (size_type index) const
162    {
163        assert( index < length() );
164        return rep_->str[ index ];
165    }
166
167    // [] operator
168    char& operator [] (size_type index) const
169    {
170        assert( index < length() );
171        return rep_->str[ index ];
172    }
173
174    // find a char in a string. Return TiXmlString::npos if not found
175    size_type find (char lookup) const
176    {
177        return find(lookup, 0);
178    }
179
180    // find a char in a string from an offset. Return TiXmlString::npos if not found
181    size_type find (char tofind, size_type offset) const
182    {
183        if (offset >= length()) return npos;
184
185        for (const char* p = c_str() + offset; *p != '\0'; ++p)
186        {
187           if (*p == tofind) return static_cast< size_type >( p - c_str() );
188        }
189        return npos;
190    }
191
192    void clear ()
193    {
194        //Lee:
195        //The original was just too strange, though correct:
196        // TiXmlString().swap(*this);
197        //Instead use the quit & re-init:
198        quit();
199        init(0,0);
200    }
201
202    /* Function to reserve a big amount of data when we know we'll need it. Be aware that this
203        function DOES NOT clear the content of the TiXmlString if any exists.
204    */
205    void reserve (size_type cap);
206
207    TiXmlString& assign (const char* str, size_type len);
208
209    TiXmlString& append (const char* str, size_type len);
210
211    void swap (TiXmlString& other)
212    {
213        Rep* r = rep_;
214        rep_ = other.rep_;
215        other.rep_ = r;
216    }
217
218  private:
219
220    void init(size_type sz) { init(sz, sz); }
221    void set_size(size_type sz) { rep_->str[ rep_->size = sz ] = '\0'; }
222    char* start() const { return rep_->str; }
223    char* finish() const { return rep_->str + rep_->size; }
224
225    struct Rep
226    {
227        size_type size, capacity;
228        char str[1];
229    };
230
231    void init(size_type sz, size_type cap)
232    {
233        if (cap)
234        {
235            // Lee: the original form:
236            // rep_ = static_cast<Rep*>(operator new(sizeof(Rep) + cap));
237            // doesn't work in some cases of new being overloaded. Switching
238            // to the normal allocation, although use an 'int' for systems
239            // that are overly picky about structure alignment.
240            const size_type bytesNeeded = sizeof(Rep) + cap;
241            const size_type intsNeeded = ( bytesNeeded + sizeof(int) - 1 ) / sizeof( int );
242            rep_ = reinterpret_cast<Rep*>( new int[ intsNeeded ] );
243
244            rep_->str[ rep_->size = sz ] = '\0';
245            rep_->capacity = cap;
246        }
247        else
248        {
249            rep_ = &nullrep_;
250        }
251    }
252
253    void quit()
254    {
255        if (rep_ != &nullrep_)
256        {
257            // The rep_ is really an array of ints. (see the allocator, above).
258            // Cast it back before delete, so the compiler won't incorrectly call destructors.
259            delete [] ( reinterpret_cast<int*>( rep_ ) );
260        }
261    }
262
263    Rep * rep_;
264    static Rep nullrep_;
265
266} ;
267
268
269inline bool operator == (const TiXmlString & a, const TiXmlString & b)
270{
271    return ( a.length() == b.length() ) // optimization on some platforms
272           && ( strcmp(a.c_str(), b.c_str()) == 0 ); // actual compare
273}
274inline bool operator < (const TiXmlString & a, const TiXmlString & b)
275{
276    return strcmp(a.c_str(), b.c_str()) < 0;
277}
278
279inline bool operator != (const TiXmlString & a, const TiXmlString & b) { return !(a == b); }
280inline bool operator > (const TiXmlString & a, const TiXmlString & b) { return b < a; }
281inline bool operator <= (const TiXmlString & a, const TiXmlString & b) { return !(b < a); }
282inline bool operator >= (const TiXmlString & a, const TiXmlString & b) { return !(a < b); }
283
284inline bool operator == (const TiXmlString & a, const char* b) { return strcmp(a.c_str(), b) == 0; }
285inline bool operator == (const char* a, const TiXmlString & b) { return b == a; }
286inline bool operator != (const TiXmlString & a, const char* b) { return !(a == b); }
287inline bool operator != (const char* a, const TiXmlString & b) { return !(b == a); }
288
289TiXmlString operator + (const TiXmlString & a, const TiXmlString & b);
290TiXmlString operator + (const TiXmlString & a, const char* b);
291TiXmlString operator + (const char* a, const TiXmlString & b);
292
293
294/*
295   TiXmlOutStream is an emulation of std::ostream. It is based on TiXmlString.
296   Only the operators that we need for TinyXML have been developped.
297*/
298class TiXmlOutStream : public TiXmlString
299{
300public :
301
302    // TiXmlOutStream << operator.
303    TiXmlOutStream & operator << (const TiXmlString & in)
304    {
305        *this += in;
306        return *this;
307    }
308
309    // TiXmlOutStream << operator.
310    TiXmlOutStream & operator << (const char * in)
311    {
312        *this += in;
313        return *this;
314    }
315
316} ;
317
318#endif // TIXML_STRING_INCLUDED
319#endif // TIXML_USE_STL
src/tinyxml/tinyxml.cpp
1/*
2www.sourceforge.net/projects/tinyxml
3Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any
7damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any
10purpose, including commercial applications, and to alter it and
11redistribute it freely, subject to the following restrictions:
12
131. The origin of this software must not be misrepresented; you must
14not claim that you wrote the original software. If you use this
15software in a product, an acknowledgment in the product documentation
16would be appreciated but is not required.
17
182. Altered source versions must be plainly marked as such, and
19must not be misrepresented as being the original software.
20
213. This notice may not be removed or altered from any source
22distribution.
23*/
24
25#include <ctype.h>
26
27#ifdef TIXML_USE_STL
28#include <sstream>
29#include <iostream>
30#endif
31
32#include "tinyxml.h"
33
34
35bool TiXmlBase::condenseWhiteSpace = true;
36
37// Microsoft compiler security
38FILE* TiXmlFOpen( const char* filename, const char* mode )
39{
40    #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
41        FILE* fp = 0;
42        errno_t err = fopen_s( &fp, filename, mode );
43        if ( !err && fp )
44            return fp;
45        return 0;
46    #else
47        return fopen( filename, mode );
48    #endif
49}
50
51void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
52{
53    int i=0;
54
55    while( i<(int)str.length() )
56    {
57        unsigned char c = (unsigned char) str[i];
58
59        if ( c == '&'
60             && i < ( (int)str.length() - 2 )
61             && str[i+1] == '#'
62             && str[i+2] == 'x' )
63        {
64            // Hexadecimal character reference.
65            // Pass through unchanged.
66            // &#xA9; -- copyright symbol, for example.
67            //
68            // The -1 is a bug fix from Rob Laveaux. It keeps
69            // an overflow from happening if there is no ';'.
70            // There are actually 2 ways to exit this loop -
71            // while fails (error case) and break (semicolon found).
72            // However, there is no mechanism (currently) for
73            // this function to return an error.
74            while ( i<(int)str.length()-1 )
75            {
76                outString->append( str.c_str() + i, 1 );
77                ++i;
78                if ( str[i] == ';' )
79                    break;
80            }
81        }
82        else if ( c == '&' )
83        {
84            outString->append( entity[0].str, entity[0].strLength );
85            ++i;
86        }
87        else if ( c == '<' )
88        {
89            outString->append( entity[1].str, entity[1].strLength );
90            ++i;
91        }
92        else if ( c == '>' )
93        {
94            outString->append( entity[2].str, entity[2].strLength );
95            ++i;
96        }
97        else if ( c == '\"' )
98        {
99            outString->append( entity[3].str, entity[3].strLength );
100            ++i;
101        }
102        else if ( c == '\'' )
103        {
104            outString->append( entity[4].str, entity[4].strLength );
105            ++i;
106        }
107        else if ( c < 32 )
108        {
109            // Easy pass at non-alpha/numeric/symbol
110            // Below 32 is symbolic.
111            char buf[ 32 ];
112
113            #if defined(TIXML_SNPRINTF)
114                TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
115            #else
116                sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
117            #endif
118
119            //*ME: warning C4267: convert 'size_t' to 'int'
120            //*ME: Int-Cast to make compiler happy ...
121            outString->append( buf, (int)strlen( buf ) );
122            ++i;
123        }
124        else
125        {
126            //char realc = (char) c;
127            //outString->append( &realc, 1 );
128            *outString += (char) c; // somewhat more efficient function call.
129            ++i;
130        }
131    }
132}
133
134
135TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
136{
137    parent = 0;
138    type = _type;
139    firstChild = 0;
140    lastChild = 0;
141    prev = 0;
142    next = 0;
143}
144
145
146TiXmlNode::~TiXmlNode()
147{
148    TiXmlNode* node = firstChild;
149    TiXmlNode* temp = 0;
150
151    while ( node )
152    {
153        temp = node;
154        node = node->next;
155        delete temp;
156    }
157}
158
159
160void TiXmlNode::CopyTo( TiXmlNode* target ) const
161{
162    target->SetValue (value.c_str() );
163    target->userData = userData;
164}
165
166
167void TiXmlNode::Clear()
168{
169    TiXmlNode* node = firstChild;
170    TiXmlNode* temp = 0;
171
172    while ( node )
173    {
174        temp = node;
175        node = node->next;
176        delete temp;
177    }
178
179    firstChild = 0;
180    lastChild = 0;
181}
182
183
184TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
185{
186    assert( node->parent == 0 || node->parent == this );
187    assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
188
189    if ( node->Type() == TiXmlNode::DOCUMENT )
190    {
191        delete node;
192        if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
193        return 0;
194    }
195
196    node->parent = this;
197
198    node->prev = lastChild;
199    node->next = 0;
200
201    if ( lastChild )
202        lastChild->next = node;
203    else
204        firstChild = node; // it was an empty list.
205
206    lastChild = node;
207    return node;
208}
209
210
211TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
212{
213    if ( addThis.Type() == TiXmlNode::DOCUMENT )
214    {
215        if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
216        return 0;
217    }
218    TiXmlNode* node = addThis.Clone();
219    if ( !node )
220        return 0;
221
222    return LinkEndChild( node );
223}
224
225
226TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
227{
228    if ( !beforeThis || beforeThis->parent != this ) {
229        return 0;
230    }
231    if ( addThis.Type() == TiXmlNode::DOCUMENT )
232    {
233        if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
234        return 0;
235    }
236
237    TiXmlNode* node = addThis.Clone();
238    if ( !node )
239        return 0;
240    node->parent = this;
241
242    node->next = beforeThis;
243    node->prev = beforeThis->prev;
244    if ( beforeThis->prev )
245    {
246        beforeThis->prev->next = node;
247    }
248    else
249    {
250        assert( firstChild == beforeThis );
251        firstChild = node;
252    }
253    beforeThis->prev = node;
254    return node;
255}
256
257
258TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
259{
260    if ( !afterThis || afterThis->parent != this ) {
261        return 0;
262    }
263    if ( addThis.Type() == TiXmlNode::DOCUMENT )
264    {
265        if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
266        return 0;
267    }
268
269    TiXmlNode* node = addThis.Clone();
270    if ( !node )
271        return 0;
272    node->parent = this;
273
274    node->prev = afterThis;
275    node->next = afterThis->next;
276    if ( afterThis->next )
277    {
278        afterThis->next->prev = node;
279    }
280    else
281    {
282        assert( lastChild == afterThis );
283        lastChild = node;
284    }
285    afterThis->next = node;
286    return node;
287}
288
289
290TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
291{
292    if ( replaceThis->parent != this )
293        return 0;
294
295    TiXmlNode* node = withThis.Clone();
296    if ( !node )
297        return 0;
298
299    node->next = replaceThis->next;
300    node->prev = replaceThis->prev;
301
302    if ( replaceThis->next )
303        replaceThis->next->prev = node;
304    else
305        lastChild = node;
306
307    if ( replaceThis->prev )
308        replaceThis->prev->next = node;
309    else
310        firstChild = node;
311
312    delete replaceThis;
313    node->parent = this;
314    return node;
315}
316
317
318bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
319{
320    if ( removeThis->parent != this )
321    {
322        assert( 0 );
323        return false;
324    }
325
326    if ( removeThis->next )
327        removeThis->next->prev = removeThis->prev;
328    else
329        lastChild = removeThis->prev;
330
331    if ( removeThis->prev )
332        removeThis->prev->next = removeThis->next;
333    else
334        firstChild = removeThis->next;
335
336    delete removeThis;
337    return true;
338}
339
340const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
341{
342    const TiXmlNode* node;
343    for ( node = firstChild; node; node = node->next )
344    {
345        if ( strcmp( node->Value(), _value ) == 0 )
346            return node;
347    }
348    return 0;
349}
350
351
352const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
353{
354    const TiXmlNode* node;
355    for ( node = lastChild; node; node = node->prev )
356    {
357        if ( strcmp( node->Value(), _value ) == 0 )
358            return node;
359    }
360    return 0;
361}
362
363
364const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
365{
366    if ( !previous )
367    {
368        return FirstChild();
369    }
370    else
371    {
372        assert( previous->parent == this );
373        return previous->NextSibling();
374    }
375}
376
377
378const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
379{
380    if ( !previous )
381    {
382        return FirstChild( val );
383    }
384    else
385    {
386        assert( previous->parent == this );
387        return previous->NextSibling( val );
388    }
389}
390
391
392const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
393{
394    const TiXmlNode* node;
395    for ( node = next; node; node = node->next )
396    {
397        if ( strcmp( node->Value(), _value ) == 0 )
398            return node;
399    }
400    return 0;
401}
402
403
404const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
405{
406    const TiXmlNode* node;
407    for ( node = prev; node; node = node->prev )
408    {
409        if ( strcmp( node->Value(), _value ) == 0 )
410            return node;
411    }
412    return 0;
413}
414
415
416void TiXmlElement::RemoveAttribute( const char * name )
417{
418    #ifdef TIXML_USE_STL
419    TIXML_STRING str( name );
420    TiXmlAttribute* node = attributeSet.Find( str );
421    #else
422    TiXmlAttribute* node = attributeSet.Find( name );
423    #endif
424    if ( node )
425    {
426        attributeSet.Remove( node );
427        delete node;
428    }
429}
430
431const TiXmlElement* TiXmlNode::FirstChildElement() const
432{
433    const TiXmlNode* node;
434
435    for ( node = FirstChild();
436            node;
437            node = node->NextSibling() )
438    {
439        if ( node->ToElement() )
440            return node->ToElement();
441    }
442    return 0;
443}
444
445
446const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
447{
448    const TiXmlNode* node;
449
450    for ( node = FirstChild( _value );
451            node;
452            node = node->NextSibling( _value ) )
453    {
454        if ( node->ToElement() )
455            return node->ToElement();
456    }
457    return 0;
458}
459
460
461const TiXmlElement* TiXmlNode::NextSiblingElement() const
462{
463    const TiXmlNode* node;
464
465    for ( node = NextSibling();
466            node;
467            node = node->NextSibling() )
468    {
469        if ( node->ToElement() )
470            return node->ToElement();
471    }
472    return 0;
473}
474
475
476const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
477{
478    const TiXmlNode* node;
479
480    for ( node = NextSibling( _value );
481            node;
482            node = node->NextSibling( _value ) )
483    {
484        if ( node->ToElement() )
485            return node->ToElement();
486    }
487    return 0;
488}
489
490
491const TiXmlDocument* TiXmlNode::GetDocument() const
492{
493    const TiXmlNode* node;
494
495    for( node = this; node; node = node->parent )
496    {
497        if ( node->ToDocument() )
498            return node->ToDocument();
499    }
500    return 0;
501}
502
503
504TiXmlElement::TiXmlElement (const char * _value)
505    : TiXmlNode( TiXmlNode::ELEMENT )
506{
507    firstChild = lastChild = 0;
508    value = _value;
509}
510
511
512#ifdef TIXML_USE_STL
513TiXmlElement::TiXmlElement( const std::string& _value )
514    : TiXmlNode( TiXmlNode::ELEMENT )
515{
516    firstChild = lastChild = 0;
517    value = _value;
518}
519#endif
520
521
522TiXmlElement::TiXmlElement( const TiXmlElement& copy)
523    : TiXmlNode( TiXmlNode::ELEMENT )
524{
525    firstChild = lastChild = 0;
526    copy.CopyTo( this );
527}
528
529
530void TiXmlElement::operator=( const TiXmlElement& base )
531{
532    ClearThis();
533    base.CopyTo( this );
534}
535
536
537TiXmlElement::~TiXmlElement()
538{
539    ClearThis();
540}
541
542
543void TiXmlElement::ClearThis()
544{
545    Clear();
546    while( attributeSet.First() )
547    {
548        TiXmlAttribute* node = attributeSet.First();
549        attributeSet.Remove( node );
550        delete node;
551    }
552}
553
554
555const char* TiXmlElement::Attribute( const char* name ) const
556{
557    const TiXmlAttribute* node = attributeSet.Find( name );
558    if ( node )
559        return node->Value();
560    return 0;
561}
562
563
564#ifdef TIXML_USE_STL
565const std::string* TiXmlElement::Attribute( const std::string& name ) const
566{
567    const TiXmlAttribute* node = attributeSet.Find( name );
568    if ( node )
569        return &node->ValueStr();
570    return 0;
571}
572#endif
573
574
575const char* TiXmlElement::Attribute( const char* name, int* i ) const
576{
577    const char* s = Attribute( name );
578    if ( i )
579    {
580        if ( s ) {
581            *i = atoi( s );
582        }
583        else {
584            *i = 0;
585        }
586    }
587    return s;
588}
589
590
591#ifdef TIXML_USE_STL
592const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
593{
594    const std::string* s = Attribute( name );
595    if ( i )
596    {
597        if ( s ) {
598            *i = atoi( s->c_str() );
599        }
600        else {
601            *i = 0;
602        }
603    }
604    return s;
605}
606#endif
607
608
609const char* TiXmlElement::Attribute( const char* name, double* d ) const
610{
611    const char* s = Attribute( name );
612    if ( d )
613    {
614        if ( s ) {
615            *d = atof( s );
616        }
617        else {
618            *d = 0;
619        }
620    }
621    return s;
622}
623
624
625#ifdef TIXML_USE_STL
626const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
627{
628    const std::string* s = Attribute( name );
629    if ( d )
630    {
631        if ( s ) {
632            *d = atof( s->c_str() );
633        }
634        else {
635            *d = 0;
636        }
637    }
638    return s;
639}
640#endif
641
642
643int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
644{
645    const TiXmlAttribute* node = attributeSet.Find( name );
646    if ( !node )
647        return TIXML_NO_ATTRIBUTE;
648    return node->QueryIntValue( ival );
649}
650
651
652#ifdef TIXML_USE_STL
653int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
654{
655    const TiXmlAttribute* node = attributeSet.Find( name );
656    if ( !node )
657        return TIXML_NO_ATTRIBUTE;
658    return node->QueryIntValue( ival );
659}
660#endif
661
662
663int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
664{
665    const TiXmlAttribute* node = attributeSet.Find( name );
666    if ( !node )
667        return TIXML_NO_ATTRIBUTE;
668    return node->QueryDoubleValue( dval );
669}
670
671
672#ifdef TIXML_USE_STL
673int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
674{
675    const TiXmlAttribute* node = attributeSet.Find( name );
676    if ( !node )
677        return TIXML_NO_ATTRIBUTE;
678    return node->QueryDoubleValue( dval );
679}
680#endif
681
682
683void TiXmlElement::SetAttribute( const char * name, int val )
684{
685    char buf[64];
686    #if defined(TIXML_SNPRINTF)
687        TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
688    #else
689        sprintf( buf, "%d", val );
690    #endif
691    SetAttribute( name, buf );
692}
693
694
695#ifdef TIXML_USE_STL
696void TiXmlElement::SetAttribute( const std::string& name, int val )
697{
698   std::ostringstream oss;
699   oss << val;
700   SetAttribute( name, oss.str() );
701}
702#endif
703
704
705void TiXmlElement::SetDoubleAttribute( const char * name, double val )
706{
707    char buf[256];
708    #if defined(TIXML_SNPRINTF)
709        TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
710    #else
711        sprintf( buf, "%f", val );
712    #endif
713    SetAttribute( name, buf );
714}
715
716
717void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
718{
719    #ifdef TIXML_USE_STL
720    TIXML_STRING _name( cname );
721    TIXML_STRING _value( cvalue );
722    #else
723    const char* _name = cname;
724    const char* _value = cvalue;
725    #endif
726
727    TiXmlAttribute* node = attributeSet.Find( _name );
728    if ( node )
729    {
730        node->SetValue( _value );
731        return;
732    }
733
734    TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue );
735    if ( attrib )
736    {
737        attributeSet.Add( attrib );
738    }
739    else
740    {
741        TiXmlDocument* document = GetDocument();
742        if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
743    }
744}
745
746
747#ifdef TIXML_USE_STL
748void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value )
749{
750    TiXmlAttribute* node = attributeSet.Find( name );
751    if ( node )
752    {
753        node->SetValue( _value );
754        return;
755    }
756
757    TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
758    if ( attrib )
759    {
760        attributeSet.Add( attrib );
761    }
762    else
763    {
764        TiXmlDocument* document = GetDocument();
765        if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
766    }
767}
768#endif
769
770
771void TiXmlElement::Print( FILE* cfile, int depth ) const
772{
773    int i;
774    assert( cfile );
775    for ( i=0; i<depth; i++ ) {
776        fprintf( cfile, " " );
777    }
778
779    fprintf( cfile, "<%s", value.c_str() );
780
781    const TiXmlAttribute* attrib;
782    for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
783    {
784        fprintf( cfile, " " );
785        attrib->Print( cfile, depth );
786    }
787
788    // There are 3 different formatting approaches:
789    // 1) An element without children is printed as a <foo /> node
790    // 2) An element with only a text child is printed as <foo> text </foo>
791    // 3) An element with children is printed on multiple lines.
792    TiXmlNode* node;
793    if ( !firstChild )
794    {
795        fprintf( cfile, " />" );
796    }
797    else if ( firstChild == lastChild && firstChild->ToText() )
798    {
799        fprintf( cfile, ">" );
800        firstChild->Print( cfile, depth + 1 );
801        fprintf( cfile, "</%s>", value.c_str() );
802    }
803    else
804    {
805        fprintf( cfile, ">" );
806
807        for ( node = firstChild; node; node=node->NextSibling() )
808        {
809            if ( !node->ToText() )
810            {
811                fprintf( cfile, "\n" );
812            }
813            node->Print( cfile, depth+1 );
814        }
815        fprintf( cfile, "\n" );
816        for( i=0; i<depth; ++i ) {
817            fprintf( cfile, " " );
818        }
819        fprintf( cfile, "</%s>", value.c_str() );
820    }
821}
822
823
824void TiXmlElement::CopyTo( TiXmlElement* target ) const
825{
826    // superclass:
827    TiXmlNode::CopyTo( target );
828
829    // Element class:
830    // Clone the attributes, then clone the children.
831    const TiXmlAttribute* attribute = 0;
832    for( attribute = attributeSet.First();
833    attribute;
834    attribute = attribute->Next() )
835    {
836        target->SetAttribute( attribute->Name(), attribute->Value() );
837    }
838
839    TiXmlNode* node = 0;
840    for ( node = firstChild; node; node = node->NextSibling() )
841    {
842        target->LinkEndChild( node->Clone() );
843    }
844}
845
846bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
847{
848    if ( visitor->VisitEnter( *this, attributeSet.First() ) )
849    {
850        for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
851        {
852            if ( !node->Accept( visitor ) )
853                break;
854        }
855    }
856    return visitor->VisitExit( *this );
857}
858
859
860TiXmlNode* TiXmlElement::Clone() const
861{
862    TiXmlElement* clone = new TiXmlElement( Value() );
863    if ( !clone )
864        return 0;
865
866    CopyTo( clone );
867    return clone;
868}
869
870
871const char* TiXmlElement::GetText() const
872{
873    const TiXmlNode* child = this->FirstChild();
874    if ( child ) {
875        const TiXmlText* childText = child->ToText();
876        if ( childText ) {
877            return childText->Value();
878        }
879    }
880    return 0;
881}
882
883
884TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
885{
886    tabsize = 4;
887    useMicrosoftBOM = false;
888    ClearError();
889}
890
891TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
892{
893    tabsize = 4;
894    useMicrosoftBOM = false;
895    value = documentName;
896    ClearError();
897}
898
899
900#ifdef TIXML_USE_STL
901TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
902{
903    tabsize = 4;
904    useMicrosoftBOM = false;
905    value = documentName;
906    ClearError();
907}
908#endif
909
910
911TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
912{
913    copy.CopyTo( this );
914}
915
916
917void TiXmlDocument::operator=( const TiXmlDocument& copy )
918{
919    Clear();
920    copy.CopyTo( this );
921}
922
923
924bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
925{
926    // See STL_STRING_BUG below.
927    //StringToBuffer buf( value );
928
929    return LoadFile( Value(), encoding );
930}
931
932
933bool TiXmlDocument::SaveFile() const
934{
935    // See STL_STRING_BUG below.
936// StringToBuffer buf( value );
937//
938// if ( buf.buffer && SaveFile( buf.buffer ) )
939// return true;
940//
941// return false;
942    return SaveFile( Value() );
943}
944
945bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
946{
947    // There was a really terrifying little bug here. The code:
948    // value = filename
949    // in the STL case, cause the assignment method of the std::string to
950    // be called. What is strange, is that the std::string had the same
951    // address as it's c_str() method, and so bad things happen. Looks
952    // like a bug in the Microsoft STL implementation.
953    // Add an extra string to avoid the crash.
954    TIXML_STRING filename( _filename );
955    value = filename;
956
957    // reading in binary mode so that tinyxml can normalize the EOL
958    FILE* file = TiXmlFOpen( value.c_str (), "rb" );
959
960    if ( file )
961    {
962        bool result = LoadFile( file, encoding );
963        fclose( file );
964        return result;
965    }
966    else
967    {
968        SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
969        return false;
970    }
971}
972
973bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
974{
975    if ( !file )
976    {
977        SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
978        return false;
979    }
980
981    // Delete the existing data:
982    Clear();
983    location.Clear();
984
985    // Get the file size, so we can pre-allocate the string. HUGE speed impact.
986    long length = 0;
987    fseek( file, 0, SEEK_END );
988    length = ftell( file );
989    fseek( file, 0, SEEK_SET );
990
991    // Strange case, but good to handle up front.
992    if ( length <= 0 )
993    {
994        SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
995        return false;
996    }
997
998    // If we have a file, assume it is all one big XML file, and read it in.
999    // The document parser may decide the document ends sooner than the entire file, however.
1000    TIXML_STRING data;
1001    data.reserve( length );
1002
1003    // Subtle bug here. TinyXml did use fgets. But from the XML spec:
1004    // 2.11 End-of-Line Handling
1005    // <snip>
1006    // <quote>
1007    // ...the XML processor MUST behave as if it normalized all line breaks in external
1008    // parsed entities (including the document entity) on input, before parsing, by translating
1009    // both the two-character sequence #xD #xA and any #xD that is not followed by #xA to
1010    // a single #xA character.
1011    // </quote>
1012    //
1013    // It is not clear fgets does that, and certainly isn't clear it works cross platform.
1014    // Generally, you expect fgets to translate from the convention of the OS to the c/unix
1015    // convention, and not work generally.
1016
1017    /*
1018    while( fgets( buf, sizeof(buf), file ) )
1019    {
1020        data += buf;
1021    }
1022    */
1023
1024    char* buf = new char[ length+1 ];
1025    buf[0] = 0;
1026
1027    if ( fread( buf, length, 1, file ) != 1 ) {
1028        delete [] buf;
1029        SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
1030        return false;
1031    }
1032
1033    const char* lastPos = buf;
1034    const char* p = buf;
1035
1036    buf[length] = 0;
1037    while( *p ) {
1038        assert( p < (buf+length) );
1039        if ( *p == 0xa ) {
1040            // Newline character. No special rules for this. Append all the characters
1041            // since the last string, and include the newline.
1042            data.append( lastPos, (p-lastPos+1) ); // append, include the newline
1043            ++p; // move past the newline
1044            lastPos = p; // and point to the new buffer (may be 0)
1045            assert( p <= (buf+length) );
1046        }
1047        else if ( *p == 0xd ) {
1048            // Carriage return. Append what we have so far, then
1049            // handle moving forward in the buffer.
1050            if ( (p-lastPos) > 0 ) {
1051                data.append( lastPos, p-lastPos ); // do not add the CR
1052            }
1053            data += (char)0xa; // a proper newline
1054
1055            if ( *(p+1) == 0xa ) {
1056                // Carriage return - new line sequence
1057                p += 2;
1058                lastPos = p;
1059                assert( p <= (buf+length) );
1060            }
1061            else {
1062                // it was followed by something else...that is presumably characters again.
1063                ++p;
1064                lastPos = p;
1065                assert( p <= (buf+length) );
1066            }
1067        }
1068        else {
1069            ++p;
1070        }
1071    }
1072    // Handle any left over characters.
1073    if ( p-lastPos ) {
1074        data.append( lastPos, p-lastPos );
1075    }
1076    delete [] buf;
1077    buf = 0;
1078
1079    Parse( data.c_str(), 0, encoding );
1080
1081    if ( Error() )
1082        return false;
1083    else
1084        return true;
1085}
1086
1087
1088bool TiXmlDocument::SaveFile( const char * filename ) const
1089{
1090    // The old c stuff lives on...
1091    FILE* fp = TiXmlFOpen( filename, "w" );
1092    if ( fp )
1093    {
1094        bool result = SaveFile( fp );
1095        fclose( fp );
1096        return result;
1097    }
1098    return false;
1099}
1100
1101
1102bool TiXmlDocument::SaveFile( FILE* fp ) const
1103{
1104    if ( useMicrosoftBOM )
1105    {
1106        const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
1107        const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
1108        const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
1109
1110        fputc( TIXML_UTF_LEAD_0, fp );
1111        fputc( TIXML_UTF_LEAD_1, fp );
1112        fputc( TIXML_UTF_LEAD_2, fp );
1113    }
1114    Print( fp, 0 );
1115    return (ferror(fp) == 0);
1116}
1117
1118
1119void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
1120{
1121    TiXmlNode::CopyTo( target );
1122
1123    target->error = error;
1124    target->errorId = errorId;
1125    target->errorDesc = errorDesc;
1126    target->tabsize = tabsize;
1127    target->errorLocation = errorLocation;
1128    target->useMicrosoftBOM = useMicrosoftBOM;
1129
1130    TiXmlNode* node = 0;
1131    for ( node = firstChild; node; node = node->NextSibling() )
1132    {
1133        target->LinkEndChild( node->Clone() );
1134    }
1135}
1136
1137
1138TiXmlNode* TiXmlDocument::Clone() const
1139{
1140    TiXmlDocument* clone = new TiXmlDocument();
1141    if ( !clone )
1142        return 0;
1143
1144    CopyTo( clone );
1145    return clone;
1146}
1147
1148
1149void TiXmlDocument::Print( FILE* cfile, int depth ) const
1150{
1151    assert( cfile );
1152    for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
1153    {
1154        node->Print( cfile, depth );
1155        fprintf( cfile, "\n" );
1156    }
1157}
1158
1159
1160bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
1161{
1162    if ( visitor->VisitEnter( *this ) )
1163    {
1164        for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
1165        {
1166            if ( !node->Accept( visitor ) )
1167                break;
1168        }
1169    }
1170    return visitor->VisitExit( *this );
1171}
1172
1173
1174const TiXmlAttribute* TiXmlAttribute::Next() const
1175{
1176    // We are using knowledge of the sentinel. The sentinel
1177    // have a value or name.
1178    if ( next->value.empty() && next->name.empty() )
1179        return 0;
1180    return next;
1181}
1182
1183/*
1184TiXmlAttribute* TiXmlAttribute::Next()
1185{
1186    // We are using knowledge of the sentinel. The sentinel
1187    // have a value or name.
1188    if ( next->value.empty() && next->name.empty() )
1189        return 0;
1190    return next;
1191}
1192*/
1193
1194const TiXmlAttribute* TiXmlAttribute::Previous() const
1195{
1196    // We are using knowledge of the sentinel. The sentinel
1197    // have a value or name.
1198    if ( prev->value.empty() && prev->name.empty() )
1199        return 0;
1200    return prev;
1201}
1202
1203/*
1204TiXmlAttribute* TiXmlAttribute::Previous()
1205{
1206    // We are using knowledge of the sentinel. The sentinel
1207    // have a value or name.
1208    if ( prev->value.empty() && prev->name.empty() )
1209        return 0;
1210    return prev;
1211}
1212*/
1213
1214void TiXmlAttribute::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
1215{
1216    TIXML_STRING n, v;
1217
1218    EncodeString( name, &n );
1219    EncodeString( value, &v );
1220
1221    if (value.find ('\"') == TIXML_STRING::npos) {
1222        if ( cfile ) {
1223        fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
1224        }
1225        if ( str ) {
1226            (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
1227        }
1228    }
1229    else {
1230        if ( cfile ) {
1231        fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
1232        }
1233        if ( str ) {
1234            (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
1235        }
1236    }
1237}
1238
1239
1240int TiXmlAttribute::QueryIntValue( int* ival ) const
1241{
1242    if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
1243        return TIXML_SUCCESS;
1244    return TIXML_WRONG_TYPE;
1245}
1246
1247int TiXmlAttribute::QueryDoubleValue( double* dval ) const
1248{
1249    if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
1250        return TIXML_SUCCESS;
1251    return TIXML_WRONG_TYPE;
1252}
1253
1254void TiXmlAttribute::SetIntValue( int _value )
1255{
1256    char buf [64];
1257    #if defined(TIXML_SNPRINTF)
1258        TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
1259    #else
1260        sprintf (buf, "%d", _value);
1261    #endif
1262    SetValue (buf);
1263}
1264
1265void TiXmlAttribute::SetDoubleValue( double _value )
1266{
1267    char buf [256];
1268    #if defined(TIXML_SNPRINTF)
1269        TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
1270    #else
1271        sprintf (buf, "%lf", _value);
1272    #endif
1273    SetValue (buf);
1274}
1275
1276int TiXmlAttribute::IntValue() const
1277{
1278    return atoi (value.c_str ());
1279}
1280
1281double TiXmlAttribute::DoubleValue() const
1282{
1283    return atof (value.c_str ());
1284}
1285
1286
1287TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
1288{
1289    copy.CopyTo( this );
1290}
1291
1292
1293void TiXmlComment::operator=( const TiXmlComment& base )
1294{
1295    Clear();
1296    base.CopyTo( this );
1297}
1298
1299
1300void TiXmlComment::Print( FILE* cfile, int depth ) const
1301{
1302    assert( cfile );
1303    for ( int i=0; i<depth; i++ )
1304    {
1305        fprintf( cfile, " " );
1306    }
1307    fprintf( cfile, "<!--%s-->", value.c_str() );
1308}
1309
1310
1311void TiXmlComment::CopyTo( TiXmlComment* target ) const
1312{
1313    TiXmlNode::CopyTo( target );
1314}
1315
1316
1317bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
1318{
1319    return visitor->Visit( *this );
1320}
1321
1322
1323TiXmlNode* TiXmlComment::Clone() const
1324{
1325    TiXmlComment* clone = new TiXmlComment();
1326
1327    if ( !clone )
1328        return 0;
1329
1330    CopyTo( clone );
1331    return clone;
1332}
1333
1334
1335void TiXmlText::Print( FILE* cfile, int depth ) const
1336{
1337    assert( cfile );
1338    if ( cdata )
1339    {
1340        int i;
1341        fprintf( cfile, "\n" );
1342        for ( i=0; i<depth; i++ ) {
1343            fprintf( cfile, " " );
1344        }
1345        fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() ); // unformatted output
1346    }
1347    else
1348    {
1349        TIXML_STRING buffer;
1350        EncodeString( value, &buffer );
1351        fprintf( cfile, "%s", buffer.c_str() );
1352    }
1353}
1354
1355
1356void TiXmlText::CopyTo( TiXmlText* target ) const
1357{
1358    TiXmlNode::CopyTo( target );
1359    target->cdata = cdata;
1360}
1361
1362
1363bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
1364{
1365    return visitor->Visit( *this );
1366}
1367
1368
1369TiXmlNode* TiXmlText::Clone() const
1370{
1371    TiXmlText* clone = 0;
1372    clone = new TiXmlText( "" );
1373
1374    if ( !clone )
1375        return 0;
1376
1377    CopyTo( clone );
1378    return clone;
1379}
1380
1381
1382TiXmlDeclaration::TiXmlDeclaration( const char * _version,
1383                                    const char * _encoding,
1384                                    const char * _standalone )
1385    : TiXmlNode( TiXmlNode::DECLARATION )
1386{
1387    version = _version;
1388    encoding = _encoding;
1389    standalone = _standalone;
1390}
1391
1392
1393#ifdef TIXML_USE_STL
1394TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
1395                                    const std::string& _encoding,
1396                                    const std::string& _standalone )
1397    : TiXmlNode( TiXmlNode::DECLARATION )
1398{
1399    version = _version;
1400    encoding = _encoding;
1401    standalone = _standalone;
1402}
1403#endif
1404
1405
1406TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
1407    : TiXmlNode( TiXmlNode::DECLARATION )
1408{
1409    copy.CopyTo( this );
1410}
1411
1412
1413void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
1414{
1415    Clear();
1416    copy.CopyTo( this );
1417}
1418
1419
1420void TiXmlDeclaration::Print( FILE* cfile, int /*depth*/, TIXML_STRING* str ) const
1421{
1422    if ( cfile ) fprintf( cfile, "<?xml " );
1423    if ( str ) (*str) += "<?xml ";
1424
1425    if ( !version.empty() ) {
1426        if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
1427        if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
1428    }
1429    if ( !encoding.empty() ) {
1430        if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
1431        if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
1432    }
1433    if ( !standalone.empty() ) {
1434        if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
1435        if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
1436    }
1437    if ( cfile ) fprintf( cfile, "?>" );
1438    if ( str ) (*str) += "?>";
1439}
1440
1441
1442void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
1443{
1444    TiXmlNode::CopyTo( target );
1445
1446    target->version = version;
1447    target->encoding = encoding;
1448    target->standalone = standalone;
1449}
1450
1451
1452bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
1453{
1454    return visitor->Visit( *this );
1455}
1456
1457
1458TiXmlNode* TiXmlDeclaration::Clone() const
1459{
1460    TiXmlDeclaration* clone = new TiXmlDeclaration();
1461
1462    if ( !clone )
1463        return 0;
1464
1465    CopyTo( clone );
1466    return clone;
1467}
1468
1469
1470void TiXmlUnknown::Print( FILE* cfile, int depth ) const
1471{
1472    for ( int i=0; i<depth; i++ )
1473        fprintf( cfile, " " );
1474    fprintf( cfile, "<%s>", value.c_str() );
1475}
1476
1477
1478void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
1479{
1480    TiXmlNode::CopyTo( target );
1481}
1482
1483
1484bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
1485{
1486    return visitor->Visit( *this );
1487}
1488
1489
1490TiXmlNode* TiXmlUnknown::Clone() const
1491{
1492    TiXmlUnknown* clone = new TiXmlUnknown();
1493
1494    if ( !clone )
1495        return 0;
1496
1497    CopyTo( clone );
1498    return clone;
1499}
1500
1501
1502TiXmlAttributeSet::TiXmlAttributeSet()
1503{
1504    sentinel.next = &sentinel;
1505    sentinel.prev = &sentinel;
1506}
1507
1508
1509TiXmlAttributeSet::~TiXmlAttributeSet()
1510{
1511    assert( sentinel.next == &sentinel );
1512    assert( sentinel.prev == &sentinel );
1513}
1514
1515
1516void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
1517{
1518    #ifdef TIXML_USE_STL
1519    assert( !Find( TIXML_STRING( addMe->Name() ) ) ); // Shouldn't be multiply adding to the set.
1520    #else
1521    assert( !Find( addMe->Name() ) ); // Shouldn't be multiply adding to the set.
1522    #endif
1523
1524    addMe->next = &sentinel;
1525    addMe->prev = sentinel.prev;
1526
1527    sentinel.prev->next = addMe;
1528    sentinel.prev = addMe;
1529}
1530
1531void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
1532{
1533    TiXmlAttribute* node;
1534
1535    for( node = sentinel.next; node != &sentinel; node = node->next )
1536    {
1537        if ( node == removeMe )
1538        {
1539            node->prev->next = node->next;
1540            node->next->prev = node->prev;
1541            node->next = 0;
1542            node->prev = 0;
1543            return;
1544        }
1545    }
1546    assert( 0 ); // we tried to remove a non-linked attribute.
1547}
1548
1549
1550#ifdef TIXML_USE_STL
1551const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
1552{
1553    for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1554    {
1555        if ( node->name == name )
1556            return node;
1557    }
1558    return 0;
1559}
1560
1561/*
1562TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name )
1563{
1564    for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1565    {
1566        if ( node->name == name )
1567            return node;
1568    }
1569    return 0;
1570}
1571*/
1572#endif
1573
1574
1575const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
1576{
1577    for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1578    {
1579        if ( strcmp( node->name.c_str(), name ) == 0 )
1580            return node;
1581    }
1582    return 0;
1583}
1584
1585/*
1586TiXmlAttribute* TiXmlAttributeSet::Find( const char* name )
1587{
1588    for( TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
1589    {
1590        if ( strcmp( node->name.c_str(), name ) == 0 )
1591            return node;
1592    }
1593    return 0;
1594}
1595*/
1596
1597#ifdef TIXML_USE_STL
1598std::istream& operator>> (std::istream & in, TiXmlNode & base)
1599{
1600    TIXML_STRING tag;
1601    tag.reserve( 8 * 1000 );
1602    base.StreamIn( &in, &tag );
1603
1604    base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
1605    return in;
1606}
1607#endif
1608
1609
1610#ifdef TIXML_USE_STL
1611std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
1612{
1613    TiXmlPrinter printer;
1614    printer.SetStreamPrinting();
1615    base.Accept( &printer );
1616    out << printer.Str();
1617
1618    return out;
1619}
1620
1621
1622std::string& operator<< (std::string& out, const TiXmlNode& base )
1623{
1624    TiXmlPrinter printer;
1625    printer.SetStreamPrinting();
1626    base.Accept( &printer );
1627    out.append( printer.Str() );
1628
1629    return out;
1630}
1631#endif
1632
1633
1634TiXmlHandle TiXmlHandle::FirstChild() const
1635{
1636    if ( node )
1637    {
1638        TiXmlNode* child = node->FirstChild();
1639        if ( child )
1640            return TiXmlHandle( child );
1641    }
1642    return TiXmlHandle( 0 );
1643}
1644
1645
1646TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
1647{
1648    if ( node )
1649    {
1650        TiXmlNode* child = node->FirstChild( value );
1651        if ( child )
1652            return TiXmlHandle( child );
1653    }
1654    return TiXmlHandle( 0 );
1655}
1656
1657
1658TiXmlHandle TiXmlHandle::FirstChildElement() const
1659{
1660    if ( node )
1661    {
1662        TiXmlElement* child = node->FirstChildElement();
1663        if ( child )
1664            return TiXmlHandle( child );
1665    }
1666    return TiXmlHandle( 0 );
1667}
1668
1669
1670TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
1671{
1672    if ( node )
1673    {
1674        TiXmlElement* child = node->FirstChildElement( value );
1675        if ( child )
1676            return TiXmlHandle( child );
1677    }
1678    return TiXmlHandle( 0 );
1679}
1680
1681
1682TiXmlHandle TiXmlHandle::Child( int count ) const
1683{
1684    if ( node )
1685    {
1686        int i;
1687        TiXmlNode* child = node->FirstChild();
1688        for ( i=0;
1689                child && i<count;
1690                child = child->NextSibling(), ++i )
1691        {
1692            // nothing
1693        }
1694        if ( child )
1695            return TiXmlHandle( child );
1696    }
1697    return TiXmlHandle( 0 );
1698}
1699
1700
1701TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
1702{
1703    if ( node )
1704    {
1705        int i;
1706        TiXmlNode* child = node->FirstChild( value );
1707        for ( i=0;
1708                child && i<count;
1709                child = child->NextSibling( value ), ++i )
1710        {
1711            // nothing
1712        }
1713        if ( child )
1714            return TiXmlHandle( child );
1715    }
1716    return TiXmlHandle( 0 );
1717}
1718
1719
1720TiXmlHandle TiXmlHandle::ChildElement( int count ) const
1721{
1722    if ( node )
1723    {
1724        int i;
1725        TiXmlElement* child = node->FirstChildElement();
1726        for ( i=0;
1727                child && i<count;
1728                child = child->NextSiblingElement(), ++i )
1729        {
1730            // nothing
1731        }
1732        if ( child )
1733            return TiXmlHandle( child );
1734    }
1735    return TiXmlHandle( 0 );
1736}
1737
1738
1739TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
1740{
1741    if ( node )
1742    {
1743        int i;
1744        TiXmlElement* child = node->FirstChildElement( value );
1745        for ( i=0;
1746                child && i<count;
1747                child = child->NextSiblingElement( value ), ++i )
1748        {
1749            // nothing
1750        }
1751        if ( child )
1752            return TiXmlHandle( child );
1753    }
1754    return TiXmlHandle( 0 );
1755}
1756
1757
1758bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
1759{
1760    return true;
1761}
1762
1763bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
1764{
1765    return true;
1766}
1767
1768bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
1769{
1770    DoIndent();
1771    buffer += "<";
1772    buffer += element.Value();
1773
1774    for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
1775    {
1776        buffer += " ";
1777        attrib->Print( 0, 0, &buffer );
1778    }
1779
1780    if ( !element.FirstChild() )
1781    {
1782        buffer += " />";
1783        DoLineBreak();
1784    }
1785    else
1786    {
1787        buffer += ">";
1788        if ( element.FirstChild()->ToText()
1789              && element.LastChild() == element.FirstChild()
1790              && element.FirstChild()->ToText()->CDATA() == false )
1791        {
1792            simpleTextPrint = true;
1793            // no DoLineBreak()!
1794        }
1795        else
1796        {
1797            DoLineBreak();
1798        }
1799    }
1800    ++depth;
1801    return true;
1802}
1803
1804
1805bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
1806{
1807    --depth;
1808    if ( !element.FirstChild() )
1809    {
1810        // nothing.
1811    }
1812    else
1813    {
1814        if ( simpleTextPrint )
1815        {
1816            simpleTextPrint = false;
1817        }
1818        else
1819        {
1820            DoIndent();
1821        }
1822        buffer += "</";
1823        buffer += element.Value();
1824        buffer += ">";
1825        DoLineBreak();
1826    }
1827    return true;
1828}
1829
1830
1831bool TiXmlPrinter::Visit( const TiXmlText& text )
1832{
1833    if ( text.CDATA() )
1834    {
1835        DoIndent();
1836        buffer += "<![CDATA[";
1837        buffer += text.Value();
1838        buffer += "]]>";
1839        DoLineBreak();
1840    }
1841    else if ( simpleTextPrint )
1842    {
1843        TIXML_STRING str;
1844        TiXmlBase::EncodeString( text.ValueTStr(), &str );
1845        buffer += str;
1846    }
1847    else
1848    {
1849        DoIndent();
1850        TIXML_STRING str;
1851        TiXmlBase::EncodeString( text.ValueTStr(), &str );
1852        buffer += str;
1853        DoLineBreak();
1854    }
1855    return true;
1856}
1857
1858
1859bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
1860{
1861    DoIndent();
1862    declaration.Print( 0, 0, &buffer );
1863    DoLineBreak();
1864    return true;
1865}
1866
1867
1868bool TiXmlPrinter::Visit( const TiXmlComment& comment )
1869{
1870    DoIndent();
1871    buffer += "<!--";
1872    buffer += comment.Value();
1873    buffer += "-->";
1874    DoLineBreak();
1875    return true;
1876}
1877
1878
1879bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
1880{
1881    DoIndent();
1882    buffer += "<";
1883    buffer += unknown.Value();
1884    buffer += ">";
1885    DoLineBreak();
1886    return true;
1887}
1888
src/tinyxml/tinyxml.h
1/*
2www.sourceforge.net/projects/tinyxml
3Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any
7damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any
10purpose, including commercial applications, and to alter it and
11redistribute it freely, subject to the following restrictions:
12
131. The origin of this software must not be misrepresented; you must
14not claim that you wrote the original software. If you use this
15software in a product, an acknowledgment in the product documentation
16would be appreciated but is not required.
17
182. Altered source versions must be plainly marked as such, and
19must not be misrepresented as being the original software.
20
213. This notice may not be removed or altered from any source
22distribution.
23*/
24
25
26#ifndef TINYXML_INCLUDED
27#define TINYXML_INCLUDED
28
29#ifdef _MSC_VER
30#pragma warning( push )
31#pragma warning( disable : 4530 )
32#pragma warning( disable : 4786 )
33#endif
34
35#include <ctype.h>
36#include <stdio.h>
37#include <stdlib.h>
38#include <string.h>
39#include <assert.h>
40
41// Help out windows:
42#if defined( _DEBUG ) && !defined( DEBUG )
43#define DEBUG
44#endif
45
46#ifdef TIXML_USE_STL
47    #include <string>
48     #include <iostream>
49    #include <sstream>
50    #define TIXML_STRING std::string
51#else
52    #include "tinystr.h"
53    #define TIXML_STRING TiXmlString
54#endif
55
56// Deprecated library function hell. Compilers want to use the
57// new safe versions. This probably doesn't fully address the problem,
58// but it gets closer. There are too many compilers for me to fully
59// test. If you get compilation troubles, undefine TIXML_SAFE
60#define TIXML_SAFE
61
62#ifdef TIXML_SAFE
63    #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
64        // Microsoft visual studio, version 2005 and higher.
65        #define TIXML_SNPRINTF _snprintf_s
66        #define TIXML_SNSCANF _snscanf_s
67        #define TIXML_SSCANF sscanf_s
68    #elif defined(_MSC_VER) && (_MSC_VER >= 1200 )
69        // Microsoft visual studio, version 6 and higher.
70        //#pragma message( "Using _sn* functions." )
71        #define TIXML_SNPRINTF _snprintf
72        #define TIXML_SNSCANF _snscanf
73        #define TIXML_SSCANF sscanf
74    #elif defined(__GNUC__) && (__GNUC__ >= 3 )
75        // GCC version 3 and higher.s
76        //#warning( "Using sn* functions." )
77        #define TIXML_SNPRINTF snprintf
78        #define TIXML_SNSCANF snscanf
79        #define TIXML_SSCANF sscanf
80    #else
81        #define TIXML_SSCANF sscanf
82    #endif
83#endif
84
85class TiXmlDocument;
86class TiXmlElement;
87class TiXmlComment;
88class TiXmlUnknown;
89class TiXmlAttribute;
90class TiXmlText;
91class TiXmlDeclaration;
92class TiXmlParsingData;
93
94const int TIXML_MAJOR_VERSION = 2;
95const int TIXML_MINOR_VERSION = 5;
96const int TIXML_PATCH_VERSION = 3;
97
98/* Internal structure for tracking location of items
99    in the XML file.
100*/
101struct TiXmlCursor
102{
103    TiXmlCursor() { Clear(); }
104    void Clear() { row = col = -1; }
105
106    int row; // 0 based.
107    int col; // 0 based.
108};
109
110
111/**
112    If you call the Accept() method, it requires being passed a TiXmlVisitor
113    class to handle callbacks. For nodes that contain other nodes (Document, Element)
114    you will get called with a VisitEnter/VisitExit pair. Nodes that are always leaves
115    are simple called with Visit().
116
117    If you return 'true' from a Visit method, recursive parsing will continue. If you return
118    false, <b>no children of this node or its sibilings</b> will be Visited.
119
120    All flavors of Visit methods have a default implementation that returns 'true' (continue
121    visiting). You need to only override methods that are interesting to you.
122
123    Generally Accept() is called on the TiXmlDocument, although all nodes suppert Visiting.
124
125    You should never change the document from a callback.
126
127    @sa TiXmlNode::Accept()
128*/
129class TiXmlVisitor
130{
131public:
132    virtual ~TiXmlVisitor() {}
133
134    /// Visit a document.
135    virtual bool VisitEnter( const TiXmlDocument& /*doc*/ ) { return true; }
136    /// Visit a document.
137    virtual bool VisitExit( const TiXmlDocument& /*doc*/ ) { return true; }
138
139    /// Visit an element.
140    virtual bool VisitEnter( const TiXmlElement& /*element*/, const TiXmlAttribute* /*firstAttribute*/ ) { return true; }
141    /// Visit an element.
142    virtual bool VisitExit( const TiXmlElement& /*element*/ ) { return true; }
143
144    /// Visit a declaration
145    virtual bool Visit( const TiXmlDeclaration& /*declaration*/ ) { return true; }
146    /// Visit a text node
147    virtual bool Visit( const TiXmlText& /*text*/ ) { return true; }
148    /// Visit a comment node
149    virtual bool Visit( const TiXmlComment& /*comment*/ ) { return true; }
150    /// Visit an unknow node
151    virtual bool Visit( const TiXmlUnknown& /*unknown*/ ) { return true; }
152};
153
154// Only used by Attribute::Query functions
155enum
156{
157    TIXML_SUCCESS,
158    TIXML_NO_ATTRIBUTE,
159    TIXML_WRONG_TYPE
160};
161
162
163// Used by the parsing routines.
164enum TiXmlEncoding
165{
166    TIXML_ENCODING_UNKNOWN,
167    TIXML_ENCODING_UTF8,
168    TIXML_ENCODING_LEGACY
169};
170
171const TiXmlEncoding TIXML_DEFAULT_ENCODING = TIXML_ENCODING_UNKNOWN;
172
173/** TiXmlBase is a base class for every class in TinyXml.
174    It does little except to establish that TinyXml classes
175    can be printed and provide some utility functions.
176
177    In XML, the document and elements can contain
178    other elements and other types of nodes.
179
180    @verbatim
181    A Document can contain: Element (container or leaf)
182                            Comment (leaf)
183                            Unknown (leaf)
184                            Declaration( leaf )
185
186    An Element can contain: Element (container or leaf)
187                            Text (leaf)
188                            Attributes (not on tree)
189                            Comment (leaf)
190                            Unknown (leaf)
191
192    A Decleration contains: Attributes (not on tree)
193    @endverbatim
194*/
195class TiXmlBase
196{
197    friend class TiXmlNode;
198    friend class TiXmlElement;
199    friend class TiXmlDocument;
200
201public:
202    TiXmlBase() : userData(0) {}
203    virtual ~TiXmlBase() {}
204
205    /** All TinyXml classes can print themselves to a filestream
206        or the string class (TiXmlString in non-STL mode, std::string
207        in STL mode.) Either or both cfile and str can be null.
208
209        This is a formatted print, and will insert
210        tabs and newlines.
211
212        (For an unformatted stream, use the << operator.)
213    */
214    virtual void Print( FILE* cfile, int depth ) const = 0;
215
216    /** The world does not agree on whether white space should be kept or
217        not. In order to make everyone happy, these global, static functions
218        are provided to set whether or not TinyXml will condense all white space
219        into a single space or not. The default is to condense. Note changing this
220        value is not thread safe.
221    */
222    static void SetCondenseWhiteSpace( bool condense ) { condenseWhiteSpace = condense; }
223
224    /// Return the current white space setting.
225    static bool IsWhiteSpaceCondensed() { return condenseWhiteSpace; }
226
227    /** Return the position, in the original source file, of this node or attribute.
228        The row and column are 1-based. (That is the first row and first column is
229        1,1). If the returns values are 0 or less, then the parser does not have
230        a row and column value.
231
232        Generally, the row and column value will be set when the TiXmlDocument::Load(),
233        TiXmlDocument::LoadFile(), or any TiXmlNode::Parse() is called. It will NOT be set
234        when the DOM was created from operator>>.
235
236        The values reflect the initial load. Once the DOM is modified programmatically
237        (by adding or changing nodes and attributes) the new values will NOT update to
238        reflect changes in the document.
239
240        There is a minor performance cost to computing the row and column. Computation
241        can be disabled if TiXmlDocument::SetTabSize() is called with 0 as the value.
242
243        @sa TiXmlDocument::SetTabSize()
244    */
245    int Row() const { return location.row + 1; }
246    int Column() const { return location.col + 1; } ///< See Row()
247
248    void SetUserData( void* user ) { userData = user; } ///< Set a pointer to arbitrary user data.
249    void* GetUserData() { return userData; } ///< Get a pointer to arbitrary user data.
250    const void* GetUserData() const { return userData; } ///< Get a pointer to arbitrary user data.
251
252    // Table that returs, for a given lead byte, the total number of bytes
253    // in the UTF-8 sequence.
254    static const int utf8ByteTable[256];
255
256    virtual const char* Parse( const char* p,
257                                TiXmlParsingData* data,
258                                TiXmlEncoding encoding /*= TIXML_ENCODING_UNKNOWN */ ) = 0;
259
260    /** Expands entities in a string. Note this should not contian the tag's '<', '>', etc,
261        or they will be transformed into entities!
262    */
263    static void EncodeString( const TIXML_STRING& str, TIXML_STRING* out );
264
265    enum
266    {
267        TIXML_NO_ERROR = 0,
268        TIXML_ERROR,
269        TIXML_ERROR_OPENING_FILE,
270        TIXML_ERROR_OUT_OF_MEMORY,
271        TIXML_ERROR_PARSING_ELEMENT,
272        TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME,
273        TIXML_ERROR_READING_ELEMENT_VALUE,
274        TIXML_ERROR_READING_ATTRIBUTES,
275        TIXML_ERROR_PARSING_EMPTY,
276        TIXML_ERROR_READING_END_TAG,
277        TIXML_ERROR_PARSING_UNKNOWN,
278        TIXML_ERROR_PARSING_COMMENT,
279        TIXML_ERROR_PARSING_DECLARATION,
280        TIXML_ERROR_DOCUMENT_EMPTY,
281        TIXML_ERROR_EMBEDDED_NULL,
282        TIXML_ERROR_PARSING_CDATA,
283        TIXML_ERROR_DOCUMENT_TOP_ONLY,
284
285        TIXML_ERROR_STRING_COUNT
286    };
287
288protected:
289
290    static const char* SkipWhiteSpace( const char*, TiXmlEncoding encoding );
291    inline static bool IsWhiteSpace( char c )
292    {
293        return ( isspace( (unsigned char) c ) || c == '\n' || c == '\r' );
294    }
295    inline static bool IsWhiteSpace( int c )
296    {
297        if ( c < 256 )
298            return IsWhiteSpace( (char) c );
299        return false; // Again, only truly correct for English/Latin...but usually works.
300    }
301
302    #ifdef TIXML_USE_STL
303    static bool StreamWhiteSpace( std::istream * in, TIXML_STRING * tag );
304    static bool StreamTo( std::istream * in, int character, TIXML_STRING * tag );
305    #endif
306
307    /* Reads an XML name into the string provided. Returns
308        a pointer just past the last character of the name,
309        or 0 if the function has an error.
310    */
311    static const char* ReadName( const char* p, TIXML_STRING* name, TiXmlEncoding encoding );
312
313    /* Reads text. Returns a pointer past the given end tag.
314        Wickedly complex options, but it keeps the (sensitive) code in one place.
315    */
316    static const char* ReadText( const char* in, // where to start
317                                    TIXML_STRING* text, // the string read
318                                    bool ignoreWhiteSpace, // whether to keep the white space
319                                    const char* endTag, // what ends this text
320                                    bool ignoreCase, // whether to ignore case in the end tag
321                                    TiXmlEncoding encoding ); // the current encoding
322
323    // If an entity has been found, transform it into a character.
324    static const char* GetEntity( const char* in, char* value, int* length, TiXmlEncoding encoding );
325
326    // Get a character, while interpreting entities.
327    // The length can be from 0 to 4 bytes.
328    inline static const char* GetChar( const char* p, char* _value, int* length, TiXmlEncoding encoding )
329    {
330        assert( p );
331        if ( encoding == TIXML_ENCODING_UTF8 )
332        {
333            *length = utf8ByteTable[ *((const unsigned char*)p) ];
334            assert( *length >= 0 && *length < 5 );
335        }
336        else
337        {
338            *length = 1;
339        }
340
341        if ( *length == 1 )
342        {
343            if ( *p == '&' )
344                return GetEntity( p, _value, length, encoding );
345            *_value = *p;
346            return p+1;
347        }
348        else if ( *length )
349        {
350            //strncpy( _value, p, *length ); // lots of compilers don't like this function (unsafe),
351                                                // and the null terminator isn't needed
352            for( int i=0; p[i] && i<*length; ++i ) {
353                _value[i] = p[i];
354            }
355            return p + (*length);
356        }
357        else
358        {
359            // Not valid text.
360            return 0;
361        }
362    }
363
364    // Return true if the next characters in the stream are any of the endTag sequences.
365    // Ignore case only works for english, and should only be relied on when comparing
366    // to English words: StringEqual( p, "version", true ) is fine.
367    static bool StringEqual( const char* p,
368                                const char* endTag,
369                                bool ignoreCase,
370                                TiXmlEncoding encoding );
371
372    static const char* errorString[ TIXML_ERROR_STRING_COUNT ];
373
374    TiXmlCursor location;
375
376    /// Field containing a generic user pointer
377    void* userData;
378
379    // None of these methods are reliable for any language except English.
380    // Good for approximation, not great for accuracy.
381    static int IsAlpha( unsigned char anyByte, TiXmlEncoding encoding );
382    static int IsAlphaNum( unsigned char anyByte, TiXmlEncoding encoding );
383    inline static int ToLower( int v, TiXmlEncoding encoding )
384    {
385        if ( encoding == TIXML_ENCODING_UTF8 )
386        {
387            if ( v < 128 ) return tolower( v );
388            return v;
389        }
390        else
391        {
392            return tolower( v );
393        }
394    }
395    static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
396
397private:
398    TiXmlBase( const TiXmlBase& ); // not implemented.
399    void operator=( const TiXmlBase& base ); // not allowed.
400
401    struct Entity
402    {
403        const char* str;
404        unsigned int strLength;
405        char chr;
406    };
407    enum
408    {
409        NUM_ENTITY = 5,
410        MAX_ENTITY_LENGTH = 6
411
412    };
413    static Entity entity[ NUM_ENTITY ];
414    static bool condenseWhiteSpace;
415};
416
417
418/** The parent class for everything in the Document Object Model.
419    (Except for attributes).
420    Nodes have siblings, a parent, and children. A node can be
421    in a document, or stand on its own. The type of a TiXmlNode
422    can be queried, and it can be cast to its more defined type.
423*/
424class TiXmlNode : public TiXmlBase
425{
426    friend class TiXmlDocument;
427    friend class TiXmlElement;
428
429public:
430    #ifdef TIXML_USE_STL
431
432        /** An input stream operator, for every class. Tolerant of newlines and
433            formatting, but doesn't expect them.
434        */
435        friend std::istream& operator >> (std::istream& in, TiXmlNode& base);
436
437        /** An output stream operator, for every class. Note that this outputs
438            without any newlines or formatting, as opposed to Print(), which
439            includes tabs and new lines.
440
441            The operator<< and operator>> are not completely symmetric. Writing
442            a node to a stream is very well defined. You'll get a nice stream
443            of output, without any extra whitespace or newlines.
444
445            But reading is not as well defined. (As it always is.) If you create
446            a TiXmlElement (for example) and read that from an input stream,
447            the text needs to define an element or junk will result. This is
448            true of all input streams, but it's worth keeping in mind.
449
450            A TiXmlDocument will read nodes until it reads a root element, and
451            all the children of that root element.
452        */
453        friend std::ostream& operator<< (std::ostream& out, const TiXmlNode& base);
454
455        /// Appends the XML node or attribute to a std::string.
456        friend std::string& operator<< (std::string& out, const TiXmlNode& base );
457
458    #endif
459
460    /** The types of XML nodes supported by TinyXml. (All the
461            unsupported types are picked up by UNKNOWN.)
462    */
463    enum NodeType
464    {
465        DOCUMENT,
466        ELEMENT,
467        COMMENT,
468        UNKNOWN,
469        TEXT,
470        DECLARATION,
471        TYPECOUNT
472    };
473
474    virtual ~TiXmlNode();
475
476    /** The meaning of 'value' changes for the specific type of
477        TiXmlNode.
478        @verbatim
479        Document: filename of the xml file
480        Element: name of the element
481        Comment: the comment text
482        Unknown: the tag contents
483        Text: the text string
484        @endverbatim
485
486        The subclasses will wrap this function.
487    */
488    const char *Value() const { return value.c_str (); }
489
490    #ifdef TIXML_USE_STL
491    /** Return Value() as a std::string. If you only use STL,
492        this is more efficient than calling Value().
493        Only available in STL mode.
494    */
495    const std::string& ValueStr() const { return value; }
496    #endif
497
498    const TIXML_STRING& ValueTStr() const { return value; }
499
500    /** Changes the value of the node. Defined as:
501        @verbatim
502        Document: filename of the xml file
503        Element: name of the element
504        Comment: the comment text
505        Unknown: the tag contents
506        Text: the text string
507        @endverbatim
508    */
509    void SetValue(const char * _value) { value = _value;}
510
511    #ifdef TIXML_USE_STL
512    /// STL std::string form.
513    void SetValue( const std::string& _value ) { value = _value; }
514    #endif
515
516    /// Delete all the children of this node. Does not affect 'this'.
517    void Clear();
518
519    /// One step up the DOM.
520    TiXmlNode* Parent() { return parent; }
521    const TiXmlNode* Parent() const { return parent; }
522
523    const TiXmlNode* FirstChild() const { return firstChild; } ///< The first child of this node. Will be null if there are no children.
524    TiXmlNode* FirstChild() { return firstChild; }
525    const TiXmlNode* FirstChild( const char * value ) const; ///< The first child of this node with the matching 'value'. Will be null if none found.
526    /// The first child of this node with the matching 'value'. Will be null if none found.
527    TiXmlNode* FirstChild( const char * _value ) {
528        // Call through to the const version - safe since nothing is changed. Exiting syntax: cast this to a const (always safe)
529        // call the method, cast the return back to non-const.
530        return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->FirstChild( _value ));
531    }
532    const TiXmlNode* LastChild() const { return lastChild; } /// The last child of this node. Will be null if there are no children.
533    TiXmlNode* LastChild() { return lastChild; }
534
535    const TiXmlNode* LastChild( const char * value ) const; /// The last child of this node matching 'value'. Will be null if there are no children.
536    TiXmlNode* LastChild( const char * _value ) {
537        return const_cast< TiXmlNode* > ((const_cast< const TiXmlNode* >(this))->LastChild( _value ));
538    }
539
540    #ifdef TIXML_USE_STL
541    const TiXmlNode* FirstChild( const std::string& _value ) const { return FirstChild (_value.c_str ()); } ///< STL std::string form.
542    TiXmlNode* FirstChild( const std::string& _value ) { return FirstChild (_value.c_str ()); } ///< STL std::string form.
543    const TiXmlNode* LastChild( const std::string& _value ) const { return LastChild (_value.c_str ()); } ///< STL std::string form.
544    TiXmlNode* LastChild( const std::string& _value ) { return LastChild (_value.c_str ()); } ///< STL std::string form.
545    #endif
546
547    /** An alternate way to walk the children of a node.
548        One way to iterate over nodes is:
549        @verbatim
550            for( child = parent->FirstChild(); child; child = child->NextSibling() )
551        @endverbatim
552
553        IterateChildren does the same thing with the syntax:
554        @verbatim
555            child = 0;
556            while( child = parent->IterateChildren( child ) )
557        @endverbatim
558
559        IterateChildren takes the previous child as input and finds
560        the next one. If the previous child is null, it returns the
561        first. IterateChildren will return null when done.
562    */
563    const TiXmlNode* IterateChildren( const TiXmlNode* previous ) const;
564    TiXmlNode* IterateChildren( const TiXmlNode* previous ) {
565        return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( previous ) );
566    }
567
568    /// This flavor of IterateChildren searches for children with a particular 'value'
569    const TiXmlNode* IterateChildren( const char * value, const TiXmlNode* previous ) const;
570    TiXmlNode* IterateChildren( const char * _value, const TiXmlNode* previous ) {
571        return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->IterateChildren( _value, previous ) );
572    }
573
574    #ifdef TIXML_USE_STL
575    const TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) const { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
576    TiXmlNode* IterateChildren( const std::string& _value, const TiXmlNode* previous ) { return IterateChildren (_value.c_str (), previous); } ///< STL std::string form.
577    #endif
578
579    /** Add a new node related to this. Adds a child past the LastChild.
580        Returns a pointer to the new object or NULL if an error occured.
581    */
582    TiXmlNode* InsertEndChild( const TiXmlNode& addThis );
583
584
585    /** Add a new node related to this. Adds a child past the LastChild.
586
587        NOTE: the node to be added is passed by pointer, and will be
588        henceforth owned (and deleted) by tinyXml. This method is efficient
589        and avoids an extra copy, but should be used with care as it
590        uses a different memory model than the other insert functions.
591
592        @sa InsertEndChild
593    */
594    TiXmlNode* LinkEndChild( TiXmlNode* addThis );
595
596    /** Add a new node related to this. Adds a child before the specified child.
597        Returns a pointer to the new object or NULL if an error occured.
598    */
599    TiXmlNode* InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis );
600
601    /** Add a new node related to this. Adds a child after the specified child.
602        Returns a pointer to the new object or NULL if an error occured.
603    */
604    TiXmlNode* InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis );
605
606    /** Replace a child of this node.
607        Returns a pointer to the new object or NULL if an error occured.
608    */
609    TiXmlNode* ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis );
610
611    /// Delete a child of this node.
612    bool RemoveChild( TiXmlNode* removeThis );
613
614    /// Navigate to a sibling node.
615    const TiXmlNode* PreviousSibling() const { return prev; }
616    TiXmlNode* PreviousSibling() { return prev; }
617
618    /// Navigate to a sibling node.
619    const TiXmlNode* PreviousSibling( const char * ) const;
620    TiXmlNode* PreviousSibling( const char *_prev ) {
621        return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->PreviousSibling( _prev ) );
622    }
623
624    #ifdef TIXML_USE_STL
625    const TiXmlNode* PreviousSibling( const std::string& _value ) const { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
626    TiXmlNode* PreviousSibling( const std::string& _value ) { return PreviousSibling (_value.c_str ()); } ///< STL std::string form.
627    const TiXmlNode* NextSibling( const std::string& _value) const { return NextSibling (_value.c_str ()); } ///< STL std::string form.
628    TiXmlNode* NextSibling( const std::string& _value) { return NextSibling (_value.c_str ()); } ///< STL std::string form.
629    #endif
630
631    /// Navigate to a sibling node.
632    const TiXmlNode* NextSibling() const { return next; }
633    TiXmlNode* NextSibling() { return next; }
634
635    /// Navigate to a sibling node with the given 'value'.
636    const TiXmlNode* NextSibling( const char * ) const;
637    TiXmlNode* NextSibling( const char* _next ) {
638        return const_cast< TiXmlNode* >( (const_cast< const TiXmlNode* >(this))->NextSibling( _next ) );
639    }
640
641    /** Convenience function to get through elements.
642        Calls NextSibling and ToElement. Will skip all non-Element
643        nodes. Returns 0 if there is not another element.
644    */
645    const TiXmlElement* NextSiblingElement() const;
646    TiXmlElement* NextSiblingElement() {
647        return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement() );
648    }
649
650    /** Convenience function to get through elements.
651        Calls NextSibling and ToElement. Will skip all non-Element
652        nodes. Returns 0 if there is not another element.
653    */
654    const TiXmlElement* NextSiblingElement( const char * ) const;
655    TiXmlElement* NextSiblingElement( const char *_next ) {
656        return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->NextSiblingElement( _next ) );
657    }
658
659    #ifdef TIXML_USE_STL
660    const TiXmlElement* NextSiblingElement( const std::string& _value) const { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
661    TiXmlElement* NextSiblingElement( const std::string& _value) { return NextSiblingElement (_value.c_str ()); } ///< STL std::string form.
662    #endif
663
664    /// Convenience function to get through elements.
665    const TiXmlElement* FirstChildElement() const;
666    TiXmlElement* FirstChildElement() {
667        return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement() );
668    }
669
670    /// Convenience function to get through elements.
671    const TiXmlElement* FirstChildElement( const char * _value ) const;
672    TiXmlElement* FirstChildElement( const char * _value ) {
673        return const_cast< TiXmlElement* >( (const_cast< const TiXmlNode* >(this))->FirstChildElement( _value ) );
674    }
675
676    #ifdef TIXML_USE_STL
677    const TiXmlElement* FirstChildElement( const std::string& _value ) const { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
678    TiXmlElement* FirstChildElement( const std::string& _value ) { return FirstChildElement (_value.c_str ()); } ///< STL std::string form.
679    #endif
680
681    /** Query the type (as an enumerated value, above) of this node.
682        The possible types are: DOCUMENT, ELEMENT, COMMENT,
683                                UNKNOWN, TEXT, and DECLARATION.
684    */
685    int Type() const { return type; }
686
687    /** Return a pointer to the Document this node lives in.
688        Returns null if not in a document.
689    */
690    const TiXmlDocument* GetDocument() const;
691    TiXmlDocument* GetDocument() {
692        return const_cast< TiXmlDocument* >( (const_cast< const TiXmlNode* >(this))->GetDocument() );
693    }
694
695    /// Returns true if this node has no children.
696    bool NoChildren() const { return !firstChild; }
697
698    virtual const TiXmlDocument* ToDocument() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
699    virtual const TiXmlElement* ToElement() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
700    virtual const TiXmlComment* ToComment() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
701    virtual const TiXmlUnknown* ToUnknown() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
702    virtual const TiXmlText* ToText() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
703    virtual const TiXmlDeclaration* ToDeclaration() const { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
704
705    virtual TiXmlDocument* ToDocument() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
706    virtual TiXmlElement* ToElement() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
707    virtual TiXmlComment* ToComment() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
708    virtual TiXmlUnknown* ToUnknown() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
709    virtual TiXmlText* ToText() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
710    virtual TiXmlDeclaration* ToDeclaration() { return 0; } ///< Cast to a more defined type. Will return null if not of the requested type.
711
712    /** Create an exact duplicate of this node and return it. The memory must be deleted
713        by the caller.
714    */
715    virtual TiXmlNode* Clone() const = 0;
716
717    /** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the
718        XML tree will be conditionally visited and the host will be called back
719        via the TiXmlVisitor interface.
720
721        This is essentially a SAX interface for TinyXML. (Note however it doesn't re-parse
722        the XML for the callbacks, so the performance of TinyXML is unchanged by using this
723        interface versus any other.)
724
725        The interface has been based on ideas from:
726
727        - http://www.saxproject.org/
728        - http://c2.com/cgi/wiki?HierarchicalVisitorPattern
729
730        Which are both good references for "visiting".
731
732        An example of using Accept():
733        @verbatim
734        TiXmlPrinter printer;
735        tinyxmlDoc.Accept( &printer );
736        const char* xmlcstr = printer.CStr();
737        @endverbatim
738    */
739    virtual bool Accept( TiXmlVisitor* visitor ) const = 0;
740
741protected:
742    TiXmlNode( NodeType _type );
743
744    // Copy to the allocated object. Shared functionality between Clone, Copy constructor,
745    // and the assignment operator.
746    void CopyTo( TiXmlNode* target ) const;
747
748    #ifdef TIXML_USE_STL
749        // The real work of the input operator.
750    virtual void StreamIn( std::istream* in, TIXML_STRING* tag ) = 0;
751    #endif
752
753    // Figure out what is at *p, and parse it. Returns null if it is not an xml node.
754    TiXmlNode* Identify( const char* start, TiXmlEncoding encoding );
755
756    TiXmlNode* parent;
757    NodeType type;
758
759    TiXmlNode* firstChild;
760    TiXmlNode* lastChild;
761
762    TIXML_STRING value;
763
764    TiXmlNode* prev;
765    TiXmlNode* next;
766
767private:
768    TiXmlNode( const TiXmlNode& ); // not implemented.
769    void operator=( const TiXmlNode& base ); // not allowed.
770};
771
772
773/** An attribute is a name-value pair. Elements have an arbitrary
774    number of attributes, each with a unique name.
775
776    @note The attributes are not TiXmlNodes, since they are not
777          part of the tinyXML document object model. There are other
778          suggested ways to look at this problem.
779*/
780class TiXmlAttribute : public TiXmlBase
781{
782    friend class TiXmlAttributeSet;
783
784public:
785    /// Construct an empty attribute.
786    TiXmlAttribute() : TiXmlBase()
787    {
788        document = 0;
789        prev = next = 0;
790    }
791
792    #ifdef TIXML_USE_STL
793    /// std::string constructor.
794    TiXmlAttribute( const std::string& _name, const std::string& _value )
795    {
796        name = _name;
797        value = _value;
798        document = 0;
799        prev = next = 0;
800    }
801    #endif
802
803    /// Construct an attribute with a name and value.
804    TiXmlAttribute( const char * _name, const char * _value )
805    {
806        name = _name;
807        value = _value;
808        document = 0;
809        prev = next = 0;
810    }
811
812    const char* Name() const { return name.c_str(); } ///< Return the name of this attribute.
813    const char* Value() const { return value.c_str(); } ///< Return the value of this attribute.
814    #ifdef TIXML_USE_STL
815    const std::string& ValueStr() const { return value; } ///< Return the value of this attribute.
816    #endif
817    int IntValue() const; ///< Return the value of this attribute, converted to an integer.
818    double DoubleValue() const; ///< Return the value of this attribute, converted to a double.
819
820    // Get the tinyxml string representation
821    const TIXML_STRING& NameTStr() const { return name; }
822
823    /** QueryIntValue examines the value string. It is an alternative to the
824        IntValue() method with richer error checking.
825        If the value is an integer, it is stored in 'value' and
826        the call returns TIXML_SUCCESS. If it is not
827        an integer, it returns TIXML_WRONG_TYPE.
828
829        A specialized but useful call. Note that for success it returns 0,
830        which is the opposite of almost all other TinyXml calls.
831    */
832    int QueryIntValue( int* _value ) const;
833    /// QueryDoubleValue examines the value string. See QueryIntValue().
834    int QueryDoubleValue( double* _value ) const;
835
836    void SetName( const char* _name ) { name = _name; } ///< Set the name of this attribute.
837    void SetValue( const char* _value ) { value = _value; } ///< Set the value.
838
839    void SetIntValue( int _value ); ///< Set the value from an integer.
840    void SetDoubleValue( double _value ); ///< Set the value from a double.
841
842    #ifdef TIXML_USE_STL
843    /// STL std::string form.
844    void SetName( const std::string& _name ) { name = _name; }
845    /// STL std::string form.
846    void SetValue( const std::string& _value ) { value = _value; }
847    #endif
848
849    /// Get the next sibling attribute in the DOM. Returns null at end.
850    const TiXmlAttribute* Next() const;
851    TiXmlAttribute* Next() {
852        return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Next() );
853    }
854
855    /// Get the previous sibling attribute in the DOM. Returns null at beginning.
856    const TiXmlAttribute* Previous() const;
857    TiXmlAttribute* Previous() {
858        return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttribute* >(this))->Previous() );
859    }
860
861    bool operator==( const TiXmlAttribute& rhs ) const { return rhs.name == name; }
862    bool operator<( const TiXmlAttribute& rhs ) const { return name < rhs.name; }
863    bool operator>( const TiXmlAttribute& rhs ) const { return name > rhs.name; }
864
865    /* Attribute parsing starts: first letter of the name
866                         returns: the next char after the value end quote
867    */
868    virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
869
870    // Prints this Attribute to a FILE stream.
871    virtual void Print( FILE* cfile, int depth ) const {
872        Print( cfile, depth, 0 );
873    }
874    void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
875
876    // [internal use]
877    // Set the document pointer so the attribute can report errors.
878    void SetDocument( TiXmlDocument* doc ) { document = doc; }
879
880private:
881    TiXmlAttribute( const TiXmlAttribute& ); // not implemented.
882    void operator=( const TiXmlAttribute& base ); // not allowed.
883
884    TiXmlDocument* document; // A pointer back to a document, for error reporting.
885    TIXML_STRING name;
886    TIXML_STRING value;
887    TiXmlAttribute* prev;
888    TiXmlAttribute* next;
889};
890
891
892/* A class used to manage a group of attributes.
893    It is only used internally, both by the ELEMENT and the DECLARATION.
894
895    The set can be changed transparent to the Element and Declaration
896    classes that use it, but NOT transparent to the Attribute
897    which has to implement a next() and previous() method. Which makes
898    it a bit problematic and prevents the use of STL.
899
900    This version is implemented with circular lists because:
901        - I like circular lists
902        - it demonstrates some independence from the (typical) doubly linked list.
903*/
904class TiXmlAttributeSet
905{
906public:
907    TiXmlAttributeSet();
908    ~TiXmlAttributeSet();
909
910    void Add( TiXmlAttribute* attribute );
911    void Remove( TiXmlAttribute* attribute );
912
913    const TiXmlAttribute* First() const { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
914    TiXmlAttribute* First() { return ( sentinel.next == &sentinel ) ? 0 : sentinel.next; }
915    const TiXmlAttribute* Last() const { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
916    TiXmlAttribute* Last() { return ( sentinel.prev == &sentinel ) ? 0 : sentinel.prev; }
917
918    const TiXmlAttribute* Find( const char* _name ) const;
919    TiXmlAttribute* Find( const char* _name ) {
920        return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
921    }
922    #ifdef TIXML_USE_STL
923    const TiXmlAttribute* Find( const std::string& _name ) const;
924    TiXmlAttribute* Find( const std::string& _name ) {
925        return const_cast< TiXmlAttribute* >( (const_cast< const TiXmlAttributeSet* >(this))->Find( _name ) );
926    }
927
928    #endif
929
930private:
931    //*ME: Because of hidden/disabled copy-construktor in TiXmlAttribute (sentinel-element),
932    //*ME: this class must be also use a hidden/disabled copy-constructor !!!
933    TiXmlAttributeSet( const TiXmlAttributeSet& ); // not allowed
934    void operator=( const TiXmlAttributeSet& ); // not allowed (as TiXmlAttribute)
935
936    TiXmlAttribute sentinel;
937};
938
939
940/** The element is a container class. It has a value, the element name,
941    and can contain other elements, text, comments, and unknowns.
942    Elements also contain an arbitrary number of attributes.
943*/
944class TiXmlElement : public TiXmlNode
945{
946public:
947    /// Construct an element.
948    TiXmlElement (const char * in_value);
949
950    #ifdef TIXML_USE_STL
951    /// std::string constructor.
952    TiXmlElement( const std::string& _value );
953    #endif
954
955    TiXmlElement( const TiXmlElement& );
956
957    void operator=( const TiXmlElement& base );
958
959    virtual ~TiXmlElement();
960
961    /** Given an attribute name, Attribute() returns the value
962        for the attribute of that name, or null if none exists.
963    */
964    const char* Attribute( const char* name ) const;
965
966    /** Given an attribute name, Attribute() returns the value
967        for the attribute of that name, or null if none exists.
968        If the attribute exists and can be converted to an integer,
969        the integer value will be put in the return 'i', if 'i'
970        is non-null.
971    */
972    const char* Attribute( const char* name, int* i ) const;
973
974    /** Given an attribute name, Attribute() returns the value
975        for the attribute of that name, or null if none exists.
976        If the attribute exists and can be converted to an double,
977        the double value will be put in the return 'd', if 'd'
978        is non-null.
979    */
980    const char* Attribute( const char* name, double* d ) const;
981
982    /** QueryIntAttribute examines the attribute - it is an alternative to the
983        Attribute() method with richer error checking.
984        If the attribute is an integer, it is stored in 'value' and
985        the call returns TIXML_SUCCESS. If it is not
986        an integer, it returns TIXML_WRONG_TYPE. If the attribute
987        does not exist, then TIXML_NO_ATTRIBUTE is returned.
988    */
989    int QueryIntAttribute( const char* name, int* _value ) const;
990    /// QueryDoubleAttribute examines the attribute - see QueryIntAttribute().
991    int QueryDoubleAttribute( const char* name, double* _value ) const;
992    /// QueryFloatAttribute examines the attribute - see QueryIntAttribute().
993    int QueryFloatAttribute( const char* name, float* _value ) const {
994        double d;
995        int result = QueryDoubleAttribute( name, &d );
996        if ( result == TIXML_SUCCESS ) {
997            *_value = (float)d;
998        }
999        return result;
1000    }
1001
1002    #ifdef TIXML_USE_STL
1003    /** Template form of the attribute query which will try to read the
1004        attribute into the specified type. Very easy, very powerful, but
1005        be careful to make sure to call this with the correct type.
1006
1007        NOTE: This method doesn't work correctly for 'string' types.
1008
1009        @return TIXML_SUCCESS, TIXML_WRONG_TYPE, or TIXML_NO_ATTRIBUTE
1010    */
1011    template< typename T > int QueryValueAttribute( const std::string& name, T* outValue ) const
1012    {
1013        const TiXmlAttribute* node = attributeSet.Find( name );
1014        if ( !node )
1015            return TIXML_NO_ATTRIBUTE;
1016
1017        std::stringstream sstream( node->ValueStr() );
1018        sstream >> *outValue;
1019        if ( !sstream.fail() )
1020            return TIXML_SUCCESS;
1021        return TIXML_WRONG_TYPE;
1022    }
1023    /*
1024     This is - in theory - a bug fix for "QueryValueAtribute returns truncated std::string"
1025     but template specialization is hard to get working cross-compiler. Leaving the bug for now.
1026
1027    // The above will fail for std::string because the space character is used as a seperator.
1028    // Specialize for strings. Bug [ 1695429 ] QueryValueAtribute returns truncated std::string
1029    template<> int QueryValueAttribute( const std::string& name, std::string* outValue ) const
1030    {
1031        const TiXmlAttribute* node = attributeSet.Find( name );
1032        if ( !node )
1033            return TIXML_NO_ATTRIBUTE;
1034        *outValue = node->ValueStr();
1035        return TIXML_SUCCESS;
1036    }
1037    */
1038    #endif
1039
1040    /** Sets an attribute of name to a given value. The attribute
1041        will be created if it does not exist, or changed if it does.
1042    */
1043    void SetAttribute( const char* name, const char * _value );
1044
1045    #ifdef TIXML_USE_STL
1046    const std::string* Attribute( const std::string& name ) const;
1047    const std::string* Attribute( const std::string& name, int* i ) const;
1048    const std::string* Attribute( const std::string& name, double* d ) const;
1049    int QueryIntAttribute( const std::string& name, int* _value ) const;
1050    int QueryDoubleAttribute( const std::string& name, double* _value ) const;
1051
1052    /// STL std::string form.
1053    void SetAttribute( const std::string& name, const std::string& _value );
1054    ///< STL std::string form.
1055    void SetAttribute( const std::string& name, int _value );
1056    #endif
1057
1058    /** Sets an attribute of name to a given value. The attribute
1059        will be created if it does not exist, or changed if it does.
1060    */
1061    void SetAttribute( const char * name, int value );
1062
1063    /** Sets an attribute of name to a given value. The attribute
1064        will be created if it does not exist, or changed if it does.
1065    */
1066    void SetDoubleAttribute( const char * name, double value );
1067
1068    /** Deletes an attribute with the given name.
1069    */
1070    void RemoveAttribute( const char * name );
1071    #ifdef TIXML_USE_STL
1072    void RemoveAttribute( const std::string& name ) { RemoveAttribute (name.c_str ()); } ///< STL std::string form.
1073    #endif
1074
1075    const TiXmlAttribute* FirstAttribute() const { return attributeSet.First(); } ///< Access the first attribute in this element.
1076    TiXmlAttribute* FirstAttribute() { return attributeSet.First(); }
1077    const TiXmlAttribute* LastAttribute() const { return attributeSet.Last(); } ///< Access the last attribute in this element.
1078    TiXmlAttribute* LastAttribute() { return attributeSet.Last(); }
1079
1080    /** Convenience function for easy access to the text inside an element. Although easy
1081        and concise, GetText() is limited compared to getting the TiXmlText child
1082        and accessing it directly.
1083
1084        If the first child of 'this' is a TiXmlText, the GetText()
1085        returns the character string of the Text node, else null is returned.
1086
1087        This is a convenient method for getting the text of simple contained text:
1088        @verbatim
1089        <foo>This is text</foo>
1090        const char* str = fooElement->GetText();
1091        @endverbatim
1092
1093        'str' will be a pointer to "This is text".
1094
1095        Note that this function can be misleading. If the element foo was created from
1096        this XML:
1097        @verbatim
1098        <foo><b>This is text</b></foo>
1099        @endverbatim
1100
1101        then the value of str would be null. The first child node isn't a text node, it is
1102        another element. From this XML:
1103        @verbatim
1104        <foo>This is <b>text</b></foo>
1105        @endverbatim
1106        GetText() will return "This is ".
1107
1108        WARNING: GetText() accesses a child node - don't become confused with the
1109                 similarly named TiXmlHandle::Text() and TiXmlNode::ToText() which are
1110                 safe type casts on the referenced node.
1111    */
1112    const char* GetText() const;
1113
1114    /// Creates a new Element and returns it - the returned element is a copy.
1115    virtual TiXmlNode* Clone() const;
1116    // Print the Element to a FILE stream.
1117    virtual void Print( FILE* cfile, int depth ) const;
1118
1119    /* Attribtue parsing starts: next char past '<'
1120                         returns: next char past '>'
1121    */
1122    virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
1123
1124    virtual const TiXmlElement* ToElement() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1125    virtual TiXmlElement* ToElement() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1126
1127    /** Walk the XML tree visiting this node and all of its children.
1128    */
1129    virtual bool Accept( TiXmlVisitor* visitor ) const;
1130
1131protected:
1132
1133    void CopyTo( TiXmlElement* target ) const;
1134    void ClearThis(); // like clear, but initializes 'this' object as well
1135
1136    // Used to be public [internal use]
1137    #ifdef TIXML_USE_STL
1138    virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
1139    #endif
1140    /* [internal use]
1141        Reads the "value" of the element -- another element, or text.
1142        This should terminate with the current end tag.
1143    */
1144    const char* ReadValue( const char* in, TiXmlParsingData* prevData, TiXmlEncoding encoding );
1145
1146private:
1147
1148    TiXmlAttributeSet attributeSet;
1149};
1150
1151
1152/** An XML comment.
1153*/
1154class TiXmlComment : public TiXmlNode
1155{
1156public:
1157    /// Constructs an empty comment.
1158    TiXmlComment() : TiXmlNode( TiXmlNode::COMMENT ) {}
1159    /// Construct a comment from text.
1160    TiXmlComment( const char* _value ) : TiXmlNode( TiXmlNode::COMMENT ) {
1161        SetValue( _value );
1162    }
1163    TiXmlComment( const TiXmlComment& );
1164    void operator=( const TiXmlComment& base );
1165
1166    virtual ~TiXmlComment() {}
1167
1168    /// Returns a copy of this Comment.
1169    virtual TiXmlNode* Clone() const;
1170    // Write this Comment to a FILE stream.
1171    virtual void Print( FILE* cfile, int depth ) const;
1172
1173    /* Attribtue parsing starts: at the ! of the !--
1174                         returns: next char past '>'
1175    */
1176    virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
1177
1178    virtual const TiXmlComment* ToComment() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1179    virtual TiXmlComment* ToComment() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1180
1181    /** Walk the XML tree visiting this node and all of its children.
1182    */
1183    virtual bool Accept( TiXmlVisitor* visitor ) const;
1184
1185protected:
1186    void CopyTo( TiXmlComment* target ) const;
1187
1188    // used to be public
1189    #ifdef TIXML_USE_STL
1190    virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
1191    #endif
1192// virtual void StreamOut( TIXML_OSTREAM * out ) const;
1193
1194private:
1195
1196};
1197
1198
1199/** XML text. A text node can have 2 ways to output the next. "normal" output
1200    and CDATA. It will default to the mode it was parsed from the XML file and
1201    you generally want to leave it alone, but you can change the output mode with
1202    SetCDATA() and query it with CDATA().
1203*/
1204class TiXmlText : public TiXmlNode
1205{
1206    friend class TiXmlElement;
1207public:
1208    /** Constructor for text element. By default, it is treated as
1209        normal, encoded text. If you want it be output as a CDATA text
1210        element, set the parameter _cdata to 'true'
1211    */
1212    TiXmlText (const char * initValue ) : TiXmlNode (TiXmlNode::TEXT)
1213    {
1214        SetValue( initValue );
1215        cdata = false;
1216    }
1217    virtual ~TiXmlText() {}
1218
1219    #ifdef TIXML_USE_STL
1220    /// Constructor.
1221    TiXmlText( const std::string& initValue ) : TiXmlNode (TiXmlNode::TEXT)
1222    {
1223        SetValue( initValue );
1224        cdata = false;
1225    }
1226    #endif
1227
1228    TiXmlText( const TiXmlText& copy ) : TiXmlNode( TiXmlNode::TEXT ) { copy.CopyTo( this ); }
1229    void operator=( const TiXmlText& base ) { base.CopyTo( this ); }
1230
1231    // Write this text object to a FILE stream.
1232    virtual void Print( FILE* cfile, int depth ) const;
1233
1234    /// Queries whether this represents text using a CDATA section.
1235    bool CDATA() const { return cdata; }
1236    /// Turns on or off a CDATA representation of text.
1237    void SetCDATA( bool _cdata ) { cdata = _cdata; }
1238
1239    virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
1240
1241    virtual const TiXmlText* ToText() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1242    virtual TiXmlText* ToText() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1243
1244    /** Walk the XML tree visiting this node and all of its children.
1245    */
1246    virtual bool Accept( TiXmlVisitor* content ) const;
1247
1248protected :
1249    /// [internal use] Creates a new Element and returns it.
1250    virtual TiXmlNode* Clone() const;
1251    void CopyTo( TiXmlText* target ) const;
1252
1253    bool Blank() const; // returns true if all white space and new lines
1254    // [internal use]
1255    #ifdef TIXML_USE_STL
1256    virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
1257    #endif
1258
1259private:
1260    bool cdata; // true if this should be input and output as a CDATA style text element
1261};
1262
1263
1264/** In correct XML the declaration is the first entry in the file.
1265    @verbatim
1266        <?xml version="1.0" standalone="yes"?>
1267    @endverbatim
1268
1269    TinyXml will happily read or write files without a declaration,
1270    however. There are 3 possible attributes to the declaration:
1271    version, encoding, and standalone.
1272
1273    Note: In this version of the code, the attributes are
1274    handled as special cases, not generic attributes, simply
1275    because there can only be at most 3 and they are always the same.
1276*/
1277class TiXmlDeclaration : public TiXmlNode
1278{
1279public:
1280    /// Construct an empty declaration.
1281    TiXmlDeclaration() : TiXmlNode( TiXmlNode::DECLARATION ) {}
1282
1283#ifdef TIXML_USE_STL
1284    /// Constructor.
1285    TiXmlDeclaration( const std::string& _version,
1286                        const std::string& _encoding,
1287                        const std::string& _standalone );
1288#endif
1289
1290    /// Construct.
1291    TiXmlDeclaration( const char* _version,
1292                        const char* _encoding,
1293                        const char* _standalone );
1294
1295    TiXmlDeclaration( const TiXmlDeclaration& copy );
1296    void operator=( const TiXmlDeclaration& copy );
1297
1298    virtual ~TiXmlDeclaration() {}
1299
1300    /// Version. Will return an empty string if none was found.
1301    const char *Version() const { return version.c_str (); }
1302    /// Encoding. Will return an empty string if none was found.
1303    const char *Encoding() const { return encoding.c_str (); }
1304    /// Is this a standalone document?
1305    const char *Standalone() const { return standalone.c_str (); }
1306
1307    /// Creates a copy of this Declaration and returns it.
1308    virtual TiXmlNode* Clone() const;
1309    // Print this declaration to a FILE stream.
1310    virtual void Print( FILE* cfile, int depth, TIXML_STRING* str ) const;
1311    virtual void Print( FILE* cfile, int depth ) const {
1312        Print( cfile, depth, 0 );
1313    }
1314
1315    virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
1316
1317    virtual const TiXmlDeclaration* ToDeclaration() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1318    virtual TiXmlDeclaration* ToDeclaration() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1319
1320    /** Walk the XML tree visiting this node and all of its children.
1321    */
1322    virtual bool Accept( TiXmlVisitor* visitor ) const;
1323
1324protected:
1325    void CopyTo( TiXmlDeclaration* target ) const;
1326    // used to be public
1327    #ifdef TIXML_USE_STL
1328    virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
1329    #endif
1330
1331private:
1332
1333    TIXML_STRING version;
1334    TIXML_STRING encoding;
1335    TIXML_STRING standalone;
1336};
1337
1338
1339/** Any tag that tinyXml doesn't recognize is saved as an
1340    unknown. It is a tag of text, but should not be modified.
1341    It will be written back to the XML, unchanged, when the file
1342    is saved.
1343
1344    DTD tags get thrown into TiXmlUnknowns.
1345*/
1346class TiXmlUnknown : public TiXmlNode
1347{
1348public:
1349    TiXmlUnknown() : TiXmlNode( TiXmlNode::UNKNOWN ) {}
1350    virtual ~TiXmlUnknown() {}
1351
1352    TiXmlUnknown( const TiXmlUnknown& copy ) : TiXmlNode( TiXmlNode::UNKNOWN ) { copy.CopyTo( this ); }
1353    void operator=( const TiXmlUnknown& copy ) { copy.CopyTo( this ); }
1354
1355    /// Creates a copy of this Unknown and returns it.
1356    virtual TiXmlNode* Clone() const;
1357    // Print this Unknown to a FILE stream.
1358    virtual void Print( FILE* cfile, int depth ) const;
1359
1360    virtual const char* Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding );
1361
1362    virtual const TiXmlUnknown* ToUnknown() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1363    virtual TiXmlUnknown* ToUnknown() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1364
1365    /** Walk the XML tree visiting this node and all of its children.
1366    */
1367    virtual bool Accept( TiXmlVisitor* content ) const;
1368
1369protected:
1370    void CopyTo( TiXmlUnknown* target ) const;
1371
1372    #ifdef TIXML_USE_STL
1373    virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
1374    #endif
1375
1376private:
1377
1378};
1379
1380
1381/** Always the top level node. A document binds together all the
1382    XML pieces. It can be saved, loaded, and printed to the screen.
1383    The 'value' of a document node is the xml file name.
1384*/
1385class TiXmlDocument : public TiXmlNode
1386{
1387public:
1388    /// Create an empty document, that has no name.
1389    TiXmlDocument();
1390    /// Create a document with a name. The name of the document is also the filename of the xml.
1391    TiXmlDocument( const char * documentName );
1392
1393    #ifdef TIXML_USE_STL
1394    /// Constructor.
1395    TiXmlDocument( const std::string& documentName );
1396    #endif
1397
1398    TiXmlDocument( const TiXmlDocument& copy );
1399    void operator=( const TiXmlDocument& copy );
1400
1401    virtual ~TiXmlDocument() {}
1402
1403    /** Load a file using the current document value.
1404        Returns true if successful. Will delete any existing
1405        document data before loading.
1406    */
1407    bool LoadFile( TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
1408    /// Save a file using the current document value. Returns true if successful.
1409    bool SaveFile() const;
1410    /// Load a file using the given filename. Returns true if successful.
1411    bool LoadFile( const char * filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
1412    /// Save a file using the given filename. Returns true if successful.
1413    bool SaveFile( const char * filename ) const;
1414    /** Load a file using the given FILE*. Returns true if successful. Note that this method
1415        doesn't stream - the entire object pointed at by the FILE*
1416        will be interpreted as an XML file. TinyXML doesn't stream in XML from the current
1417        file location. Streaming may be added in the future.
1418    */
1419    bool LoadFile( FILE*, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
1420    /// Save a file using the given FILE*. Returns true if successful.
1421    bool SaveFile( FILE* ) const;
1422
1423    #ifdef TIXML_USE_STL
1424    bool LoadFile( const std::string& filename, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING ) ///< STL std::string version.
1425    {
1426// StringToBuffer f( filename );
1427// return ( f.buffer && LoadFile( f.buffer, encoding ));
1428        return LoadFile( filename.c_str(), encoding );
1429    }
1430    bool SaveFile( const std::string& filename ) const ///< STL std::string version.
1431    {
1432// StringToBuffer f( filename );
1433// return ( f.buffer && SaveFile( f.buffer ));
1434        return SaveFile( filename.c_str() );
1435    }
1436    #endif
1437
1438    /** Parse the given null terminated block of xml data. Passing in an encoding to this
1439        method (either TIXML_ENCODING_LEGACY or TIXML_ENCODING_UTF8 will force TinyXml
1440        to use that encoding, regardless of what TinyXml might otherwise try to detect.
1441    */
1442    virtual const char* Parse( const char* p, TiXmlParsingData* data = 0, TiXmlEncoding encoding = TIXML_DEFAULT_ENCODING );
1443
1444    /** Get the root element -- the only top level element -- of the document.
1445        In well formed XML, there should only be one. TinyXml is tolerant of
1446        multiple elements at the document level.
1447    */
1448    const TiXmlElement* RootElement() const { return FirstChildElement(); }
1449    TiXmlElement* RootElement() { return FirstChildElement(); }
1450
1451    /** If an error occurs, Error will be set to true. Also,
1452        - The ErrorId() will contain the integer identifier of the error (not generally useful)
1453        - The ErrorDesc() method will return the name of the error. (very useful)
1454        - The ErrorRow() and ErrorCol() will return the location of the error (if known)
1455    */
1456    bool Error() const { return error; }
1457
1458    /// Contains a textual (english) description of the error if one occurs.
1459    const char * ErrorDesc() const { return errorDesc.c_str (); }
1460
1461    /** Generally, you probably want the error string ( ErrorDesc() ). But if you
1462        prefer the ErrorId, this function will fetch it.
1463    */
1464    int ErrorId() const { return errorId; }
1465
1466    /** Returns the location (if known) of the error. The first column is column 1,
1467        and the first row is row 1. A value of 0 means the row and column wasn't applicable
1468        (memory errors, for example, have no row/column) or the parser lost the error. (An
1469        error in the error reporting, in that case.)
1470
1471        @sa SetTabSize, Row, Column
1472    */
1473    int ErrorRow() const { return errorLocation.row+1; }
1474    int ErrorCol() const { return errorLocation.col+1; } ///< The column where the error occured. See ErrorRow()
1475
1476    /** SetTabSize() allows the error reporting functions (ErrorRow() and ErrorCol())
1477        to report the correct values for row and column. It does not change the output
1478        or input in any way.
1479
1480        By calling this method, with a tab size
1481        greater than 0, the row and column of each node and attribute is stored
1482        when the file is loaded. Very useful for tracking the DOM back in to
1483        the source file.
1484
1485        The tab size is required for calculating the location of nodes. If not
1486        set, the default of 4 is used. The tabsize is set per document. Setting
1487        the tabsize to 0 disables row/column tracking.
1488
1489        Note that row and column tracking is not supported when using operator>>.
1490
1491        The tab size needs to be enabled before the parse or load. Correct usage:
1492        @verbatim
1493        TiXmlDocument doc;
1494        doc.SetTabSize( 8 );
1495        doc.Load( "myfile.xml" );
1496        @endverbatim
1497
1498        @sa Row, Column
1499    */
1500    void SetTabSize( int _tabsize ) { tabsize = _tabsize; }
1501
1502    int TabSize() const { return tabsize; }
1503
1504    /** If you have handled the error, it can be reset with this call. The error
1505        state is automatically cleared if you Parse a new XML block.
1506    */
1507    void ClearError() { error = false;
1508                                                errorId = 0;
1509                                                errorDesc = "";
1510                                                errorLocation.row = errorLocation.col = 0;
1511                                                //errorLocation.last = 0;
1512                                            }
1513
1514    /** Write the document to standard out using formatted printing ("pretty print"). */
1515    void Print() const { Print( stdout, 0 ); }
1516
1517    /* Write the document to a string using formatted printing ("pretty print"). This
1518        will allocate a character array (new char[]) and return it as a pointer. The
1519        calling code pust call delete[] on the return char* to avoid a memory leak.
1520    */
1521    //char* PrintToMemory() const;
1522
1523    /// Print this Document to a FILE stream.
1524    virtual void Print( FILE* cfile, int depth = 0 ) const;
1525    // [internal use]
1526    void SetError( int err, const char* errorLocation, TiXmlParsingData* prevData, TiXmlEncoding encoding );
1527
1528    virtual const TiXmlDocument* ToDocument() const { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1529    virtual TiXmlDocument* ToDocument() { return this; } ///< Cast to a more defined type. Will return null not of the requested type.
1530
1531    /** Walk the XML tree visiting this node and all of its children.
1532    */
1533    virtual bool Accept( TiXmlVisitor* content ) const;
1534
1535protected :
1536    // [internal use]
1537    virtual TiXmlNode* Clone() const;
1538    #ifdef TIXML_USE_STL
1539    virtual void StreamIn( std::istream * in, TIXML_STRING * tag );
1540    #endif
1541
1542private:
1543    void CopyTo( TiXmlDocument* target ) const;
1544
1545    bool error;
1546    int errorId;
1547    TIXML_STRING errorDesc;
1548    int tabsize;
1549    TiXmlCursor errorLocation;
1550    bool useMicrosoftBOM; // the UTF-8 BOM were found when read. Note this, and try to write.
1551};
1552
1553
1554/**
1555    A TiXmlHandle is a class that wraps a node pointer with null checks; this is
1556    an incredibly useful thing. Note that TiXmlHandle is not part of the TinyXml
1557    DOM structure. It is a separate utility class.
1558
1559    Take an example:
1560    @verbatim
1561    <Document>
1562        <Element attributeA = "valueA">
1563            <Child attributeB = "value1" />
1564            <Child attributeB = "value2" />
1565        </Element>
1566    <Document>
1567    @endverbatim
1568
1569    Assuming you want the value of "attributeB" in the 2nd "Child" element, it's very
1570    easy to write a *lot* of code that looks like:
1571
1572    @verbatim
1573    TiXmlElement* root = document.FirstChildElement( "Document" );
1574    if ( root )
1575    {
1576        TiXmlElement* element = root->FirstChildElement( "Element" );
1577        if ( element )
1578        {
1579            TiXmlElement* child = element->FirstChildElement( "Child" );
1580            if ( child )
1581            {
1582                TiXmlElement* child2 = child->NextSiblingElement( "Child" );
1583                if ( child2 )
1584                {
1585                    // Finally do something useful.
1586    @endverbatim
1587
1588    And that doesn't even cover "else" cases. TiXmlHandle addresses the verbosity
1589    of such code. A TiXmlHandle checks for null pointers so it is perfectly safe
1590    and correct to use:
1591
1592    @verbatim
1593    TiXmlHandle docHandle( &document );
1594    TiXmlElement* child2 = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", 1 ).ToElement();
1595    if ( child2 )
1596    {
1597        // do something useful
1598    @endverbatim
1599
1600    Which is MUCH more concise and useful.
1601
1602    It is also safe to copy handles - internally they are nothing more than node pointers.
1603    @verbatim
1604    TiXmlHandle handleCopy = handle;
1605    @endverbatim
1606
1607    What they should not be used for is iteration:
1608
1609    @verbatim
1610    int i=0;
1611    while ( true )
1612    {
1613        TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).Child( "Child", i ).ToElement();
1614        if ( !child )
1615            break;
1616        // do something
1617        ++i;
1618    }
1619    @endverbatim
1620
1621    It seems reasonable, but it is in fact two embedded while loops. The Child method is
1622    a linear walk to find the element, so this code would iterate much more than it needs
1623    to. Instead, prefer:
1624
1625    @verbatim
1626    TiXmlElement* child = docHandle.FirstChild( "Document" ).FirstChild( "Element" ).FirstChild( "Child" ).ToElement();
1627
1628    for( child; child; child=child->NextSiblingElement() )
1629    {
1630        // do something
1631    }
1632    @endverbatim
1633*/
1634class TiXmlHandle
1635{
1636public:
1637    /// Create a handle from any node (at any depth of the tree.) This can be a null pointer.
1638    TiXmlHandle( TiXmlNode* _node ) { this->node = _node; }
1639    /// Copy constructor
1640    TiXmlHandle( const TiXmlHandle& ref ) { this->node = ref.node; }
1641    TiXmlHandle operator=( const TiXmlHandle& ref ) { this->node = ref.node; return *this; }
1642
1643    /// Return a handle to the first child node.
1644    TiXmlHandle FirstChild() const;
1645    /// Return a handle to the first child node with the given name.
1646    TiXmlHandle FirstChild( const char * value ) const;
1647    /// Return a handle to the first child element.
1648    TiXmlHandle FirstChildElement() const;
1649    /// Return a handle to the first child element with the given name.
1650    TiXmlHandle FirstChildElement( const char * value ) const;
1651
1652    /** Return a handle to the "index" child with the given name.
1653        The first child is 0, the second 1, etc.
1654    */
1655    TiXmlHandle Child( const char* value, int index ) const;
1656    /** Return a handle to the "index" child.
1657        The first child is 0, the second 1, etc.
1658    */
1659    TiXmlHandle Child( int index ) const;
1660    /** Return a handle to the "index" child element with the given name.
1661        The first child element is 0, the second 1, etc. Note that only TiXmlElements
1662        are indexed: other types are not counted.
1663    */
1664    TiXmlHandle ChildElement( const char* value, int index ) const;
1665    /** Return a handle to the "index" child element.
1666        The first child element is 0, the second 1, etc. Note that only TiXmlElements
1667        are indexed: other types are not counted.
1668    */
1669    TiXmlHandle ChildElement( int index ) const;
1670
1671    #ifdef TIXML_USE_STL
1672    TiXmlHandle FirstChild( const std::string& _value ) const { return FirstChild( _value.c_str() ); }
1673    TiXmlHandle FirstChildElement( const std::string& _value ) const { return FirstChildElement( _value.c_str() ); }
1674
1675    TiXmlHandle Child( const std::string& _value, int index ) const { return Child( _value.c_str(), index ); }
1676    TiXmlHandle ChildElement( const std::string& _value, int index ) const { return ChildElement( _value.c_str(), index ); }
1677    #endif
1678
1679    /** Return the handle as a TiXmlNode. This may return null.
1680    */
1681    TiXmlNode* ToNode() const { return node; }
1682    /** Return the handle as a TiXmlElement. This may return null.
1683    */
1684    TiXmlElement* ToElement() const { return ( ( node && node->ToElement() ) ? node->ToElement() : 0 ); }
1685    /** Return the handle as a TiXmlText. This may return null.
1686    */
1687    TiXmlText* ToText() const { return ( ( node && node->ToText() ) ? node->ToText() : 0 ); }
1688    /** Return the handle as a TiXmlUnknown. This may return null.
1689    */
1690    TiXmlUnknown* ToUnknown() const { return ( ( node && node->ToUnknown() ) ? node->ToUnknown() : 0 ); }
1691
1692    /** @deprecated use ToNode.
1693        Return the handle as a TiXmlNode. This may return null.
1694    */
1695    TiXmlNode* Node() const { return ToNode(); }
1696    /** @deprecated use ToElement.
1697        Return the handle as a TiXmlElement. This may return null.
1698    */
1699    TiXmlElement* Element() const { return ToElement(); }
1700    /** @deprecated use ToText()
1701        Return the handle as a TiXmlText. This may return null.
1702    */
1703    TiXmlText* Text() const { return ToText(); }
1704    /** @deprecated use ToUnknown()
1705        Return the handle as a TiXmlUnknown. This may return null.
1706    */
1707    TiXmlUnknown* Unknown() const { return ToUnknown(); }
1708
1709private:
1710    TiXmlNode* node;
1711};
1712
1713
1714/** Print to memory functionality. The TiXmlPrinter is useful when you need to:
1715
1716    -# Print to memory (especially in non-STL mode)
1717    -# Control formatting (line endings, etc.)
1718
1719    When constructed, the TiXmlPrinter is in its default "pretty printing" mode.
1720    Before calling Accept() you can call methods to control the printing
1721    of the XML document. After TiXmlNode::Accept() is called, the printed document can
1722    be accessed via the CStr(), Str(), and Size() methods.
1723
1724    TiXmlPrinter uses the Visitor API.
1725    @verbatim
1726    TiXmlPrinter printer;
1727    printer.SetIndent( "\t" );
1728
1729    doc.Accept( &printer );
1730    fprintf( stdout, "%s", printer.CStr() );
1731    @endverbatim
1732*/
1733class TiXmlPrinter : public TiXmlVisitor
1734{
1735public:
1736    TiXmlPrinter() : depth( 0 ), simpleTextPrint( false ),
1737                     buffer(), indent( " " ), lineBreak( "\n" ) {}
1738
1739    virtual bool VisitEnter( const TiXmlDocument& doc );
1740    virtual bool VisitExit( const TiXmlDocument& doc );
1741
1742    virtual bool VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute );
1743    virtual bool VisitExit( const TiXmlElement& element );
1744
1745    virtual bool Visit( const TiXmlDeclaration& declaration );
1746    virtual bool Visit( const TiXmlText& text );
1747    virtual bool Visit( const TiXmlComment& comment );
1748    virtual bool Visit( const TiXmlUnknown& unknown );
1749
1750    /** Set the indent characters for printing. By default 4 spaces
1751        but tab (\t) is also useful, or null/empty string for no indentation.
1752    */
1753    void SetIndent( const char* _indent ) { indent = _indent ? _indent : "" ; }
1754    /// Query the indention string.
1755    const char* Indent() { return indent.c_str(); }
1756    /** Set the line breaking string. By default set to newline (\n).
1757        Some operating systems prefer other characters, or can be
1758        set to the null/empty string for no indenation.
1759    */
1760    void SetLineBreak( const char* _lineBreak ) { lineBreak = _lineBreak ? _lineBreak : ""; }
1761    /// Query the current line breaking string.
1762    const char* LineBreak() { return lineBreak.c_str(); }
1763
1764    /** Switch over to "stream printing" which is the most dense formatting without
1765        linebreaks. Common when the XML is needed for network transmission.
1766    */
1767    void SetStreamPrinting() { indent = "";
1768                                                      lineBreak = "";
1769                                                    }
1770    /// Return the result.
1771    const char* CStr() { return buffer.c_str(); }
1772    /// Return the length of the result string.
1773    size_t Size() { return buffer.size(); }
1774
1775    #ifdef TIXML_USE_STL
1776    /// Return the result.
1777    const std::string& Str() { return buffer; }
1778    #endif
1779
1780private:
1781    void DoIndent() {
1782        for( int i=0; i<depth; ++i )
1783            buffer += indent;
1784    }
1785    void DoLineBreak() {
1786        buffer += lineBreak;
1787    }
1788
1789    int depth;
1790    bool simpleTextPrint;
1791    TIXML_STRING buffer;
1792    TIXML_STRING indent;
1793    TIXML_STRING lineBreak;
1794};
1795
1796
1797#ifdef _MSC_VER
1798#pragma warning( pop )
1799#endif
1800
1801#endif
1802
src/tinyxml/tinyxmlerror.cpp
1/*
2www.sourceforge.net/projects/tinyxml
3Original code (2.0 and earlier )copyright (c) 2000-2006 Lee Thomason (www.grinninglizard.com)
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any
7damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any
10purpose, including commercial applications, and to alter it and
11redistribute it freely, subject to the following restrictions:
12
131. The origin of this software must not be misrepresented; you must
14not claim that you wrote the original software. If you use this
15software in a product, an acknowledgment in the product documentation
16would be appreciated but is not required.
17
182. Altered source versions must be plainly marked as such, and
19must not be misrepresented as being the original software.
20
213. This notice may not be removed or altered from any source
22distribution.
23*/
24
25#include "tinyxml.h"
26
27// The goal of the seperate error file is to make the first
28// step towards localization. tinyxml (currently) only supports
29// english error messages, but the could now be translated.
30//
31// It also cleans up the code a bit.
32//
33
34const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
35{
36    "No error",
37    "Error",
38    "Failed to open file",
39    "Memory allocation failed.",
40    "Error parsing Element.",
41    "Failed to read Element name",
42    "Error reading Element value.",
43    "Error reading Attributes.",
44    "Error: empty tag.",
45    "Error reading end tag.",
46    "Error parsing Unknown.",
47    "Error parsing Comment.",
48    "Error parsing Declaration.",
49    "Error document empty.",
50    "Error null (0) or unexpected EOF found in input stream.",
51    "Error parsing CDATA.",
52    "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
53};
src/tinyxml/tinyxmlparser.cpp
1/*
2www.sourceforge.net/projects/tinyxml
3Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
4
5This software is provided 'as-is', without any express or implied
6warranty. In no event will the authors be held liable for any
7damages arising from the use of this software.
8
9Permission is granted to anyone to use this software for any
10purpose, including commercial applications, and to alter it and
11redistribute it freely, subject to the following restrictions:
12
131. The origin of this software must not be misrepresented; you must
14not claim that you wrote the original software. If you use this
15software in a product, an acknowledgment in the product documentation
16would be appreciated but is not required.
17
182. Altered source versions must be plainly marked as such, and
19must not be misrepresented as being the original software.
20
213. This notice may not be removed or altered from any source
22distribution.
23*/
24
25#include <ctype.h>
26#include <stddef.h>
27
28#include "tinyxml.h"
29
30//#define DEBUG_PARSER
31#if defined( DEBUG_PARSER )
32# if defined( DEBUG ) && defined( _MSC_VER )
33# include <windows.h>
34# define TIXML_LOG OutputDebugString
35# else
36# define TIXML_LOG printf
37# endif
38#endif
39
40// Note tha "PutString" hardcodes the same list. This
41// is less flexible than it appears. Changing the entries
42// or order will break putstring.
43TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
44{
45    { "&amp;", 5, '&' },
46    { "&lt;", 4, '<' },
47    { "&gt;", 4, '>' },
48    { "&quot;", 6, '\"' },
49    { "&apos;", 6, '\'' }
50};
51
52// Bunch of unicode info at:
53// http://www.unicode.org/faq/utf_bom.html
54// Including the basic of this table, which determines the #bytes in the
55// sequence from the lead byte. 1 placed for invalid sequences --
56// although the result will be junk, pass it through as much as possible.
57// Beware of the non-characters in UTF-8:
58// ef bb bf (Microsoft "lead bytes")
59// ef bf be
60// ef bf bf
61
62const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
63const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
64const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
65
66const int TiXmlBase::utf8ByteTable[256] =
67{
68    // 0 1 2 3 4 5 6 7 8 9 a b c d e f
69        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x00
70        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x10
71        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x20
72        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x30
73        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x40
74        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x50
75        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x60
76        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x70 End of ASCII range
77        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x80 0x80 to 0xc1 invalid
78        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0x90
79        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xa0
80        1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 0xb0
81        1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xc0 0xc2 to 0xdf 2 byte
82        2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, // 0xd0
83        3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xe0 0xe0 to 0xef 3 byte
84        4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
85};
86
87
88void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
89{
90    const unsigned long BYTE_MASK = 0xBF;
91    const unsigned long BYTE_MARK = 0x80;
92    const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
93
94    if (input < 0x80)
95        *length = 1;
96    else if ( input < 0x800 )
97        *length = 2;
98    else if ( input < 0x10000 )
99        *length = 3;
100    else if ( input < 0x200000 )
101        *length = 4;
102    else
103        { *length = 0; return; } // This code won't covert this correctly anyway.
104
105    output += *length;
106
107    // Scary scary fall throughs.
108    switch (*length)
109    {
110        case 4:
111            --output;
112            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
113            input >>= 6;
114        case 3:
115            --output;
116            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
117            input >>= 6;
118        case 2:
119            --output;
120            *output = (char)((input | BYTE_MARK) & BYTE_MASK);
121            input >>= 6;
122        case 1:
123            --output;
124            *output = (char)(input | FIRST_BYTE_MARK[*length]);
125    }
126}
127
128
129/*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
130{
131    // This will only work for low-ascii, everything else is assumed to be a valid
132    // letter. I'm not sure this is the best approach, but it is quite tricky trying
133    // to figure out alhabetical vs. not across encoding. So take a very
134    // conservative approach.
135
136// if ( encoding == TIXML_ENCODING_UTF8 )
137// {
138        if ( anyByte < 127 )
139            return isalpha( anyByte );
140        else
141            return 1; // What else to do? The unicode set is huge...get the english ones right.
142// }
143// else
144// {
145// return isalpha( anyByte );
146// }
147}
148
149
150/*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
151{
152    // This will only work for low-ascii, everything else is assumed to be a valid
153    // letter. I'm not sure this is the best approach, but it is quite tricky trying
154    // to figure out alhabetical vs. not across encoding. So take a very
155    // conservative approach.
156
157// if ( encoding == TIXML_ENCODING_UTF8 )
158// {
159        if ( anyByte < 127 )
160            return isalnum( anyByte );
161        else
162            return 1; // What else to do? The unicode set is huge...get the english ones right.
163// }
164// else
165// {
166// return isalnum( anyByte );
167// }
168}
169
170
171class TiXmlParsingData
172{
173    friend class TiXmlDocument;
174  public:
175    void Stamp( const char* now, TiXmlEncoding encoding );
176
177    const TiXmlCursor& Cursor() { return cursor; }
178
179  private:
180    // Only used by the document!
181    TiXmlParsingData( const char* start, int _tabsize, int row, int col )
182    {
183        assert( start );
184        stamp = start;
185        tabsize = _tabsize;
186        cursor.row = row;
187        cursor.col = col;
188    }
189
190    TiXmlCursor cursor;
191    const char* stamp;
192    int tabsize;
193};
194
195
196void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
197{
198    assert( now );
199
200    // Do nothing if the tabsize is 0.
201    if ( tabsize < 1 )
202    {
203        return;
204    }
205
206    // Get the current row, column.
207    int row = cursor.row;
208    int col = cursor.col;
209    const char* p = stamp;
210    assert( p );
211
212    while ( p < now )
213    {
214        // Treat p as unsigned, so we have a happy compiler.
215        const unsigned char* pU = (const unsigned char*)p;
216
217        // Code contributed by Fletcher Dunn: (modified by lee)
218        switch (*pU) {
219            case 0:
220                // We *should* never get here, but in case we do, don't
221                // advance past the terminating null character, ever
222                return;
223
224            case '\r':
225                // bump down to the next line
226                ++row;
227                col = 0;
228                // Eat the character
229                ++p;
230
231                // Check for \r\n sequence, and treat this as a single character
232                if (*p == '\n') {
233                    ++p;
234                }
235                break;
236
237            case '\n':
238                // bump down to the next line
239                ++row;
240                col = 0;
241
242                // Eat the character
243                ++p;
244
245                // Check for \n\r sequence, and treat this as a single
246                // character. (Yes, this bizarre thing does occur still
247                // on some arcane platforms...)
248                if (*p == '\r') {
249                    ++p;
250                }
251                break;
252
253            case '\t':
254                // Eat the character
255                ++p;
256
257                // Skip to next tab stop
258                col = (col / tabsize + 1) * tabsize;
259                break;
260
261            case TIXML_UTF_LEAD_0:
262                if ( encoding == TIXML_ENCODING_UTF8 )
263                {
264                    if ( *(p+1) && *(p+2) )
265                    {
266                        // In these cases, don't advance the column. These are
267                        // 0-width spaces.
268                        if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
269                            p += 3;
270                        else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
271                            p += 3;
272                        else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
273                            p += 3;
274                        else
275                            { p +=3; ++col; } // A normal character.
276                    }
277                }
278                else
279                {
280                    ++p;
281                    ++col;
282                }
283                break;
284
285            default:
286                if ( encoding == TIXML_ENCODING_UTF8 )
287                {
288                    // Eat the 1 to 4 byte utf8 character.
289                    int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
290                    if ( step == 0 )
291                        step = 1; // Error case from bad encoding, but handle gracefully.
292                    p += step;
293
294                    // Just advance one column, of course.
295                    ++col;
296                }
297                else
298                {
299                    ++p;
300                    ++col;
301                }
302                break;
303        }
304    }
305    cursor.row = row;
306    cursor.col = col;
307    assert( cursor.row >= -1 );
308    assert( cursor.col >= -1 );
309    stamp = p;
310    assert( stamp );
311}
312
313
314const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
315{
316    if ( !p || !*p )
317    {
318        return 0;
319    }
320    if ( encoding == TIXML_ENCODING_UTF8 )
321    {
322        while ( *p )
323        {
324            const unsigned char* pU = (const unsigned char*)p;
325
326            // Skip the stupid Microsoft UTF-8 Byte order marks
327            if ( *(pU+0)==TIXML_UTF_LEAD_0
328                 && *(pU+1)==TIXML_UTF_LEAD_1
329                 && *(pU+2)==TIXML_UTF_LEAD_2 )
330            {
331                p += 3;
332                continue;
333            }
334            else if(*(pU+0)==TIXML_UTF_LEAD_0
335                 && *(pU+1)==0xbfU
336                 && *(pU+2)==0xbeU )
337            {
338                p += 3;
339                continue;
340            }
341            else if(*(pU+0)==TIXML_UTF_LEAD_0
342                 && *(pU+1)==0xbfU
343                 && *(pU+2)==0xbfU )
344            {
345                p += 3;
346                continue;
347            }
348
349            if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' ) // Still using old rules for white space.
350                ++p;
351            else
352                break;
353        }
354    }
355    else
356    {
357        while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
358            ++p;
359    }
360
361    return p;
362}
363
364#ifdef TIXML_USE_STL
365/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
366{
367    for( ;; )
368    {
369        if ( !in->good() ) return false;
370
371        int c = in->peek();
372        // At this scope, we can't get to a document. So fail silently.
373        if ( !IsWhiteSpace( c ) || c <= 0 )
374            return true;
375
376        *tag += (char) in->get();
377    }
378}
379
380/*static*/ bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
381{
382    //assert( character > 0 && character < 128 ); // else it won't work in utf-8
383    while ( in->good() )
384    {
385        int c = in->peek();
386        if ( c == character )
387            return true;
388        if ( c <= 0 ) // Silent failure: can't get document at this scope
389            return false;
390
391        in->get();
392        *tag += (char) c;
393    }
394    return false;
395}
396#endif
397
398// One of TinyXML's more performance demanding functions. Try to keep the memory overhead down. The
399// "assign" optimization removes over 10% of the execution time.
400//
401const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
402{
403    // Oddly, not supported on some comilers,
404    //name->clear();
405    // So use this:
406    *name = "";
407    assert( p );
408
409    // Names start with letters or underscores.
410    // Of course, in unicode, tinyxml has no idea what a letter *is*. The
411    // algorithm is generous.
412    //
413    // After that, they can be letters, underscores, numbers,
414    // hyphens, or colons. (Colons are valid ony for namespaces,
415    // but tinyxml can't tell namespaces from names.)
416    if ( p && *p
417         && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
418    {
419        const char* start = p;
420        while( p && *p
421                && ( IsAlphaNum( (unsigned char ) *p, encoding )
422                         || *p == '_'
423                         || *p == '-'
424                         || *p == '.'
425                         || *p == ':' ) )
426        {
427            //(*name) += *p; // expensive
428            ++p;
429        }
430        if ( p-start > 0 ) {
431            name->assign( start, p-start );
432        }
433        return p;
434    }
435    return 0;
436}
437
438const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
439{
440    // Presume an entity, and pull it out.
441    TIXML_STRING ent;
442    int i;
443    *length = 0;
444
445    if ( *(p+1) && *(p+1) == '#' && *(p+2) )
446    {
447        unsigned long ucs = 0;
448        ptrdiff_t delta = 0;
449        unsigned mult = 1;
450
451        if ( *(p+2) == 'x' )
452        {
453            // Hexadecimal.
454            if ( !*(p+3) ) return 0;
455
456            const char* q = p+3;
457            q = strchr( q, ';' );
458
459            if ( !q || !*q ) return 0;
460
461            delta = q-p;
462            --q;
463
464            while ( *q != 'x' )
465            {
466                if ( *q >= '0' && *q <= '9' )
467                    ucs += mult * (*q - '0');
468                else if ( *q >= 'a' && *q <= 'f' )
469                    ucs += mult * (*q - 'a' + 10);
470                else if ( *q >= 'A' && *q <= 'F' )
471                    ucs += mult * (*q - 'A' + 10 );
472                else
473                    return 0;
474                mult *= 16;
475                --q;
476            }
477        }
478        else
479        {
480            // Decimal.
481            if ( !*(p+2) ) return 0;
482
483            const char* q = p+2;
484            q = strchr( q, ';' );
485
486            if ( !q || !*q ) return 0;
487
488            delta = q-p;
489            --q;
490
491            while ( *q != '#' )
492            {
493                if ( *q >= '0' && *q <= '9' )
494                    ucs += mult * (*q - '0');
495                else
496                    return 0;
497                mult *= 10;
498                --q;
499            }
500        }
501        if ( encoding == TIXML_ENCODING_UTF8 )
502        {
503            // convert the UCS to UTF-8
504            ConvertUTF32ToUTF8( ucs, value, length );
505        }
506        else
507        {
508            *value = (char)ucs;
509            *length = 1;
510        }
511        return p + delta + 1;
512    }
513
514    // Now try to match it.
515    for( i=0; i<NUM_ENTITY; ++i )
516    {
517        if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
518        {
519            assert( strlen( entity[i].str ) == entity[i].strLength );
520            *value = entity[i].chr;
521            *length = 1;
522            return ( p + entity[i].strLength );
523        }
524    }
525
526    // So it wasn't an entity, its unrecognized, or something like that.
527    *value = *p; // Don't put back the last one, since we return it!
528    //*length = 1; // Leave unrecognized entities - this doesn't really work.
529                    // Just writes strange XML.
530    return p+1;
531}
532
533
534bool TiXmlBase::StringEqual( const char* p,
535                             const char* tag,
536                             bool ignoreCase,
537                             TiXmlEncoding encoding )
538{
539    assert( p );
540    assert( tag );
541    if ( !p || !*p )
542    {
543        assert( 0 );
544        return false;
545    }
546
547    const char* q = p;
548
549    if ( ignoreCase )
550    {
551        while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
552        {
553            ++q;
554            ++tag;
555        }
556
557        if ( *tag == 0 )
558            return true;
559    }
560    else
561    {
562        while ( *q && *tag && *q == *tag )
563        {
564            ++q;
565            ++tag;
566        }
567
568        if ( *tag == 0 ) // Have we found the end of the tag, and everything equal?
569            return true;
570    }
571    return false;
572}
573
574const char* TiXmlBase::ReadText( const char* p,
575                                    TIXML_STRING * text,
576                                    bool trimWhiteSpace,
577                                    const char* endTag,
578                                    bool caseInsensitive,
579                                    TiXmlEncoding encoding )
580{
581    *text = "";
582    if ( !trimWhiteSpace // certain tags always keep whitespace
583         || !condenseWhiteSpace ) // if true, whitespace is always kept
584    {
585        // Keep all the white space.
586        while ( p && *p
587                && !StringEqual( p, endTag, caseInsensitive, encoding )
588              )
589        {
590            int len;
591            char cArr[4] = { 0, 0, 0, 0 };
592            p = GetChar( p, cArr, &len, encoding );
593            text->append( cArr, len );
594        }
595    }
596    else
597    {
598        bool whitespace = false;
599
600        // Remove leading white space:
601        p = SkipWhiteSpace( p, encoding );
602        while ( p && *p
603                && !StringEqual( p, endTag, caseInsensitive, encoding ) )
604        {
605            if ( *p == '\r' || *p == '\n' )
606            {
607                whitespace = true;
608                ++p;
609            }
610            else if ( IsWhiteSpace( *p ) )
611            {
612                whitespace = true;
613                ++p;
614            }
615            else
616            {
617                // If we've found whitespace, add it before the
618                // new character. Any whitespace just becomes a space.
619                if ( whitespace )
620                {
621                    (*text) += ' ';
622                    whitespace = false;
623                }
624                int len;
625                char cArr[4] = { 0, 0, 0, 0 };
626                p = GetChar( p, cArr, &len, encoding );
627                if ( len == 1 )
628                    (*text) += cArr[0]; // more efficient
629                else
630                    text->append( cArr, len );
631            }
632        }
633    }
634    if ( p )
635        p += strlen( endTag );
636    return p;
637}
638
639#ifdef TIXML_USE_STL
640
641void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
642{
643    // The basic issue with a document is that we don't know what we're
644    // streaming. Read something presumed to be a tag (and hope), then
645    // identify it, and call the appropriate stream method on the tag.
646    //
647    // This "pre-streaming" will never read the closing ">" so the
648    // sub-tag can orient itself.
649
650    if ( !StreamTo( in, '<', tag ) )
651    {
652        SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
653        return;
654    }
655
656    while ( in->good() )
657    {
658        int tagIndex = (int) tag->length();
659        while ( in->good() && in->peek() != '>' )
660        {
661            int c = in->get();
662            if ( c <= 0 )
663            {
664                SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
665                break;
666            }
667            (*tag) += (char) c;
668        }
669
670        if ( in->good() )
671        {
672            // We now have something we presume to be a node of
673            // some sort. Identify it, and call the node to
674            // continue streaming.
675            TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
676
677            if ( node )
678            {
679                node->StreamIn( in, tag );
680                bool isElement = node->ToElement() != 0;
681                delete node;
682                node = 0;
683
684                // If this is the root element, we're done. Parsing will be
685                // done by the >> operator.
686                if ( isElement )
687                {
688                    return;
689                }
690            }
691            else
692            {
693                SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
694                return;
695            }
696        }
697    }
698    // We should have returned sooner.
699    SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
700}
701
702#endif
703
704const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
705{
706    ClearError();
707
708    // Parse away, at the document level. Since a document
709    // contains nothing but other tags, most of what happens
710    // here is skipping white space.
711    if ( !p || !*p )
712    {
713        SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
714        return 0;
715    }
716
717    // Note that, for a document, this needs to come
718    // before the while space skip, so that parsing
719    // starts from the pointer we are given.
720    location.Clear();
721    if ( prevData )
722    {
723        location.row = prevData->cursor.row;
724        location.col = prevData->cursor.col;
725    }
726    else
727    {
728        location.row = 0;
729        location.col = 0;
730    }
731    TiXmlParsingData data( p, TabSize(), location.row, location.col );
732    location = data.Cursor();
733
734    if ( encoding == TIXML_ENCODING_UNKNOWN )
735    {
736        // Check for the Microsoft UTF-8 lead bytes.
737        const unsigned char* pU = (const unsigned char*)p;
738        if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
739             && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
740             && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
741        {
742            encoding = TIXML_ENCODING_UTF8;
743            useMicrosoftBOM = true;
744        }
745    }
746
747    p = SkipWhiteSpace( p, encoding );
748    if ( !p )
749    {
750        SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
751        return 0;
752    }
753
754    while ( p && *p )
755    {
756        TiXmlNode* node = Identify( p, encoding );
757        if ( node )
758        {
759            p = node->Parse( p, &data, encoding );
760            LinkEndChild( node );
761        }
762        else
763        {
764            break;
765        }
766
767        // Did we get encoding info?
768        if ( encoding == TIXML_ENCODING_UNKNOWN
769             && node->ToDeclaration() )
770        {
771            TiXmlDeclaration* dec = node->ToDeclaration();
772            const char* enc = dec->Encoding();
773            assert( enc );
774
775            if ( *enc == 0 )
776                encoding = TIXML_ENCODING_UTF8;
777            else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
778                encoding = TIXML_ENCODING_UTF8;
779            else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
780                encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
781            else
782                encoding = TIXML_ENCODING_LEGACY;
783        }
784
785        p = SkipWhiteSpace( p, encoding );
786    }
787
788    // Was this empty?
789    if ( !firstChild ) {
790        SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
791        return 0;
792    }
793
794    // All is well.
795    return p;
796}
797
798void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
799{
800    // The first error in a chain is more accurate - don't set again!
801    if ( error )
802        return;
803
804    assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
805    error = true;
806    errorId = err;
807    errorDesc = errorString[ errorId ];
808
809    errorLocation.Clear();
810    if ( pError && data )
811    {
812        data->Stamp( pError, encoding );
813        errorLocation = data->Cursor();
814    }
815}
816
817
818TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
819{
820    TiXmlNode* returnNode = 0;
821
822    p = SkipWhiteSpace( p, encoding );
823    if( !p || !*p || *p != '<' )
824    {
825        return 0;
826    }
827
828    TiXmlDocument* doc = GetDocument();
829    p = SkipWhiteSpace( p, encoding );
830
831    if ( !p || !*p )
832    {
833        return 0;
834    }
835
836    // What is this thing?
837    // - Elements start with a letter or underscore, but xml is reserved.
838    // - Comments: <!--
839    // - Decleration: <?xml
840    // - Everthing else is unknown to tinyxml.
841    //
842
843    const char* xmlHeader = { "<?xml" };
844    const char* commentHeader = { "<!--" };
845    const char* dtdHeader = { "<!" };
846    const char* cdataHeader = { "<![CDATA[" };
847
848    if ( StringEqual( p, xmlHeader, true, encoding ) )
849    {
850        #ifdef DEBUG_PARSER
851            TIXML_LOG( "XML parsing Declaration\n" );
852        #endif
853        returnNode = new TiXmlDeclaration();
854    }
855    else if ( StringEqual( p, commentHeader, false, encoding ) )
856    {
857        #ifdef DEBUG_PARSER
858            TIXML_LOG( "XML parsing Comment\n" );
859        #endif
860        returnNode = new TiXmlComment();
861    }
862    else if ( StringEqual( p, cdataHeader, false, encoding ) )
863    {
864        #ifdef DEBUG_PARSER
865            TIXML_LOG( "XML parsing CDATA\n" );
866        #endif
867        TiXmlText* text = new TiXmlText( "" );
868        text->SetCDATA( true );
869        returnNode = text;
870    }
871    else if ( StringEqual( p, dtdHeader, false, encoding ) )
872    {
873        #ifdef DEBUG_PARSER
874            TIXML_LOG( "XML parsing Unknown(1)\n" );
875        #endif
876        returnNode = new TiXmlUnknown();
877    }
878    else if ( IsAlpha( *(p+1), encoding )
879              || *(p+1) == '_' )
880    {
881        #ifdef DEBUG_PARSER
882            TIXML_LOG( "XML parsing Element\n" );
883        #endif
884        returnNode = new TiXmlElement( "" );
885    }
886    else
887    {
888        #ifdef DEBUG_PARSER
889            TIXML_LOG( "XML parsing Unknown(2)\n" );
890        #endif
891        returnNode = new TiXmlUnknown();
892    }
893
894    if ( returnNode )
895    {
896        // Set the parent, so it can report errors
897        returnNode->parent = this;
898    }
899    else
900    {
901        if ( doc )
902            doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
903    }
904    return returnNode;
905}
906
907#ifdef TIXML_USE_STL
908
909void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
910{
911    // We're called with some amount of pre-parsing. That is, some of "this"
912    // element is in "tag". Go ahead and stream to the closing ">"
913    while( in->good() )
914    {
915        int c = in->get();
916        if ( c <= 0 )
917        {
918            TiXmlDocument* document = GetDocument();
919            if ( document )
920                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
921            return;
922        }
923        (*tag) += (char) c ;
924
925        if ( c == '>' )
926            break;
927    }
928
929    if ( tag->length() < 3 ) return;
930
931    // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
932    // If not, identify and stream.
933
934    if ( tag->at( tag->length() - 1 ) == '>'
935         && tag->at( tag->length() - 2 ) == '/' )
936    {
937        // All good!
938        return;
939    }
940    else if ( tag->at( tag->length() - 1 ) == '>' )
941    {
942        // There is more. Could be:
943        // text
944        // cdata text (which looks like another node)
945        // closing tag
946        // another node.
947        for ( ;; )
948        {
949            StreamWhiteSpace( in, tag );
950
951            // Do we have text?
952            if ( in->good() && in->peek() != '<' )
953            {
954                // Yep, text.
955                TiXmlText text( "" );
956                text.StreamIn( in, tag );
957
958                // What follows text is a closing tag or another node.
959                // Go around again and figure it out.
960                continue;
961            }
962
963            // We now have either a closing tag...or another node.
964            // We should be at a "<", regardless.
965            if ( !in->good() ) return;
966            assert( in->peek() == '<' );
967            int tagIndex = (int) tag->length();
968
969            bool closingTag = false;
970            bool firstCharFound = false;
971
972            for( ;; )
973            {
974                if ( !in->good() )
975                    return;
976
977                int c = in->peek();
978                if ( c <= 0 )
979                {
980                    TiXmlDocument* document = GetDocument();
981                    if ( document )
982                        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
983                    return;
984                }
985
986                if ( c == '>' )
987                    break;
988
989                *tag += (char) c;
990                in->get();
991
992                // Early out if we find the CDATA id.
993                if ( c == '[' && tag->size() >= 9 )
994                {
995                    size_t len = tag->size();
996                    const char* start = tag->c_str() + len - 9;
997                    if ( strcmp( start, "<![CDATA[" ) == 0 ) {
998                        assert( !closingTag );
999                        break;
1000                    }
1001                }
1002
1003                if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
1004                {
1005                    firstCharFound = true;
1006                    if ( c == '/' )
1007                        closingTag = true;
1008                }
1009            }
1010            // If it was a closing tag, then read in the closing '>' to clean up the input stream.
1011            // If it was not, the streaming will be done by the tag.
1012            if ( closingTag )
1013            {
1014                if ( !in->good() )
1015                    return;
1016
1017                int c = in->get();
1018                if ( c <= 0 )
1019                {
1020                    TiXmlDocument* document = GetDocument();
1021                    if ( document )
1022                        document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1023                    return;
1024                }
1025                assert( c == '>' );
1026                *tag += (char) c;
1027
1028                // We are done, once we've found our closing tag.
1029                return;
1030            }
1031            else
1032            {
1033                // If not a closing tag, id it, and stream.
1034                const char* tagloc = tag->c_str() + tagIndex;
1035                TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
1036                if ( !node )
1037                    return;
1038                node->StreamIn( in, tag );
1039                delete node;
1040                node = 0;
1041
1042                // No return: go around from the beginning: text, closing tag, or node.
1043            }
1044        }
1045    }
1046}
1047#endif
1048
1049const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1050{
1051    p = SkipWhiteSpace( p, encoding );
1052    TiXmlDocument* document = GetDocument();
1053
1054    if ( !p || !*p )
1055    {
1056        if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
1057        return 0;
1058    }
1059
1060    if ( data )
1061    {
1062        data->Stamp( p, encoding );
1063        location = data->Cursor();
1064    }
1065
1066    if ( *p != '<' )
1067    {
1068        if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
1069        return 0;
1070    }
1071
1072    p = SkipWhiteSpace( p+1, encoding );
1073
1074    // Read the name.
1075    const char* pErr = p;
1076
1077    p = ReadName( p, &value, encoding );
1078    if ( !p || !*p )
1079    {
1080        if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
1081        return 0;
1082    }
1083
1084    TIXML_STRING endTag ("</");
1085    endTag += value;
1086    endTag += ">";
1087
1088    // Check for and read attributes. Also look for an empty
1089    // tag or an end tag.
1090    while ( p && *p )
1091    {
1092        pErr = p;
1093        p = SkipWhiteSpace( p, encoding );
1094        if ( !p || !*p )
1095        {
1096            if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1097            return 0;
1098        }
1099        if ( *p == '/' )
1100        {
1101            ++p;
1102            // Empty tag.
1103            if ( *p != '>' )
1104            {
1105                if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
1106                return 0;
1107            }
1108            return (p+1);
1109        }
1110        else if ( *p == '>' )
1111        {
1112            // Done with attributes (if there were any.)
1113            // Read the value -- which can include other
1114            // elements -- read the end tag, and return.
1115            ++p;
1116            p = ReadValue( p, data, encoding ); // Note this is an Element method, and will set the error if one happens.
1117            if ( !p || !*p ) {
1118                // We were looking for the end tag, but found nothing.
1119                // Fix for [ 1663758 ] Failure to report error on bad XML
1120                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1121                return 0;
1122            }
1123
1124            // We should find the end tag now
1125            if ( StringEqual( p, endTag.c_str(), false, encoding ) )
1126            {
1127                p += endTag.length();
1128                return p;
1129            }
1130            else
1131            {
1132                if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
1133                return 0;
1134            }
1135        }
1136        else
1137        {
1138            // Try to read an attribute:
1139            TiXmlAttribute* attrib = new TiXmlAttribute();
1140            if ( !attrib )
1141            {
1142                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
1143                return 0;
1144            }
1145
1146            attrib->SetDocument( document );
1147            pErr = p;
1148            p = attrib->Parse( p, data, encoding );
1149
1150            if ( !p || !*p )
1151            {
1152                if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
1153                delete attrib;
1154                return 0;
1155            }
1156
1157            // Handle the strange case of double attributes:
1158            #ifdef TIXML_USE_STL
1159            TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
1160            #else
1161            TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
1162            #endif
1163            if ( node )
1164            {
1165                node->SetValue( attrib->Value() );
1166                delete attrib;
1167                return 0;
1168            }
1169
1170            attributeSet.Add( attrib );
1171        }
1172    }
1173    return p;
1174}
1175
1176
1177const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1178{
1179    TiXmlDocument* document = GetDocument();
1180
1181    // Read in text and elements in any order.
1182    const char* pWithWhiteSpace = p;
1183    p = SkipWhiteSpace( p, encoding );
1184
1185    while ( p && *p )
1186    {
1187        if ( *p != '<' )
1188        {
1189            // Take what we have, make a text element.
1190            TiXmlText* textNode = new TiXmlText( "" );
1191
1192            if ( !textNode )
1193            {
1194                if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
1195                    return 0;
1196            }
1197
1198            if ( TiXmlBase::IsWhiteSpaceCondensed() )
1199            {
1200                p = textNode->Parse( p, data, encoding );
1201            }
1202            else
1203            {
1204                // Special case: we want to keep the white space
1205                // so that leading spaces aren't removed.
1206                p = textNode->Parse( pWithWhiteSpace, data, encoding );
1207            }
1208
1209            if ( !textNode->Blank() )
1210                LinkEndChild( textNode );
1211            else
1212                delete textNode;
1213        }
1214        else
1215        {
1216            // We hit a '<'
1217            // Have we hit a new element or an end tag? This could also be
1218            // a TiXmlText in the "CDATA" style.
1219            if ( StringEqual( p, "</", false, encoding ) )
1220            {
1221                return p;
1222            }
1223            else
1224            {
1225                TiXmlNode* node = Identify( p, encoding );
1226                if ( node )
1227                {
1228                    p = node->Parse( p, data, encoding );
1229                    LinkEndChild( node );
1230                }
1231                else
1232                {
1233                    return 0;
1234                }
1235            }
1236        }
1237        pWithWhiteSpace = p;
1238        p = SkipWhiteSpace( p, encoding );
1239    }
1240
1241    if ( !p )
1242    {
1243        if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
1244    }
1245    return p;
1246}
1247
1248
1249#ifdef TIXML_USE_STL
1250void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
1251{
1252    while ( in->good() )
1253    {
1254        int c = in->get();
1255        if ( c <= 0 )
1256        {
1257            TiXmlDocument* document = GetDocument();
1258            if ( document )
1259                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1260            return;
1261        }
1262        (*tag) += (char) c;
1263
1264        if ( c == '>' )
1265        {
1266            // All is well.
1267            return;
1268        }
1269    }
1270}
1271#endif
1272
1273
1274const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1275{
1276    TiXmlDocument* document = GetDocument();
1277    p = SkipWhiteSpace( p, encoding );
1278
1279    if ( data )
1280    {
1281        data->Stamp( p, encoding );
1282        location = data->Cursor();
1283    }
1284    if ( !p || !*p || *p != '<' )
1285    {
1286        if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
1287        return 0;
1288    }
1289    ++p;
1290    value = "";
1291
1292    while ( p && *p && *p != '>' )
1293    {
1294        value += *p;
1295        ++p;
1296    }
1297
1298    if ( !p )
1299    {
1300        if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
1301    }
1302    if ( *p == '>' )
1303        return p+1;
1304    return p;
1305}
1306
1307#ifdef TIXML_USE_STL
1308void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
1309{
1310    while ( in->good() )
1311    {
1312        int c = in->get();
1313        if ( c <= 0 )
1314        {
1315            TiXmlDocument* document = GetDocument();
1316            if ( document )
1317                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1318            return;
1319        }
1320
1321        (*tag) += (char) c;
1322
1323        if ( c == '>'
1324             && tag->at( tag->length() - 2 ) == '-'
1325             && tag->at( tag->length() - 3 ) == '-' )
1326        {
1327            // All is well.
1328            return;
1329        }
1330    }
1331}
1332#endif
1333
1334
1335const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1336{
1337    TiXmlDocument* document = GetDocument();
1338    value = "";
1339
1340    p = SkipWhiteSpace( p, encoding );
1341
1342    if ( data )
1343    {
1344        data->Stamp( p, encoding );
1345        location = data->Cursor();
1346    }
1347    const char* startTag = "<!--";
1348    const char* endTag = "-->";
1349
1350    if ( !StringEqual( p, startTag, false, encoding ) )
1351    {
1352        document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
1353        return 0;
1354    }
1355    p += strlen( startTag );
1356
1357    // [ 1475201 ] TinyXML parses entities in comments
1358    // Oops - ReadText doesn't work, because we don't want to parse the entities.
1359    // p = ReadText( p, &value, false, endTag, false, encoding );
1360    //
1361    // from the XML spec:
1362    /*
1363     [Definition: Comments may appear anywhere in a document outside other markup; in addition,
1364                  they may appear within the document type declaration at places allowed by the grammar.
1365                  They are not part of the document's character data; an XML processor MAY, but need not,
1366                  make it possible for an application to retrieve the text of comments. For compatibility,
1367                  the string "--" (double-hyphen) MUST NOT occur within comments.] Parameter entity
1368                  references MUST NOT be recognized within comments.
1369
1370                  An example of a comment:
1371
1372                  <!-- declarations for <head> & <body> -->
1373    */
1374
1375    value = "";
1376    // Keep all the white space.
1377    while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
1378    {
1379        value.append( p, 1 );
1380        ++p;
1381    }
1382    if ( p )
1383        p += strlen( endTag );
1384
1385    return p;
1386}
1387
1388
1389const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1390{
1391    p = SkipWhiteSpace( p, encoding );
1392    if ( !p || !*p ) return 0;
1393
1394// int tabsize = 4;
1395// if ( document )
1396// tabsize = document->TabSize();
1397
1398    if ( data )
1399    {
1400        data->Stamp( p, encoding );
1401        location = data->Cursor();
1402    }
1403    // Read the name, the '=' and the value.
1404    const char* pErr = p;
1405    p = ReadName( p, &name, encoding );
1406    if ( !p || !*p )
1407    {
1408        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
1409        return 0;
1410    }
1411    p = SkipWhiteSpace( p, encoding );
1412    if ( !p || !*p || *p != '=' )
1413    {
1414        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1415        return 0;
1416    }
1417
1418    ++p; // skip '='
1419    p = SkipWhiteSpace( p, encoding );
1420    if ( !p || !*p )
1421    {
1422        if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1423        return 0;
1424    }
1425
1426    const char* end;
1427    const char SINGLE_QUOTE = '\'';
1428    const char DOUBLE_QUOTE = '\"';
1429
1430    if ( *p == SINGLE_QUOTE )
1431    {
1432        ++p;
1433        end = "\'"; // single quote in string
1434        p = ReadText( p, &value, false, end, false, encoding );
1435    }
1436    else if ( *p == DOUBLE_QUOTE )
1437    {
1438        ++p;
1439        end = "\""; // double quote in string
1440        p = ReadText( p, &value, false, end, false, encoding );
1441    }
1442    else
1443    {
1444        // All attribute values should be in single or double quotes.
1445        // But this is such a common error that the parser will try
1446        // its best, even without them.
1447        value = "";
1448        while ( p && *p // existence
1449                && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r' // whitespace
1450                && *p != '/' && *p != '>' ) // tag end
1451        {
1452            if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
1453                // [ 1451649 ] Attribute values with trailing quotes not handled correctly
1454                // We did not have an opening quote but seem to have a
1455                // closing one. Give up and throw an error.
1456                if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
1457                return 0;
1458            }
1459            value += *p;
1460            ++p;
1461        }
1462    }
1463    return p;
1464}
1465
1466#ifdef TIXML_USE_STL
1467void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
1468{
1469    while ( in->good() )
1470    {
1471        int c = in->peek();
1472        if ( !cdata && (c == '<' ) )
1473        {
1474            return;
1475        }
1476        if ( c <= 0 )
1477        {
1478            TiXmlDocument* document = GetDocument();
1479            if ( document )
1480                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1481            return;
1482        }
1483
1484        (*tag) += (char) c;
1485        in->get(); // "commits" the peek made above
1486
1487        if ( cdata && c == '>' && tag->size() >= 3 ) {
1488            size_t len = tag->size();
1489            if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
1490                // terminator of cdata.
1491                return;
1492            }
1493        }
1494    }
1495}
1496#endif
1497
1498const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
1499{
1500    value = "";
1501    TiXmlDocument* document = GetDocument();
1502
1503    if ( data )
1504    {
1505        data->Stamp( p, encoding );
1506        location = data->Cursor();
1507    }
1508
1509    const char* const startTag = "<![CDATA[";
1510    const char* const endTag = "]]>";
1511
1512    if ( cdata || StringEqual( p, startTag, false, encoding ) )
1513    {
1514        cdata = true;
1515
1516        if ( !StringEqual( p, startTag, false, encoding ) )
1517        {
1518            document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
1519            return 0;
1520        }
1521        p += strlen( startTag );
1522
1523        // Keep all the white space, ignore the encoding, etc.
1524        while ( p && *p
1525                && !StringEqual( p, endTag, false, encoding )
1526              )
1527        {
1528            value += *p;
1529            ++p;
1530        }
1531
1532        TIXML_STRING dummy;
1533        p = ReadText( p, &dummy, false, endTag, false, encoding );
1534        return p;
1535    }
1536    else
1537    {
1538        bool ignoreWhite = true;
1539
1540        const char* end = "<";
1541        p = ReadText( p, &value, ignoreWhite, end, false, encoding );
1542        if ( p )
1543            return p-1; // don't truncate the '<'
1544        return 0;
1545    }
1546}
1547
1548#ifdef TIXML_USE_STL
1549void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
1550{
1551    while ( in->good() )
1552    {
1553        int c = in->get();
1554        if ( c <= 0 )
1555        {
1556            TiXmlDocument* document = GetDocument();
1557            if ( document )
1558                document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
1559            return;
1560        }
1561        (*tag) += (char) c;
1562
1563        if ( c == '>' )
1564        {
1565            // All is well.
1566            return;
1567        }
1568    }
1569}
1570#endif
1571
1572const char* TiXmlDeclaration::Parse( const char* p,