xref: /aosp_15_r20/external/tinyxml2/tinyxml2.cpp (revision 7485b22521f577cf944e5687361548d8993d8d2c)
1*7485b225SElliott Hughes /*
2*7485b225SElliott Hughes Original code by Lee Thomason (www.grinninglizard.com)
3*7485b225SElliott Hughes 
4*7485b225SElliott Hughes This software is provided 'as-is', without any express or implied
5*7485b225SElliott Hughes warranty. In no event will the authors be held liable for any
6*7485b225SElliott Hughes damages arising from the use of this software.
7*7485b225SElliott Hughes 
8*7485b225SElliott Hughes Permission is granted to anyone to use this software for any
9*7485b225SElliott Hughes purpose, including commercial applications, and to alter it and
10*7485b225SElliott Hughes redistribute it freely, subject to the following restrictions:
11*7485b225SElliott Hughes 
12*7485b225SElliott Hughes 1. The origin of this software must not be misrepresented; you must
13*7485b225SElliott Hughes not claim that you wrote the original software. If you use this
14*7485b225SElliott Hughes software in a product, an acknowledgment in the product documentation
15*7485b225SElliott Hughes would be appreciated but is not required.
16*7485b225SElliott Hughes 
17*7485b225SElliott Hughes 2. Altered source versions must be plainly marked as such, and
18*7485b225SElliott Hughes must not be misrepresented as being the original software.
19*7485b225SElliott Hughes 
20*7485b225SElliott Hughes 3. This notice may not be removed or altered from any source
21*7485b225SElliott Hughes distribution.
22*7485b225SElliott Hughes */
23*7485b225SElliott Hughes 
24*7485b225SElliott Hughes #include "tinyxml2.h"
25*7485b225SElliott Hughes 
26*7485b225SElliott Hughes #include <new>		// yes, this one new style header, is in the Android SDK.
27*7485b225SElliott Hughes #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
28*7485b225SElliott Hughes #   include <stddef.h>
29*7485b225SElliott Hughes #   include <stdarg.h>
30*7485b225SElliott Hughes #else
31*7485b225SElliott Hughes #   include <cstddef>
32*7485b225SElliott Hughes #   include <cstdarg>
33*7485b225SElliott Hughes #endif
34*7485b225SElliott Hughes 
35*7485b225SElliott Hughes #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
36*7485b225SElliott Hughes 	// Microsoft Visual Studio, version 2005 and higher. Not WinCE.
37*7485b225SElliott Hughes 	/*int _snprintf_s(
38*7485b225SElliott Hughes 	   char *buffer,
39*7485b225SElliott Hughes 	   size_t sizeOfBuffer,
40*7485b225SElliott Hughes 	   size_t count,
41*7485b225SElliott Hughes 	   const char *format [,
42*7485b225SElliott Hughes 		  argument] ...
43*7485b225SElliott Hughes 	);*/
TIXML_SNPRINTF(char * buffer,size_t size,const char * format,...)44*7485b225SElliott Hughes 	static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
45*7485b225SElliott Hughes 	{
46*7485b225SElliott Hughes 		va_list va;
47*7485b225SElliott Hughes 		va_start( va, format );
48*7485b225SElliott Hughes 		const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
49*7485b225SElliott Hughes 		va_end( va );
50*7485b225SElliott Hughes 		return result;
51*7485b225SElliott Hughes 	}
52*7485b225SElliott Hughes 
TIXML_VSNPRINTF(char * buffer,size_t size,const char * format,va_list va)53*7485b225SElliott Hughes 	static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
54*7485b225SElliott Hughes 	{
55*7485b225SElliott Hughes 		const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
56*7485b225SElliott Hughes 		return result;
57*7485b225SElliott Hughes 	}
58*7485b225SElliott Hughes 
59*7485b225SElliott Hughes 	#define TIXML_VSCPRINTF	_vscprintf
60*7485b225SElliott Hughes 	#define TIXML_SSCANF	sscanf_s
61*7485b225SElliott Hughes #elif defined _MSC_VER
62*7485b225SElliott Hughes 	// Microsoft Visual Studio 2003 and earlier or WinCE
63*7485b225SElliott Hughes 	#define TIXML_SNPRINTF	_snprintf
64*7485b225SElliott Hughes 	#define TIXML_VSNPRINTF _vsnprintf
65*7485b225SElliott Hughes 	#define TIXML_SSCANF	sscanf
66*7485b225SElliott Hughes 	#if (_MSC_VER < 1400 ) && (!defined WINCE)
67*7485b225SElliott Hughes 		// Microsoft Visual Studio 2003 and not WinCE.
68*7485b225SElliott Hughes 		#define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
69*7485b225SElliott Hughes 	#else
70*7485b225SElliott Hughes 		// Microsoft Visual Studio 2003 and earlier or WinCE.
TIXML_VSCPRINTF(const char * format,va_list va)71*7485b225SElliott Hughes 		static inline int TIXML_VSCPRINTF( const char* format, va_list va )
72*7485b225SElliott Hughes 		{
73*7485b225SElliott Hughes 			int len = 512;
74*7485b225SElliott Hughes 			for (;;) {
75*7485b225SElliott Hughes 				len = len*2;
76*7485b225SElliott Hughes 				char* str = new char[len]();
77*7485b225SElliott Hughes 				const int required = _vsnprintf(str, len, format, va);
78*7485b225SElliott Hughes 				delete[] str;
79*7485b225SElliott Hughes 				if ( required != -1 ) {
80*7485b225SElliott Hughes 					TIXMLASSERT( required >= 0 );
81*7485b225SElliott Hughes 					len = required;
82*7485b225SElliott Hughes 					break;
83*7485b225SElliott Hughes 				}
84*7485b225SElliott Hughes 			}
85*7485b225SElliott Hughes 			TIXMLASSERT( len >= 0 );
86*7485b225SElliott Hughes 			return len;
87*7485b225SElliott Hughes 		}
88*7485b225SElliott Hughes 	#endif
89*7485b225SElliott Hughes #else
90*7485b225SElliott Hughes 	// GCC version 3 and higher
91*7485b225SElliott Hughes 	//#warning( "Using sn* functions." )
92*7485b225SElliott Hughes 	#define TIXML_SNPRINTF	snprintf
93*7485b225SElliott Hughes 	#define TIXML_VSNPRINTF	vsnprintf
TIXML_VSCPRINTF(const char * format,va_list va)94*7485b225SElliott Hughes 	static inline int TIXML_VSCPRINTF( const char* format, va_list va )
95*7485b225SElliott Hughes 	{
96*7485b225SElliott Hughes 		int len = vsnprintf( 0, 0, format, va );
97*7485b225SElliott Hughes 		TIXMLASSERT( len >= 0 );
98*7485b225SElliott Hughes 		return len;
99*7485b225SElliott Hughes 	}
100*7485b225SElliott Hughes 	#define TIXML_SSCANF   sscanf
101*7485b225SElliott Hughes #endif
102*7485b225SElliott Hughes 
103*7485b225SElliott Hughes #if defined(_WIN64)
104*7485b225SElliott Hughes 	#define TIXML_FSEEK _fseeki64
105*7485b225SElliott Hughes 	#define TIXML_FTELL _ftelli64
106*7485b225SElliott Hughes #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || defined(__CYGWIN__)
107*7485b225SElliott Hughes 	#define TIXML_FSEEK fseeko
108*7485b225SElliott Hughes 	#define TIXML_FTELL ftello
109*7485b225SElliott Hughes #elif defined(__ANDROID__)
110*7485b225SElliott Hughes     #if __ANDROID_API__ > 24
111*7485b225SElliott Hughes         #define TIXML_FSEEK fseeko64
112*7485b225SElliott Hughes         #define TIXML_FTELL ftello64
113*7485b225SElliott Hughes     #else
114*7485b225SElliott Hughes         #define TIXML_FSEEK fseeko
115*7485b225SElliott Hughes         #define TIXML_FTELL ftello
116*7485b225SElliott Hughes     #endif
117*7485b225SElliott Hughes #else
118*7485b225SElliott Hughes 	#define TIXML_FSEEK fseek
119*7485b225SElliott Hughes 	#define TIXML_FTELL ftell
120*7485b225SElliott Hughes #endif
121*7485b225SElliott Hughes 
122*7485b225SElliott Hughes 
123*7485b225SElliott Hughes static const char LINE_FEED				= static_cast<char>(0x0a);			// all line endings are normalized to LF
124*7485b225SElliott Hughes static const char LF = LINE_FEED;
125*7485b225SElliott Hughes static const char CARRIAGE_RETURN		= static_cast<char>(0x0d);			// CR gets filtered out
126*7485b225SElliott Hughes static const char CR = CARRIAGE_RETURN;
127*7485b225SElliott Hughes static const char SINGLE_QUOTE			= '\'';
128*7485b225SElliott Hughes static const char DOUBLE_QUOTE			= '\"';
129*7485b225SElliott Hughes 
130*7485b225SElliott Hughes // Bunch of unicode info at:
131*7485b225SElliott Hughes //		http://www.unicode.org/faq/utf_bom.html
132*7485b225SElliott Hughes //	ef bb bf (Microsoft "lead bytes") - designates UTF-8
133*7485b225SElliott Hughes 
134*7485b225SElliott Hughes static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
135*7485b225SElliott Hughes static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
136*7485b225SElliott Hughes static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
137*7485b225SElliott Hughes 
138*7485b225SElliott Hughes namespace tinyxml2
139*7485b225SElliott Hughes {
140*7485b225SElliott Hughes 
141*7485b225SElliott Hughes struct Entity {
142*7485b225SElliott Hughes     const char* pattern;
143*7485b225SElliott Hughes     int length;
144*7485b225SElliott Hughes     char value;
145*7485b225SElliott Hughes };
146*7485b225SElliott Hughes 
147*7485b225SElliott Hughes static const int NUM_ENTITIES = 5;
148*7485b225SElliott Hughes static const Entity entities[NUM_ENTITIES] = {
149*7485b225SElliott Hughes     { "quot", 4,	DOUBLE_QUOTE },
150*7485b225SElliott Hughes     { "amp", 3,		'&'  },
151*7485b225SElliott Hughes     { "apos", 4,	SINGLE_QUOTE },
152*7485b225SElliott Hughes     { "lt",	2, 		'<'	 },
153*7485b225SElliott Hughes     { "gt",	2,		'>'	 }
154*7485b225SElliott Hughes };
155*7485b225SElliott Hughes 
156*7485b225SElliott Hughes 
~StrPair()157*7485b225SElliott Hughes StrPair::~StrPair()
158*7485b225SElliott Hughes {
159*7485b225SElliott Hughes     Reset();
160*7485b225SElliott Hughes }
161*7485b225SElliott Hughes 
162*7485b225SElliott Hughes 
TransferTo(StrPair * other)163*7485b225SElliott Hughes void StrPair::TransferTo( StrPair* other )
164*7485b225SElliott Hughes {
165*7485b225SElliott Hughes     if ( this == other ) {
166*7485b225SElliott Hughes         return;
167*7485b225SElliott Hughes     }
168*7485b225SElliott Hughes     // This in effect implements the assignment operator by "moving"
169*7485b225SElliott Hughes     // ownership (as in auto_ptr).
170*7485b225SElliott Hughes 
171*7485b225SElliott Hughes     TIXMLASSERT( other != 0 );
172*7485b225SElliott Hughes     TIXMLASSERT( other->_flags == 0 );
173*7485b225SElliott Hughes     TIXMLASSERT( other->_start == 0 );
174*7485b225SElliott Hughes     TIXMLASSERT( other->_end == 0 );
175*7485b225SElliott Hughes 
176*7485b225SElliott Hughes     other->Reset();
177*7485b225SElliott Hughes 
178*7485b225SElliott Hughes     other->_flags = _flags;
179*7485b225SElliott Hughes     other->_start = _start;
180*7485b225SElliott Hughes     other->_end = _end;
181*7485b225SElliott Hughes 
182*7485b225SElliott Hughes     _flags = 0;
183*7485b225SElliott Hughes     _start = 0;
184*7485b225SElliott Hughes     _end = 0;
185*7485b225SElliott Hughes }
186*7485b225SElliott Hughes 
187*7485b225SElliott Hughes 
Reset()188*7485b225SElliott Hughes void StrPair::Reset()
189*7485b225SElliott Hughes {
190*7485b225SElliott Hughes     if ( _flags & NEEDS_DELETE ) {
191*7485b225SElliott Hughes         delete [] _start;
192*7485b225SElliott Hughes     }
193*7485b225SElliott Hughes     _flags = 0;
194*7485b225SElliott Hughes     _start = 0;
195*7485b225SElliott Hughes     _end = 0;
196*7485b225SElliott Hughes }
197*7485b225SElliott Hughes 
198*7485b225SElliott Hughes 
SetStr(const char * str,int flags)199*7485b225SElliott Hughes void StrPair::SetStr( const char* str, int flags )
200*7485b225SElliott Hughes {
201*7485b225SElliott Hughes     TIXMLASSERT( str );
202*7485b225SElliott Hughes     Reset();
203*7485b225SElliott Hughes     size_t len = strlen( str );
204*7485b225SElliott Hughes     TIXMLASSERT( _start == 0 );
205*7485b225SElliott Hughes     _start = new char[ len+1 ];
206*7485b225SElliott Hughes     memcpy( _start, str, len+1 );
207*7485b225SElliott Hughes     _end = _start + len;
208*7485b225SElliott Hughes     _flags = flags | NEEDS_DELETE;
209*7485b225SElliott Hughes }
210*7485b225SElliott Hughes 
211*7485b225SElliott Hughes 
ParseText(char * p,const char * endTag,int strFlags,int * curLineNumPtr)212*7485b225SElliott Hughes char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
213*7485b225SElliott Hughes {
214*7485b225SElliott Hughes     TIXMLASSERT( p );
215*7485b225SElliott Hughes     TIXMLASSERT( endTag && *endTag );
216*7485b225SElliott Hughes 	TIXMLASSERT(curLineNumPtr);
217*7485b225SElliott Hughes 
218*7485b225SElliott Hughes     char* start = p;
219*7485b225SElliott Hughes     const char  endChar = *endTag;
220*7485b225SElliott Hughes     size_t length = strlen( endTag );
221*7485b225SElliott Hughes 
222*7485b225SElliott Hughes     // Inner loop of text parsing.
223*7485b225SElliott Hughes     while ( *p ) {
224*7485b225SElliott Hughes         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
225*7485b225SElliott Hughes             Set( start, p, strFlags );
226*7485b225SElliott Hughes             return p + length;
227*7485b225SElliott Hughes         } else if (*p == '\n') {
228*7485b225SElliott Hughes             ++(*curLineNumPtr);
229*7485b225SElliott Hughes         }
230*7485b225SElliott Hughes         ++p;
231*7485b225SElliott Hughes         TIXMLASSERT( p );
232*7485b225SElliott Hughes     }
233*7485b225SElliott Hughes     return 0;
234*7485b225SElliott Hughes }
235*7485b225SElliott Hughes 
236*7485b225SElliott Hughes 
ParseName(char * p)237*7485b225SElliott Hughes char* StrPair::ParseName( char* p )
238*7485b225SElliott Hughes {
239*7485b225SElliott Hughes     if ( !p || !(*p) ) {
240*7485b225SElliott Hughes         return 0;
241*7485b225SElliott Hughes     }
242*7485b225SElliott Hughes     if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
243*7485b225SElliott Hughes         return 0;
244*7485b225SElliott Hughes     }
245*7485b225SElliott Hughes 
246*7485b225SElliott Hughes     char* const start = p;
247*7485b225SElliott Hughes     ++p;
248*7485b225SElliott Hughes     while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {
249*7485b225SElliott Hughes         ++p;
250*7485b225SElliott Hughes     }
251*7485b225SElliott Hughes 
252*7485b225SElliott Hughes     Set( start, p, 0 );
253*7485b225SElliott Hughes     return p;
254*7485b225SElliott Hughes }
255*7485b225SElliott Hughes 
256*7485b225SElliott Hughes 
CollapseWhitespace()257*7485b225SElliott Hughes void StrPair::CollapseWhitespace()
258*7485b225SElliott Hughes {
259*7485b225SElliott Hughes     // Adjusting _start would cause undefined behavior on delete[]
260*7485b225SElliott Hughes     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
261*7485b225SElliott Hughes     // Trim leading space.
262*7485b225SElliott Hughes     _start = XMLUtil::SkipWhiteSpace( _start, 0 );
263*7485b225SElliott Hughes 
264*7485b225SElliott Hughes     if ( *_start ) {
265*7485b225SElliott Hughes         const char* p = _start;	// the read pointer
266*7485b225SElliott Hughes         char* q = _start;	// the write pointer
267*7485b225SElliott Hughes 
268*7485b225SElliott Hughes         while( *p ) {
269*7485b225SElliott Hughes             if ( XMLUtil::IsWhiteSpace( *p )) {
270*7485b225SElliott Hughes                 p = XMLUtil::SkipWhiteSpace( p, 0 );
271*7485b225SElliott Hughes                 if ( *p == 0 ) {
272*7485b225SElliott Hughes                     break;    // don't write to q; this trims the trailing space.
273*7485b225SElliott Hughes                 }
274*7485b225SElliott Hughes                 *q = ' ';
275*7485b225SElliott Hughes                 ++q;
276*7485b225SElliott Hughes             }
277*7485b225SElliott Hughes             *q = *p;
278*7485b225SElliott Hughes             ++q;
279*7485b225SElliott Hughes             ++p;
280*7485b225SElliott Hughes         }
281*7485b225SElliott Hughes         *q = 0;
282*7485b225SElliott Hughes     }
283*7485b225SElliott Hughes }
284*7485b225SElliott Hughes 
285*7485b225SElliott Hughes 
GetStr()286*7485b225SElliott Hughes const char* StrPair::GetStr()
287*7485b225SElliott Hughes {
288*7485b225SElliott Hughes     TIXMLASSERT( _start );
289*7485b225SElliott Hughes     TIXMLASSERT( _end );
290*7485b225SElliott Hughes     if ( _flags & NEEDS_FLUSH ) {
291*7485b225SElliott Hughes         *_end = 0;
292*7485b225SElliott Hughes         _flags ^= NEEDS_FLUSH;
293*7485b225SElliott Hughes 
294*7485b225SElliott Hughes         if ( _flags ) {
295*7485b225SElliott Hughes             const char* p = _start;	// the read pointer
296*7485b225SElliott Hughes             char* q = _start;	// the write pointer
297*7485b225SElliott Hughes 
298*7485b225SElliott Hughes             while( p < _end ) {
299*7485b225SElliott Hughes                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
300*7485b225SElliott Hughes                     // CR-LF pair becomes LF
301*7485b225SElliott Hughes                     // CR alone becomes LF
302*7485b225SElliott Hughes                     // LF-CR becomes LF
303*7485b225SElliott Hughes                     if ( *(p+1) == LF ) {
304*7485b225SElliott Hughes                         p += 2;
305*7485b225SElliott Hughes                     }
306*7485b225SElliott Hughes                     else {
307*7485b225SElliott Hughes                         ++p;
308*7485b225SElliott Hughes                     }
309*7485b225SElliott Hughes                     *q = LF;
310*7485b225SElliott Hughes                     ++q;
311*7485b225SElliott Hughes                 }
312*7485b225SElliott Hughes                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
313*7485b225SElliott Hughes                     if ( *(p+1) == CR ) {
314*7485b225SElliott Hughes                         p += 2;
315*7485b225SElliott Hughes                     }
316*7485b225SElliott Hughes                     else {
317*7485b225SElliott Hughes                         ++p;
318*7485b225SElliott Hughes                     }
319*7485b225SElliott Hughes                     *q = LF;
320*7485b225SElliott Hughes                     ++q;
321*7485b225SElliott Hughes                 }
322*7485b225SElliott Hughes                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
323*7485b225SElliott Hughes                     // Entities handled by tinyXML2:
324*7485b225SElliott Hughes                     // - special entities in the entity table [in/out]
325*7485b225SElliott Hughes                     // - numeric character reference [in]
326*7485b225SElliott Hughes                     //   &#20013; or &#x4e2d;
327*7485b225SElliott Hughes 
328*7485b225SElliott Hughes                     if ( *(p+1) == '#' ) {
329*7485b225SElliott Hughes                         const int buflen = 10;
330*7485b225SElliott Hughes                         char buf[buflen] = { 0 };
331*7485b225SElliott Hughes                         int len = 0;
332*7485b225SElliott Hughes                         const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
333*7485b225SElliott Hughes                         if ( adjusted == 0 ) {
334*7485b225SElliott Hughes                             *q = *p;
335*7485b225SElliott Hughes                             ++p;
336*7485b225SElliott Hughes                             ++q;
337*7485b225SElliott Hughes                         }
338*7485b225SElliott Hughes                         else {
339*7485b225SElliott Hughes                             TIXMLASSERT( 0 <= len && len <= buflen );
340*7485b225SElliott Hughes                             TIXMLASSERT( q + len <= adjusted );
341*7485b225SElliott Hughes                             p = adjusted;
342*7485b225SElliott Hughes                             memcpy( q, buf, len );
343*7485b225SElliott Hughes                             q += len;
344*7485b225SElliott Hughes                         }
345*7485b225SElliott Hughes                     }
346*7485b225SElliott Hughes                     else {
347*7485b225SElliott Hughes                         bool entityFound = false;
348*7485b225SElliott Hughes                         for( int i = 0; i < NUM_ENTITIES; ++i ) {
349*7485b225SElliott Hughes                             const Entity& entity = entities[i];
350*7485b225SElliott Hughes                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
351*7485b225SElliott Hughes                                     && *( p + entity.length + 1 ) == ';' ) {
352*7485b225SElliott Hughes                                 // Found an entity - convert.
353*7485b225SElliott Hughes                                 *q = entity.value;
354*7485b225SElliott Hughes                                 ++q;
355*7485b225SElliott Hughes                                 p += entity.length + 2;
356*7485b225SElliott Hughes                                 entityFound = true;
357*7485b225SElliott Hughes                                 break;
358*7485b225SElliott Hughes                             }
359*7485b225SElliott Hughes                         }
360*7485b225SElliott Hughes                         if ( !entityFound ) {
361*7485b225SElliott Hughes                             // fixme: treat as error?
362*7485b225SElliott Hughes                             ++p;
363*7485b225SElliott Hughes                             ++q;
364*7485b225SElliott Hughes                         }
365*7485b225SElliott Hughes                     }
366*7485b225SElliott Hughes                 }
367*7485b225SElliott Hughes                 else {
368*7485b225SElliott Hughes                     *q = *p;
369*7485b225SElliott Hughes                     ++p;
370*7485b225SElliott Hughes                     ++q;
371*7485b225SElliott Hughes                 }
372*7485b225SElliott Hughes             }
373*7485b225SElliott Hughes             *q = 0;
374*7485b225SElliott Hughes         }
375*7485b225SElliott Hughes         // The loop below has plenty going on, and this
376*7485b225SElliott Hughes         // is a less useful mode. Break it out.
377*7485b225SElliott Hughes         if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
378*7485b225SElliott Hughes             CollapseWhitespace();
379*7485b225SElliott Hughes         }
380*7485b225SElliott Hughes         _flags = (_flags & NEEDS_DELETE);
381*7485b225SElliott Hughes     }
382*7485b225SElliott Hughes     TIXMLASSERT( _start );
383*7485b225SElliott Hughes     return _start;
384*7485b225SElliott Hughes }
385*7485b225SElliott Hughes 
386*7485b225SElliott Hughes 
387*7485b225SElliott Hughes 
388*7485b225SElliott Hughes 
389*7485b225SElliott Hughes // --------- XMLUtil ----------- //
390*7485b225SElliott Hughes 
391*7485b225SElliott Hughes const char* XMLUtil::writeBoolTrue  = "true";
392*7485b225SElliott Hughes const char* XMLUtil::writeBoolFalse = "false";
393*7485b225SElliott Hughes 
SetBoolSerialization(const char * writeTrue,const char * writeFalse)394*7485b225SElliott Hughes void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
395*7485b225SElliott Hughes {
396*7485b225SElliott Hughes 	static const char* defTrue  = "true";
397*7485b225SElliott Hughes 	static const char* defFalse = "false";
398*7485b225SElliott Hughes 
399*7485b225SElliott Hughes 	writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
400*7485b225SElliott Hughes 	writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
401*7485b225SElliott Hughes }
402*7485b225SElliott Hughes 
403*7485b225SElliott Hughes 
ReadBOM(const char * p,bool * bom)404*7485b225SElliott Hughes const char* XMLUtil::ReadBOM( const char* p, bool* bom )
405*7485b225SElliott Hughes {
406*7485b225SElliott Hughes     TIXMLASSERT( p );
407*7485b225SElliott Hughes     TIXMLASSERT( bom );
408*7485b225SElliott Hughes     *bom = false;
409*7485b225SElliott Hughes     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
410*7485b225SElliott Hughes     // Check for BOM:
411*7485b225SElliott Hughes     if (    *(pu+0) == TIXML_UTF_LEAD_0
412*7485b225SElliott Hughes             && *(pu+1) == TIXML_UTF_LEAD_1
413*7485b225SElliott Hughes             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
414*7485b225SElliott Hughes         *bom = true;
415*7485b225SElliott Hughes         p += 3;
416*7485b225SElliott Hughes     }
417*7485b225SElliott Hughes     TIXMLASSERT( p );
418*7485b225SElliott Hughes     return p;
419*7485b225SElliott Hughes }
420*7485b225SElliott Hughes 
421*7485b225SElliott Hughes 
ConvertUTF32ToUTF8(unsigned long input,char * output,int * length)422*7485b225SElliott Hughes void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
423*7485b225SElliott Hughes {
424*7485b225SElliott Hughes     const unsigned long BYTE_MASK = 0xBF;
425*7485b225SElliott Hughes     const unsigned long BYTE_MARK = 0x80;
426*7485b225SElliott Hughes     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
427*7485b225SElliott Hughes 
428*7485b225SElliott Hughes     if (input < 0x80) {
429*7485b225SElliott Hughes         *length = 1;
430*7485b225SElliott Hughes     }
431*7485b225SElliott Hughes     else if ( input < 0x800 ) {
432*7485b225SElliott Hughes         *length = 2;
433*7485b225SElliott Hughes     }
434*7485b225SElliott Hughes     else if ( input < 0x10000 ) {
435*7485b225SElliott Hughes         *length = 3;
436*7485b225SElliott Hughes     }
437*7485b225SElliott Hughes     else if ( input < 0x200000 ) {
438*7485b225SElliott Hughes         *length = 4;
439*7485b225SElliott Hughes     }
440*7485b225SElliott Hughes     else {
441*7485b225SElliott Hughes         *length = 0;    // This code won't convert this correctly anyway.
442*7485b225SElliott Hughes         return;
443*7485b225SElliott Hughes     }
444*7485b225SElliott Hughes 
445*7485b225SElliott Hughes     output += *length;
446*7485b225SElliott Hughes 
447*7485b225SElliott Hughes     // Scary scary fall throughs are annotated with carefully designed comments
448*7485b225SElliott Hughes     // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
449*7485b225SElliott Hughes     switch (*length) {
450*7485b225SElliott Hughes         case 4:
451*7485b225SElliott Hughes             --output;
452*7485b225SElliott Hughes             *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
453*7485b225SElliott Hughes             input >>= 6;
454*7485b225SElliott Hughes             //fall through
455*7485b225SElliott Hughes         case 3:
456*7485b225SElliott Hughes             --output;
457*7485b225SElliott Hughes             *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
458*7485b225SElliott Hughes             input >>= 6;
459*7485b225SElliott Hughes             //fall through
460*7485b225SElliott Hughes         case 2:
461*7485b225SElliott Hughes             --output;
462*7485b225SElliott Hughes             *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
463*7485b225SElliott Hughes             input >>= 6;
464*7485b225SElliott Hughes             //fall through
465*7485b225SElliott Hughes         case 1:
466*7485b225SElliott Hughes             --output;
467*7485b225SElliott Hughes             *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
468*7485b225SElliott Hughes             break;
469*7485b225SElliott Hughes         default:
470*7485b225SElliott Hughes             TIXMLASSERT( false );
471*7485b225SElliott Hughes     }
472*7485b225SElliott Hughes }
473*7485b225SElliott Hughes 
474*7485b225SElliott Hughes 
GetCharacterRef(const char * p,char * value,int * length)475*7485b225SElliott Hughes const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
476*7485b225SElliott Hughes {
477*7485b225SElliott Hughes     // Presume an entity, and pull it out.
478*7485b225SElliott Hughes     *length = 0;
479*7485b225SElliott Hughes 
480*7485b225SElliott Hughes     if ( *(p+1) == '#' && *(p+2) ) {
481*7485b225SElliott Hughes         unsigned long ucs = 0;
482*7485b225SElliott Hughes         TIXMLASSERT( sizeof( ucs ) >= 4 );
483*7485b225SElliott Hughes         ptrdiff_t delta = 0;
484*7485b225SElliott Hughes         unsigned mult = 1;
485*7485b225SElliott Hughes         static const char SEMICOLON = ';';
486*7485b225SElliott Hughes 
487*7485b225SElliott Hughes         if ( *(p+2) == 'x' ) {
488*7485b225SElliott Hughes             // Hexadecimal.
489*7485b225SElliott Hughes             const char* q = p+3;
490*7485b225SElliott Hughes             if ( !(*q) ) {
491*7485b225SElliott Hughes                 return 0;
492*7485b225SElliott Hughes             }
493*7485b225SElliott Hughes 
494*7485b225SElliott Hughes             q = strchr( q, SEMICOLON );
495*7485b225SElliott Hughes 
496*7485b225SElliott Hughes             if ( !q ) {
497*7485b225SElliott Hughes                 return 0;
498*7485b225SElliott Hughes             }
499*7485b225SElliott Hughes             TIXMLASSERT( *q == SEMICOLON );
500*7485b225SElliott Hughes 
501*7485b225SElliott Hughes             delta = q-p;
502*7485b225SElliott Hughes             --q;
503*7485b225SElliott Hughes 
504*7485b225SElliott Hughes             while ( *q != 'x' ) {
505*7485b225SElliott Hughes                 unsigned int digit = 0;
506*7485b225SElliott Hughes 
507*7485b225SElliott Hughes                 if ( *q >= '0' && *q <= '9' ) {
508*7485b225SElliott Hughes                     digit = *q - '0';
509*7485b225SElliott Hughes                 }
510*7485b225SElliott Hughes                 else if ( *q >= 'a' && *q <= 'f' ) {
511*7485b225SElliott Hughes                     digit = *q - 'a' + 10;
512*7485b225SElliott Hughes                 }
513*7485b225SElliott Hughes                 else if ( *q >= 'A' && *q <= 'F' ) {
514*7485b225SElliott Hughes                     digit = *q - 'A' + 10;
515*7485b225SElliott Hughes                 }
516*7485b225SElliott Hughes                 else {
517*7485b225SElliott Hughes                     return 0;
518*7485b225SElliott Hughes                 }
519*7485b225SElliott Hughes                 TIXMLASSERT( digit < 16 );
520*7485b225SElliott Hughes                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
521*7485b225SElliott Hughes                 const unsigned int digitScaled = mult * digit;
522*7485b225SElliott Hughes                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
523*7485b225SElliott Hughes                 ucs += digitScaled;
524*7485b225SElliott Hughes                 TIXMLASSERT( mult <= UINT_MAX / 16 );
525*7485b225SElliott Hughes                 mult *= 16;
526*7485b225SElliott Hughes                 --q;
527*7485b225SElliott Hughes             }
528*7485b225SElliott Hughes         }
529*7485b225SElliott Hughes         else {
530*7485b225SElliott Hughes             // Decimal.
531*7485b225SElliott Hughes             const char* q = p+2;
532*7485b225SElliott Hughes             if ( !(*q) ) {
533*7485b225SElliott Hughes                 return 0;
534*7485b225SElliott Hughes             }
535*7485b225SElliott Hughes 
536*7485b225SElliott Hughes             q = strchr( q, SEMICOLON );
537*7485b225SElliott Hughes 
538*7485b225SElliott Hughes             if ( !q ) {
539*7485b225SElliott Hughes                 return 0;
540*7485b225SElliott Hughes             }
541*7485b225SElliott Hughes             TIXMLASSERT( *q == SEMICOLON );
542*7485b225SElliott Hughes 
543*7485b225SElliott Hughes             delta = q-p;
544*7485b225SElliott Hughes             --q;
545*7485b225SElliott Hughes 
546*7485b225SElliott Hughes             while ( *q != '#' ) {
547*7485b225SElliott Hughes                 if ( *q >= '0' && *q <= '9' ) {
548*7485b225SElliott Hughes                     const unsigned int digit = *q - '0';
549*7485b225SElliott Hughes                     TIXMLASSERT( digit < 10 );
550*7485b225SElliott Hughes                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
551*7485b225SElliott Hughes                     const unsigned int digitScaled = mult * digit;
552*7485b225SElliott Hughes                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
553*7485b225SElliott Hughes                     ucs += digitScaled;
554*7485b225SElliott Hughes                 }
555*7485b225SElliott Hughes                 else {
556*7485b225SElliott Hughes                     return 0;
557*7485b225SElliott Hughes                 }
558*7485b225SElliott Hughes                 TIXMLASSERT( mult <= UINT_MAX / 10 );
559*7485b225SElliott Hughes                 mult *= 10;
560*7485b225SElliott Hughes                 --q;
561*7485b225SElliott Hughes             }
562*7485b225SElliott Hughes         }
563*7485b225SElliott Hughes         // convert the UCS to UTF-8
564*7485b225SElliott Hughes         ConvertUTF32ToUTF8( ucs, value, length );
565*7485b225SElliott Hughes         return p + delta + 1;
566*7485b225SElliott Hughes     }
567*7485b225SElliott Hughes     return p+1;
568*7485b225SElliott Hughes }
569*7485b225SElliott Hughes 
570*7485b225SElliott Hughes 
ToStr(int v,char * buffer,int bufferSize)571*7485b225SElliott Hughes void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
572*7485b225SElliott Hughes {
573*7485b225SElliott Hughes     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
574*7485b225SElliott Hughes }
575*7485b225SElliott Hughes 
576*7485b225SElliott Hughes 
ToStr(unsigned v,char * buffer,int bufferSize)577*7485b225SElliott Hughes void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
578*7485b225SElliott Hughes {
579*7485b225SElliott Hughes     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
580*7485b225SElliott Hughes }
581*7485b225SElliott Hughes 
582*7485b225SElliott Hughes 
ToStr(bool v,char * buffer,int bufferSize)583*7485b225SElliott Hughes void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
584*7485b225SElliott Hughes {
585*7485b225SElliott Hughes     TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
586*7485b225SElliott Hughes }
587*7485b225SElliott Hughes 
588*7485b225SElliott Hughes /*
589*7485b225SElliott Hughes 	ToStr() of a number is a very tricky topic.
590*7485b225SElliott Hughes 	https://github.com/leethomason/tinyxml2/issues/106
591*7485b225SElliott Hughes */
ToStr(float v,char * buffer,int bufferSize)592*7485b225SElliott Hughes void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
593*7485b225SElliott Hughes {
594*7485b225SElliott Hughes     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
595*7485b225SElliott Hughes }
596*7485b225SElliott Hughes 
597*7485b225SElliott Hughes 
ToStr(double v,char * buffer,int bufferSize)598*7485b225SElliott Hughes void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
599*7485b225SElliott Hughes {
600*7485b225SElliott Hughes     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
601*7485b225SElliott Hughes }
602*7485b225SElliott Hughes 
603*7485b225SElliott Hughes 
ToStr(int64_t v,char * buffer,int bufferSize)604*7485b225SElliott Hughes void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
605*7485b225SElliott Hughes {
606*7485b225SElliott Hughes 	// horrible syntax trick to make the compiler happy about %lld
607*7485b225SElliott Hughes 	TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v));
608*7485b225SElliott Hughes }
609*7485b225SElliott Hughes 
ToStr(uint64_t v,char * buffer,int bufferSize)610*7485b225SElliott Hughes void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
611*7485b225SElliott Hughes {
612*7485b225SElliott Hughes     // horrible syntax trick to make the compiler happy about %llu
613*7485b225SElliott Hughes     TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v);
614*7485b225SElliott Hughes }
615*7485b225SElliott Hughes 
ToInt(const char * str,int * value)616*7485b225SElliott Hughes bool XMLUtil::ToInt(const char* str, int* value)
617*7485b225SElliott Hughes {
618*7485b225SElliott Hughes     if (IsPrefixHex(str)) {
619*7485b225SElliott Hughes         unsigned v;
620*7485b225SElliott Hughes         if (TIXML_SSCANF(str, "%x", &v) == 1) {
621*7485b225SElliott Hughes             *value = static_cast<int>(v);
622*7485b225SElliott Hughes             return true;
623*7485b225SElliott Hughes         }
624*7485b225SElliott Hughes     }
625*7485b225SElliott Hughes     else {
626*7485b225SElliott Hughes         if (TIXML_SSCANF(str, "%d", value) == 1) {
627*7485b225SElliott Hughes             return true;
628*7485b225SElliott Hughes         }
629*7485b225SElliott Hughes     }
630*7485b225SElliott Hughes     return false;
631*7485b225SElliott Hughes }
632*7485b225SElliott Hughes 
ToUnsigned(const char * str,unsigned * value)633*7485b225SElliott Hughes bool XMLUtil::ToUnsigned(const char* str, unsigned* value)
634*7485b225SElliott Hughes {
635*7485b225SElliott Hughes     if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) {
636*7485b225SElliott Hughes         return true;
637*7485b225SElliott Hughes     }
638*7485b225SElliott Hughes     return false;
639*7485b225SElliott Hughes }
640*7485b225SElliott Hughes 
ToBool(const char * str,bool * value)641*7485b225SElliott Hughes bool XMLUtil::ToBool( const char* str, bool* value )
642*7485b225SElliott Hughes {
643*7485b225SElliott Hughes     int ival = 0;
644*7485b225SElliott Hughes     if ( ToInt( str, &ival )) {
645*7485b225SElliott Hughes         *value = (ival==0) ? false : true;
646*7485b225SElliott Hughes         return true;
647*7485b225SElliott Hughes     }
648*7485b225SElliott Hughes     static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 };
649*7485b225SElliott Hughes     static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 };
650*7485b225SElliott Hughes 
651*7485b225SElliott Hughes     for (int i = 0; TRUE_VALS[i]; ++i) {
652*7485b225SElliott Hughes         if (StringEqual(str, TRUE_VALS[i])) {
653*7485b225SElliott Hughes             *value = true;
654*7485b225SElliott Hughes             return true;
655*7485b225SElliott Hughes         }
656*7485b225SElliott Hughes     }
657*7485b225SElliott Hughes     for (int i = 0; FALSE_VALS[i]; ++i) {
658*7485b225SElliott Hughes         if (StringEqual(str, FALSE_VALS[i])) {
659*7485b225SElliott Hughes             *value = false;
660*7485b225SElliott Hughes             return true;
661*7485b225SElliott Hughes         }
662*7485b225SElliott Hughes     }
663*7485b225SElliott Hughes     return false;
664*7485b225SElliott Hughes }
665*7485b225SElliott Hughes 
666*7485b225SElliott Hughes 
ToFloat(const char * str,float * value)667*7485b225SElliott Hughes bool XMLUtil::ToFloat( const char* str, float* value )
668*7485b225SElliott Hughes {
669*7485b225SElliott Hughes     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
670*7485b225SElliott Hughes         return true;
671*7485b225SElliott Hughes     }
672*7485b225SElliott Hughes     return false;
673*7485b225SElliott Hughes }
674*7485b225SElliott Hughes 
675*7485b225SElliott Hughes 
ToDouble(const char * str,double * value)676*7485b225SElliott Hughes bool XMLUtil::ToDouble( const char* str, double* value )
677*7485b225SElliott Hughes {
678*7485b225SElliott Hughes     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
679*7485b225SElliott Hughes         return true;
680*7485b225SElliott Hughes     }
681*7485b225SElliott Hughes     return false;
682*7485b225SElliott Hughes }
683*7485b225SElliott Hughes 
684*7485b225SElliott Hughes 
ToInt64(const char * str,int64_t * value)685*7485b225SElliott Hughes bool XMLUtil::ToInt64(const char* str, int64_t* value)
686*7485b225SElliott Hughes {
687*7485b225SElliott Hughes     if (IsPrefixHex(str)) {
688*7485b225SElliott Hughes         unsigned long long v = 0;	// horrible syntax trick to make the compiler happy about %llx
689*7485b225SElliott Hughes         if (TIXML_SSCANF(str, "%llx", &v) == 1) {
690*7485b225SElliott Hughes             *value = static_cast<int64_t>(v);
691*7485b225SElliott Hughes             return true;
692*7485b225SElliott Hughes         }
693*7485b225SElliott Hughes     }
694*7485b225SElliott Hughes     else {
695*7485b225SElliott Hughes         long long v = 0;	// horrible syntax trick to make the compiler happy about %lld
696*7485b225SElliott Hughes         if (TIXML_SSCANF(str, "%lld", &v) == 1) {
697*7485b225SElliott Hughes             *value = static_cast<int64_t>(v);
698*7485b225SElliott Hughes             return true;
699*7485b225SElliott Hughes         }
700*7485b225SElliott Hughes     }
701*7485b225SElliott Hughes 	return false;
702*7485b225SElliott Hughes }
703*7485b225SElliott Hughes 
704*7485b225SElliott Hughes 
ToUnsigned64(const char * str,uint64_t * value)705*7485b225SElliott Hughes bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
706*7485b225SElliott Hughes     unsigned long long v = 0;	// horrible syntax trick to make the compiler happy about %llu
707*7485b225SElliott Hughes     if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
708*7485b225SElliott Hughes         *value = (uint64_t)v;
709*7485b225SElliott Hughes         return true;
710*7485b225SElliott Hughes     }
711*7485b225SElliott Hughes     return false;
712*7485b225SElliott Hughes }
713*7485b225SElliott Hughes 
714*7485b225SElliott Hughes 
Identify(char * p,XMLNode ** node,bool first)715*7485b225SElliott Hughes char* XMLDocument::Identify( char* p, XMLNode** node, bool first )
716*7485b225SElliott Hughes {
717*7485b225SElliott Hughes     TIXMLASSERT( node );
718*7485b225SElliott Hughes     TIXMLASSERT( p );
719*7485b225SElliott Hughes     char* const start = p;
720*7485b225SElliott Hughes     int const startLine = _parseCurLineNum;
721*7485b225SElliott Hughes     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
722*7485b225SElliott Hughes     if( !*p ) {
723*7485b225SElliott Hughes         *node = 0;
724*7485b225SElliott Hughes         TIXMLASSERT( p );
725*7485b225SElliott Hughes         return p;
726*7485b225SElliott Hughes     }
727*7485b225SElliott Hughes 
728*7485b225SElliott Hughes     // These strings define the matching patterns:
729*7485b225SElliott Hughes     static const char* xmlHeader		= { "<?" };
730*7485b225SElliott Hughes     static const char* commentHeader	= { "<!--" };
731*7485b225SElliott Hughes     static const char* cdataHeader		= { "<![CDATA[" };
732*7485b225SElliott Hughes     static const char* dtdHeader		= { "<!" };
733*7485b225SElliott Hughes     static const char* elementHeader	= { "<" };	// and a header for everything else; check last.
734*7485b225SElliott Hughes 
735*7485b225SElliott Hughes     static const int xmlHeaderLen		= 2;
736*7485b225SElliott Hughes     static const int commentHeaderLen	= 4;
737*7485b225SElliott Hughes     static const int cdataHeaderLen		= 9;
738*7485b225SElliott Hughes     static const int dtdHeaderLen		= 2;
739*7485b225SElliott Hughes     static const int elementHeaderLen	= 1;
740*7485b225SElliott Hughes 
741*7485b225SElliott Hughes     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
742*7485b225SElliott Hughes     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
743*7485b225SElliott Hughes     XMLNode* returnNode = 0;
744*7485b225SElliott Hughes     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
745*7485b225SElliott Hughes         returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
746*7485b225SElliott Hughes         returnNode->_parseLineNum = _parseCurLineNum;
747*7485b225SElliott Hughes         p += xmlHeaderLen;
748*7485b225SElliott Hughes     }
749*7485b225SElliott Hughes     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
750*7485b225SElliott Hughes         returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
751*7485b225SElliott Hughes         returnNode->_parseLineNum = _parseCurLineNum;
752*7485b225SElliott Hughes         p += commentHeaderLen;
753*7485b225SElliott Hughes     }
754*7485b225SElliott Hughes     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
755*7485b225SElliott Hughes         XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
756*7485b225SElliott Hughes         returnNode = text;
757*7485b225SElliott Hughes         returnNode->_parseLineNum = _parseCurLineNum;
758*7485b225SElliott Hughes         p += cdataHeaderLen;
759*7485b225SElliott Hughes         text->SetCData( true );
760*7485b225SElliott Hughes     }
761*7485b225SElliott Hughes     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
762*7485b225SElliott Hughes         returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
763*7485b225SElliott Hughes         returnNode->_parseLineNum = _parseCurLineNum;
764*7485b225SElliott Hughes         p += dtdHeaderLen;
765*7485b225SElliott Hughes     }
766*7485b225SElliott Hughes     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
767*7485b225SElliott Hughes 
768*7485b225SElliott Hughes         // Preserve whitespace pedantically before closing tag, when it's immediately after opening tag
769*7485b225SElliott Hughes         if (WhitespaceMode() == PEDANTIC_WHITESPACE && first && p != start && *(p + elementHeaderLen) == '/') {
770*7485b225SElliott Hughes             returnNode = CreateUnlinkedNode<XMLText>(_textPool);
771*7485b225SElliott Hughes             returnNode->_parseLineNum = startLine;
772*7485b225SElliott Hughes             p = start;	// Back it up, all the text counts.
773*7485b225SElliott Hughes             _parseCurLineNum = startLine;
774*7485b225SElliott Hughes         }
775*7485b225SElliott Hughes         else {
776*7485b225SElliott Hughes             returnNode = CreateUnlinkedNode<XMLElement>(_elementPool);
777*7485b225SElliott Hughes             returnNode->_parseLineNum = _parseCurLineNum;
778*7485b225SElliott Hughes             p += elementHeaderLen;
779*7485b225SElliott Hughes         }
780*7485b225SElliott Hughes     }
781*7485b225SElliott Hughes     else {
782*7485b225SElliott Hughes         returnNode = CreateUnlinkedNode<XMLText>( _textPool );
783*7485b225SElliott Hughes         returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
784*7485b225SElliott Hughes         p = start;	// Back it up, all the text counts.
785*7485b225SElliott Hughes         _parseCurLineNum = startLine;
786*7485b225SElliott Hughes     }
787*7485b225SElliott Hughes 
788*7485b225SElliott Hughes     TIXMLASSERT( returnNode );
789*7485b225SElliott Hughes     TIXMLASSERT( p );
790*7485b225SElliott Hughes     *node = returnNode;
791*7485b225SElliott Hughes     return p;
792*7485b225SElliott Hughes }
793*7485b225SElliott Hughes 
794*7485b225SElliott Hughes 
Accept(XMLVisitor * visitor) const795*7485b225SElliott Hughes bool XMLDocument::Accept( XMLVisitor* visitor ) const
796*7485b225SElliott Hughes {
797*7485b225SElliott Hughes     TIXMLASSERT( visitor );
798*7485b225SElliott Hughes     if ( visitor->VisitEnter( *this ) ) {
799*7485b225SElliott Hughes         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
800*7485b225SElliott Hughes             if ( !node->Accept( visitor ) ) {
801*7485b225SElliott Hughes                 break;
802*7485b225SElliott Hughes             }
803*7485b225SElliott Hughes         }
804*7485b225SElliott Hughes     }
805*7485b225SElliott Hughes     return visitor->VisitExit( *this );
806*7485b225SElliott Hughes }
807*7485b225SElliott Hughes 
808*7485b225SElliott Hughes 
809*7485b225SElliott Hughes // --------- XMLNode ----------- //
810*7485b225SElliott Hughes 
XMLNode(XMLDocument * doc)811*7485b225SElliott Hughes XMLNode::XMLNode( XMLDocument* doc ) :
812*7485b225SElliott Hughes     _document( doc ),
813*7485b225SElliott Hughes     _parent( 0 ),
814*7485b225SElliott Hughes     _value(),
815*7485b225SElliott Hughes     _parseLineNum( 0 ),
816*7485b225SElliott Hughes     _firstChild( 0 ), _lastChild( 0 ),
817*7485b225SElliott Hughes     _prev( 0 ), _next( 0 ),
818*7485b225SElliott Hughes 	_userData( 0 ),
819*7485b225SElliott Hughes     _memPool( 0 )
820*7485b225SElliott Hughes {
821*7485b225SElliott Hughes }
822*7485b225SElliott Hughes 
823*7485b225SElliott Hughes 
~XMLNode()824*7485b225SElliott Hughes XMLNode::~XMLNode()
825*7485b225SElliott Hughes {
826*7485b225SElliott Hughes     DeleteChildren();
827*7485b225SElliott Hughes     if ( _parent ) {
828*7485b225SElliott Hughes         _parent->Unlink( this );
829*7485b225SElliott Hughes     }
830*7485b225SElliott Hughes }
831*7485b225SElliott Hughes 
832*7485b225SElliott Hughes // ChildElementCount was originally suggested by msteiger on the sourceforge page for TinyXML and modified by KB1SPH for TinyXML-2.
833*7485b225SElliott Hughes 
ChildElementCount(const char * value) const834*7485b225SElliott Hughes int XMLNode::ChildElementCount(const char *value) const {
835*7485b225SElliott Hughes 	int count = 0;
836*7485b225SElliott Hughes 
837*7485b225SElliott Hughes 	const XMLElement *e = FirstChildElement(value);
838*7485b225SElliott Hughes 
839*7485b225SElliott Hughes 	while (e) {
840*7485b225SElliott Hughes 		e = e->NextSiblingElement(value);
841*7485b225SElliott Hughes 		count++;
842*7485b225SElliott Hughes 	}
843*7485b225SElliott Hughes 
844*7485b225SElliott Hughes 	return count;
845*7485b225SElliott Hughes }
846*7485b225SElliott Hughes 
ChildElementCount() const847*7485b225SElliott Hughes int XMLNode::ChildElementCount() const {
848*7485b225SElliott Hughes 	int count = 0;
849*7485b225SElliott Hughes 
850*7485b225SElliott Hughes 	const XMLElement *e = FirstChildElement();
851*7485b225SElliott Hughes 
852*7485b225SElliott Hughes 	while (e) {
853*7485b225SElliott Hughes 		e = e->NextSiblingElement();
854*7485b225SElliott Hughes 		count++;
855*7485b225SElliott Hughes 	}
856*7485b225SElliott Hughes 
857*7485b225SElliott Hughes 	return count;
858*7485b225SElliott Hughes }
859*7485b225SElliott Hughes 
Value() const860*7485b225SElliott Hughes const char* XMLNode::Value() const
861*7485b225SElliott Hughes {
862*7485b225SElliott Hughes     // Edge case: XMLDocuments don't have a Value. Return null.
863*7485b225SElliott Hughes     if ( this->ToDocument() )
864*7485b225SElliott Hughes         return 0;
865*7485b225SElliott Hughes     return _value.GetStr();
866*7485b225SElliott Hughes }
867*7485b225SElliott Hughes 
SetValue(const char * str,bool staticMem)868*7485b225SElliott Hughes void XMLNode::SetValue( const char* str, bool staticMem )
869*7485b225SElliott Hughes {
870*7485b225SElliott Hughes     if ( staticMem ) {
871*7485b225SElliott Hughes         _value.SetInternedStr( str );
872*7485b225SElliott Hughes     }
873*7485b225SElliott Hughes     else {
874*7485b225SElliott Hughes         _value.SetStr( str );
875*7485b225SElliott Hughes     }
876*7485b225SElliott Hughes }
877*7485b225SElliott Hughes 
DeepClone(XMLDocument * target) const878*7485b225SElliott Hughes XMLNode* XMLNode::DeepClone(XMLDocument* target) const
879*7485b225SElliott Hughes {
880*7485b225SElliott Hughes 	XMLNode* clone = this->ShallowClone(target);
881*7485b225SElliott Hughes 	if (!clone) return 0;
882*7485b225SElliott Hughes 
883*7485b225SElliott Hughes 	for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
884*7485b225SElliott Hughes 		XMLNode* childClone = child->DeepClone(target);
885*7485b225SElliott Hughes 		TIXMLASSERT(childClone);
886*7485b225SElliott Hughes 		clone->InsertEndChild(childClone);
887*7485b225SElliott Hughes 	}
888*7485b225SElliott Hughes 	return clone;
889*7485b225SElliott Hughes }
890*7485b225SElliott Hughes 
DeleteChildren()891*7485b225SElliott Hughes void XMLNode::DeleteChildren()
892*7485b225SElliott Hughes {
893*7485b225SElliott Hughes     while( _firstChild ) {
894*7485b225SElliott Hughes         TIXMLASSERT( _lastChild );
895*7485b225SElliott Hughes         DeleteChild( _firstChild );
896*7485b225SElliott Hughes     }
897*7485b225SElliott Hughes     _firstChild = _lastChild = 0;
898*7485b225SElliott Hughes }
899*7485b225SElliott Hughes 
900*7485b225SElliott Hughes 
Unlink(XMLNode * child)901*7485b225SElliott Hughes void XMLNode::Unlink( XMLNode* child )
902*7485b225SElliott Hughes {
903*7485b225SElliott Hughes     TIXMLASSERT( child );
904*7485b225SElliott Hughes     TIXMLASSERT( child->_document == _document );
905*7485b225SElliott Hughes     TIXMLASSERT( child->_parent == this );
906*7485b225SElliott Hughes     if ( child == _firstChild ) {
907*7485b225SElliott Hughes         _firstChild = _firstChild->_next;
908*7485b225SElliott Hughes     }
909*7485b225SElliott Hughes     if ( child == _lastChild ) {
910*7485b225SElliott Hughes         _lastChild = _lastChild->_prev;
911*7485b225SElliott Hughes     }
912*7485b225SElliott Hughes 
913*7485b225SElliott Hughes     if ( child->_prev ) {
914*7485b225SElliott Hughes         child->_prev->_next = child->_next;
915*7485b225SElliott Hughes     }
916*7485b225SElliott Hughes     if ( child->_next ) {
917*7485b225SElliott Hughes         child->_next->_prev = child->_prev;
918*7485b225SElliott Hughes     }
919*7485b225SElliott Hughes 	child->_next = 0;
920*7485b225SElliott Hughes 	child->_prev = 0;
921*7485b225SElliott Hughes 	child->_parent = 0;
922*7485b225SElliott Hughes }
923*7485b225SElliott Hughes 
924*7485b225SElliott Hughes 
DeleteChild(XMLNode * node)925*7485b225SElliott Hughes void XMLNode::DeleteChild( XMLNode* node )
926*7485b225SElliott Hughes {
927*7485b225SElliott Hughes     TIXMLASSERT( node );
928*7485b225SElliott Hughes     TIXMLASSERT( node->_document == _document );
929*7485b225SElliott Hughes     TIXMLASSERT( node->_parent == this );
930*7485b225SElliott Hughes     Unlink( node );
931*7485b225SElliott Hughes 	TIXMLASSERT(node->_prev == 0);
932*7485b225SElliott Hughes 	TIXMLASSERT(node->_next == 0);
933*7485b225SElliott Hughes 	TIXMLASSERT(node->_parent == 0);
934*7485b225SElliott Hughes     DeleteNode( node );
935*7485b225SElliott Hughes }
936*7485b225SElliott Hughes 
937*7485b225SElliott Hughes 
InsertEndChild(XMLNode * addThis)938*7485b225SElliott Hughes XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
939*7485b225SElliott Hughes {
940*7485b225SElliott Hughes     TIXMLASSERT( addThis );
941*7485b225SElliott Hughes     if ( addThis->_document != _document ) {
942*7485b225SElliott Hughes         TIXMLASSERT( false );
943*7485b225SElliott Hughes         return 0;
944*7485b225SElliott Hughes     }
945*7485b225SElliott Hughes     InsertChildPreamble( addThis );
946*7485b225SElliott Hughes 
947*7485b225SElliott Hughes     if ( _lastChild ) {
948*7485b225SElliott Hughes         TIXMLASSERT( _firstChild );
949*7485b225SElliott Hughes         TIXMLASSERT( _lastChild->_next == 0 );
950*7485b225SElliott Hughes         _lastChild->_next = addThis;
951*7485b225SElliott Hughes         addThis->_prev = _lastChild;
952*7485b225SElliott Hughes         _lastChild = addThis;
953*7485b225SElliott Hughes 
954*7485b225SElliott Hughes         addThis->_next = 0;
955*7485b225SElliott Hughes     }
956*7485b225SElliott Hughes     else {
957*7485b225SElliott Hughes         TIXMLASSERT( _firstChild == 0 );
958*7485b225SElliott Hughes         _firstChild = _lastChild = addThis;
959*7485b225SElliott Hughes 
960*7485b225SElliott Hughes         addThis->_prev = 0;
961*7485b225SElliott Hughes         addThis->_next = 0;
962*7485b225SElliott Hughes     }
963*7485b225SElliott Hughes     addThis->_parent = this;
964*7485b225SElliott Hughes     return addThis;
965*7485b225SElliott Hughes }
966*7485b225SElliott Hughes 
967*7485b225SElliott Hughes 
InsertFirstChild(XMLNode * addThis)968*7485b225SElliott Hughes XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
969*7485b225SElliott Hughes {
970*7485b225SElliott Hughes     TIXMLASSERT( addThis );
971*7485b225SElliott Hughes     if ( addThis->_document != _document ) {
972*7485b225SElliott Hughes         TIXMLASSERT( false );
973*7485b225SElliott Hughes         return 0;
974*7485b225SElliott Hughes     }
975*7485b225SElliott Hughes     InsertChildPreamble( addThis );
976*7485b225SElliott Hughes 
977*7485b225SElliott Hughes     if ( _firstChild ) {
978*7485b225SElliott Hughes         TIXMLASSERT( _lastChild );
979*7485b225SElliott Hughes         TIXMLASSERT( _firstChild->_prev == 0 );
980*7485b225SElliott Hughes 
981*7485b225SElliott Hughes         _firstChild->_prev = addThis;
982*7485b225SElliott Hughes         addThis->_next = _firstChild;
983*7485b225SElliott Hughes         _firstChild = addThis;
984*7485b225SElliott Hughes 
985*7485b225SElliott Hughes         addThis->_prev = 0;
986*7485b225SElliott Hughes     }
987*7485b225SElliott Hughes     else {
988*7485b225SElliott Hughes         TIXMLASSERT( _lastChild == 0 );
989*7485b225SElliott Hughes         _firstChild = _lastChild = addThis;
990*7485b225SElliott Hughes 
991*7485b225SElliott Hughes         addThis->_prev = 0;
992*7485b225SElliott Hughes         addThis->_next = 0;
993*7485b225SElliott Hughes     }
994*7485b225SElliott Hughes     addThis->_parent = this;
995*7485b225SElliott Hughes     return addThis;
996*7485b225SElliott Hughes }
997*7485b225SElliott Hughes 
998*7485b225SElliott Hughes 
InsertAfterChild(XMLNode * afterThis,XMLNode * addThis)999*7485b225SElliott Hughes XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
1000*7485b225SElliott Hughes {
1001*7485b225SElliott Hughes     TIXMLASSERT( addThis );
1002*7485b225SElliott Hughes     if ( addThis->_document != _document ) {
1003*7485b225SElliott Hughes         TIXMLASSERT( false );
1004*7485b225SElliott Hughes         return 0;
1005*7485b225SElliott Hughes     }
1006*7485b225SElliott Hughes 
1007*7485b225SElliott Hughes     TIXMLASSERT( afterThis );
1008*7485b225SElliott Hughes 
1009*7485b225SElliott Hughes     if ( afterThis->_parent != this ) {
1010*7485b225SElliott Hughes         TIXMLASSERT( false );
1011*7485b225SElliott Hughes         return 0;
1012*7485b225SElliott Hughes     }
1013*7485b225SElliott Hughes     if ( afterThis == addThis ) {
1014*7485b225SElliott Hughes         // Current state: BeforeThis -> AddThis -> OneAfterAddThis
1015*7485b225SElliott Hughes         // Now AddThis must disappear from it's location and then
1016*7485b225SElliott Hughes         // reappear between BeforeThis and OneAfterAddThis.
1017*7485b225SElliott Hughes         // So just leave it where it is.
1018*7485b225SElliott Hughes         return addThis;
1019*7485b225SElliott Hughes     }
1020*7485b225SElliott Hughes 
1021*7485b225SElliott Hughes     if ( afterThis->_next == 0 ) {
1022*7485b225SElliott Hughes         // The last node or the only node.
1023*7485b225SElliott Hughes         return InsertEndChild( addThis );
1024*7485b225SElliott Hughes     }
1025*7485b225SElliott Hughes     InsertChildPreamble( addThis );
1026*7485b225SElliott Hughes     addThis->_prev = afterThis;
1027*7485b225SElliott Hughes     addThis->_next = afterThis->_next;
1028*7485b225SElliott Hughes     afterThis->_next->_prev = addThis;
1029*7485b225SElliott Hughes     afterThis->_next = addThis;
1030*7485b225SElliott Hughes     addThis->_parent = this;
1031*7485b225SElliott Hughes     return addThis;
1032*7485b225SElliott Hughes }
1033*7485b225SElliott Hughes 
1034*7485b225SElliott Hughes 
1035*7485b225SElliott Hughes 
1036*7485b225SElliott Hughes 
FirstChildElement(const char * name) const1037*7485b225SElliott Hughes const XMLElement* XMLNode::FirstChildElement( const char* name ) const
1038*7485b225SElliott Hughes {
1039*7485b225SElliott Hughes     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
1040*7485b225SElliott Hughes         const XMLElement* element = node->ToElementWithName( name );
1041*7485b225SElliott Hughes         if ( element ) {
1042*7485b225SElliott Hughes             return element;
1043*7485b225SElliott Hughes         }
1044*7485b225SElliott Hughes     }
1045*7485b225SElliott Hughes     return 0;
1046*7485b225SElliott Hughes }
1047*7485b225SElliott Hughes 
1048*7485b225SElliott Hughes 
LastChildElement(const char * name) const1049*7485b225SElliott Hughes const XMLElement* XMLNode::LastChildElement( const char* name ) const
1050*7485b225SElliott Hughes {
1051*7485b225SElliott Hughes     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
1052*7485b225SElliott Hughes         const XMLElement* element = node->ToElementWithName( name );
1053*7485b225SElliott Hughes         if ( element ) {
1054*7485b225SElliott Hughes             return element;
1055*7485b225SElliott Hughes         }
1056*7485b225SElliott Hughes     }
1057*7485b225SElliott Hughes     return 0;
1058*7485b225SElliott Hughes }
1059*7485b225SElliott Hughes 
1060*7485b225SElliott Hughes 
NextSiblingElement(const char * name) const1061*7485b225SElliott Hughes const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
1062*7485b225SElliott Hughes {
1063*7485b225SElliott Hughes     for( const XMLNode* node = _next; node; node = node->_next ) {
1064*7485b225SElliott Hughes         const XMLElement* element = node->ToElementWithName( name );
1065*7485b225SElliott Hughes         if ( element ) {
1066*7485b225SElliott Hughes             return element;
1067*7485b225SElliott Hughes         }
1068*7485b225SElliott Hughes     }
1069*7485b225SElliott Hughes     return 0;
1070*7485b225SElliott Hughes }
1071*7485b225SElliott Hughes 
1072*7485b225SElliott Hughes 
PreviousSiblingElement(const char * name) const1073*7485b225SElliott Hughes const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
1074*7485b225SElliott Hughes {
1075*7485b225SElliott Hughes     for( const XMLNode* node = _prev; node; node = node->_prev ) {
1076*7485b225SElliott Hughes         const XMLElement* element = node->ToElementWithName( name );
1077*7485b225SElliott Hughes         if ( element ) {
1078*7485b225SElliott Hughes             return element;
1079*7485b225SElliott Hughes         }
1080*7485b225SElliott Hughes     }
1081*7485b225SElliott Hughes     return 0;
1082*7485b225SElliott Hughes }
1083*7485b225SElliott Hughes 
1084*7485b225SElliott Hughes 
ParseDeep(char * p,StrPair * parentEndTag,int * curLineNumPtr)1085*7485b225SElliott Hughes char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
1086*7485b225SElliott Hughes {
1087*7485b225SElliott Hughes     // This is a recursive method, but thinking about it "at the current level"
1088*7485b225SElliott Hughes     // it is a pretty simple flat list:
1089*7485b225SElliott Hughes     //		<foo/>
1090*7485b225SElliott Hughes     //		<!-- comment -->
1091*7485b225SElliott Hughes     //
1092*7485b225SElliott Hughes     // With a special case:
1093*7485b225SElliott Hughes     //		<foo>
1094*7485b225SElliott Hughes     //		</foo>
1095*7485b225SElliott Hughes     //		<!-- comment -->
1096*7485b225SElliott Hughes     //
1097*7485b225SElliott Hughes     // Where the closing element (/foo) *must* be the next thing after the opening
1098*7485b225SElliott Hughes     // element, and the names must match. BUT the tricky bit is that the closing
1099*7485b225SElliott Hughes     // element will be read by the child.
1100*7485b225SElliott Hughes     //
1101*7485b225SElliott Hughes     // 'endTag' is the end tag for this node, it is returned by a call to a child.
1102*7485b225SElliott Hughes     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
1103*7485b225SElliott Hughes 
1104*7485b225SElliott Hughes 	XMLDocument::DepthTracker tracker(_document);
1105*7485b225SElliott Hughes 	if (_document->Error())
1106*7485b225SElliott Hughes 		return 0;
1107*7485b225SElliott Hughes 
1108*7485b225SElliott Hughes 	bool first = true;
1109*7485b225SElliott Hughes 	while( p && *p ) {
1110*7485b225SElliott Hughes         XMLNode* node = 0;
1111*7485b225SElliott Hughes 
1112*7485b225SElliott Hughes         p = _document->Identify( p, &node, first );
1113*7485b225SElliott Hughes         TIXMLASSERT( p );
1114*7485b225SElliott Hughes         if ( node == 0 ) {
1115*7485b225SElliott Hughes             break;
1116*7485b225SElliott Hughes         }
1117*7485b225SElliott Hughes         first = false;
1118*7485b225SElliott Hughes 
1119*7485b225SElliott Hughes        const int initialLineNum = node->_parseLineNum;
1120*7485b225SElliott Hughes 
1121*7485b225SElliott Hughes         StrPair endTag;
1122*7485b225SElliott Hughes         p = node->ParseDeep( p, &endTag, curLineNumPtr );
1123*7485b225SElliott Hughes         if ( !p ) {
1124*7485b225SElliott Hughes             _document->DeleteNode( node );
1125*7485b225SElliott Hughes             if ( !_document->Error() ) {
1126*7485b225SElliott Hughes                 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1127*7485b225SElliott Hughes             }
1128*7485b225SElliott Hughes             break;
1129*7485b225SElliott Hughes         }
1130*7485b225SElliott Hughes 
1131*7485b225SElliott Hughes         const XMLDeclaration* const decl = node->ToDeclaration();
1132*7485b225SElliott Hughes         if ( decl ) {
1133*7485b225SElliott Hughes             // Declarations are only allowed at document level
1134*7485b225SElliott Hughes             //
1135*7485b225SElliott Hughes             // Multiple declarations are allowed but all declarations
1136*7485b225SElliott Hughes             // must occur before anything else.
1137*7485b225SElliott Hughes             //
1138*7485b225SElliott Hughes             // Optimized due to a security test case. If the first node is
1139*7485b225SElliott Hughes             // a declaration, and the last node is a declaration, then only
1140*7485b225SElliott Hughes             // declarations have so far been added.
1141*7485b225SElliott Hughes             bool wellLocated = false;
1142*7485b225SElliott Hughes 
1143*7485b225SElliott Hughes             if (ToDocument()) {
1144*7485b225SElliott Hughes                 if (FirstChild()) {
1145*7485b225SElliott Hughes                     wellLocated =
1146*7485b225SElliott Hughes                         FirstChild() &&
1147*7485b225SElliott Hughes                         FirstChild()->ToDeclaration() &&
1148*7485b225SElliott Hughes                         LastChild() &&
1149*7485b225SElliott Hughes                         LastChild()->ToDeclaration();
1150*7485b225SElliott Hughes                 }
1151*7485b225SElliott Hughes                 else {
1152*7485b225SElliott Hughes                     wellLocated = true;
1153*7485b225SElliott Hughes                 }
1154*7485b225SElliott Hughes             }
1155*7485b225SElliott Hughes             if ( !wellLocated ) {
1156*7485b225SElliott Hughes                 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1157*7485b225SElliott Hughes                 _document->DeleteNode( node );
1158*7485b225SElliott Hughes                 break;
1159*7485b225SElliott Hughes             }
1160*7485b225SElliott Hughes         }
1161*7485b225SElliott Hughes 
1162*7485b225SElliott Hughes         XMLElement* ele = node->ToElement();
1163*7485b225SElliott Hughes         if ( ele ) {
1164*7485b225SElliott Hughes             // We read the end tag. Return it to the parent.
1165*7485b225SElliott Hughes             if ( ele->ClosingType() == XMLElement::CLOSING ) {
1166*7485b225SElliott Hughes                 if ( parentEndTag ) {
1167*7485b225SElliott Hughes                     ele->_value.TransferTo( parentEndTag );
1168*7485b225SElliott Hughes                 }
1169*7485b225SElliott Hughes                 node->_memPool->SetTracked();   // created and then immediately deleted.
1170*7485b225SElliott Hughes                 DeleteNode( node );
1171*7485b225SElliott Hughes                 return p;
1172*7485b225SElliott Hughes             }
1173*7485b225SElliott Hughes 
1174*7485b225SElliott Hughes             // Handle an end tag returned to this level.
1175*7485b225SElliott Hughes             // And handle a bunch of annoying errors.
1176*7485b225SElliott Hughes             bool mismatch = false;
1177*7485b225SElliott Hughes             if ( endTag.Empty() ) {
1178*7485b225SElliott Hughes                 if ( ele->ClosingType() == XMLElement::OPEN ) {
1179*7485b225SElliott Hughes                     mismatch = true;
1180*7485b225SElliott Hughes                 }
1181*7485b225SElliott Hughes             }
1182*7485b225SElliott Hughes             else {
1183*7485b225SElliott Hughes                 if ( ele->ClosingType() != XMLElement::OPEN ) {
1184*7485b225SElliott Hughes                     mismatch = true;
1185*7485b225SElliott Hughes                 }
1186*7485b225SElliott Hughes                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1187*7485b225SElliott Hughes                     mismatch = true;
1188*7485b225SElliott Hughes                 }
1189*7485b225SElliott Hughes             }
1190*7485b225SElliott Hughes             if ( mismatch ) {
1191*7485b225SElliott Hughes                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1192*7485b225SElliott Hughes                 _document->DeleteNode( node );
1193*7485b225SElliott Hughes                 break;
1194*7485b225SElliott Hughes             }
1195*7485b225SElliott Hughes         }
1196*7485b225SElliott Hughes         InsertEndChild( node );
1197*7485b225SElliott Hughes     }
1198*7485b225SElliott Hughes     return 0;
1199*7485b225SElliott Hughes }
1200*7485b225SElliott Hughes 
DeleteNode(XMLNode * node)1201*7485b225SElliott Hughes /*static*/ void XMLNode::DeleteNode( XMLNode* node )
1202*7485b225SElliott Hughes {
1203*7485b225SElliott Hughes     if ( node == 0 ) {
1204*7485b225SElliott Hughes         return;
1205*7485b225SElliott Hughes     }
1206*7485b225SElliott Hughes 	TIXMLASSERT(node->_document);
1207*7485b225SElliott Hughes 	if (!node->ToDocument()) {
1208*7485b225SElliott Hughes 		node->_document->MarkInUse(node);
1209*7485b225SElliott Hughes 	}
1210*7485b225SElliott Hughes 
1211*7485b225SElliott Hughes     MemPool* pool = node->_memPool;
1212*7485b225SElliott Hughes     node->~XMLNode();
1213*7485b225SElliott Hughes     pool->Free( node );
1214*7485b225SElliott Hughes }
1215*7485b225SElliott Hughes 
InsertChildPreamble(XMLNode * insertThis) const1216*7485b225SElliott Hughes void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1217*7485b225SElliott Hughes {
1218*7485b225SElliott Hughes     TIXMLASSERT( insertThis );
1219*7485b225SElliott Hughes     TIXMLASSERT( insertThis->_document == _document );
1220*7485b225SElliott Hughes 
1221*7485b225SElliott Hughes 	if (insertThis->_parent) {
1222*7485b225SElliott Hughes         insertThis->_parent->Unlink( insertThis );
1223*7485b225SElliott Hughes 	}
1224*7485b225SElliott Hughes 	else {
1225*7485b225SElliott Hughes 		insertThis->_document->MarkInUse(insertThis);
1226*7485b225SElliott Hughes         insertThis->_memPool->SetTracked();
1227*7485b225SElliott Hughes 	}
1228*7485b225SElliott Hughes }
1229*7485b225SElliott Hughes 
ToElementWithName(const char * name) const1230*7485b225SElliott Hughes const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1231*7485b225SElliott Hughes {
1232*7485b225SElliott Hughes     const XMLElement* element = this->ToElement();
1233*7485b225SElliott Hughes     if ( element == 0 ) {
1234*7485b225SElliott Hughes         return 0;
1235*7485b225SElliott Hughes     }
1236*7485b225SElliott Hughes     if ( name == 0 ) {
1237*7485b225SElliott Hughes         return element;
1238*7485b225SElliott Hughes     }
1239*7485b225SElliott Hughes     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1240*7485b225SElliott Hughes        return element;
1241*7485b225SElliott Hughes     }
1242*7485b225SElliott Hughes     return 0;
1243*7485b225SElliott Hughes }
1244*7485b225SElliott Hughes 
1245*7485b225SElliott Hughes // --------- XMLText ---------- //
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1246*7485b225SElliott Hughes char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1247*7485b225SElliott Hughes {
1248*7485b225SElliott Hughes     if ( this->CData() ) {
1249*7485b225SElliott Hughes         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1250*7485b225SElliott Hughes         if ( !p ) {
1251*7485b225SElliott Hughes             _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1252*7485b225SElliott Hughes         }
1253*7485b225SElliott Hughes         return p;
1254*7485b225SElliott Hughes     }
1255*7485b225SElliott Hughes     else {
1256*7485b225SElliott Hughes         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1257*7485b225SElliott Hughes         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1258*7485b225SElliott Hughes             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1259*7485b225SElliott Hughes         }
1260*7485b225SElliott Hughes 
1261*7485b225SElliott Hughes         p = _value.ParseText( p, "<", flags, curLineNumPtr );
1262*7485b225SElliott Hughes         if ( p && *p ) {
1263*7485b225SElliott Hughes             return p-1;
1264*7485b225SElliott Hughes         }
1265*7485b225SElliott Hughes         if ( !p ) {
1266*7485b225SElliott Hughes             _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1267*7485b225SElliott Hughes         }
1268*7485b225SElliott Hughes     }
1269*7485b225SElliott Hughes     return 0;
1270*7485b225SElliott Hughes }
1271*7485b225SElliott Hughes 
1272*7485b225SElliott Hughes 
ShallowClone(XMLDocument * doc) const1273*7485b225SElliott Hughes XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1274*7485b225SElliott Hughes {
1275*7485b225SElliott Hughes     if ( !doc ) {
1276*7485b225SElliott Hughes         doc = _document;
1277*7485b225SElliott Hughes     }
1278*7485b225SElliott Hughes     XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
1279*7485b225SElliott Hughes     text->SetCData( this->CData() );
1280*7485b225SElliott Hughes     return text;
1281*7485b225SElliott Hughes }
1282*7485b225SElliott Hughes 
1283*7485b225SElliott Hughes 
ShallowEqual(const XMLNode * compare) const1284*7485b225SElliott Hughes bool XMLText::ShallowEqual( const XMLNode* compare ) const
1285*7485b225SElliott Hughes {
1286*7485b225SElliott Hughes     TIXMLASSERT( compare );
1287*7485b225SElliott Hughes     const XMLText* text = compare->ToText();
1288*7485b225SElliott Hughes     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1289*7485b225SElliott Hughes }
1290*7485b225SElliott Hughes 
1291*7485b225SElliott Hughes 
Accept(XMLVisitor * visitor) const1292*7485b225SElliott Hughes bool XMLText::Accept( XMLVisitor* visitor ) const
1293*7485b225SElliott Hughes {
1294*7485b225SElliott Hughes     TIXMLASSERT( visitor );
1295*7485b225SElliott Hughes     return visitor->Visit( *this );
1296*7485b225SElliott Hughes }
1297*7485b225SElliott Hughes 
1298*7485b225SElliott Hughes 
1299*7485b225SElliott Hughes // --------- XMLComment ---------- //
1300*7485b225SElliott Hughes 
XMLComment(XMLDocument * doc)1301*7485b225SElliott Hughes XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1302*7485b225SElliott Hughes {
1303*7485b225SElliott Hughes }
1304*7485b225SElliott Hughes 
1305*7485b225SElliott Hughes 
~XMLComment()1306*7485b225SElliott Hughes XMLComment::~XMLComment()
1307*7485b225SElliott Hughes {
1308*7485b225SElliott Hughes }
1309*7485b225SElliott Hughes 
1310*7485b225SElliott Hughes 
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1311*7485b225SElliott Hughes char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1312*7485b225SElliott Hughes {
1313*7485b225SElliott Hughes     // Comment parses as text.
1314*7485b225SElliott Hughes     p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1315*7485b225SElliott Hughes     if ( p == 0 ) {
1316*7485b225SElliott Hughes         _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1317*7485b225SElliott Hughes     }
1318*7485b225SElliott Hughes     return p;
1319*7485b225SElliott Hughes }
1320*7485b225SElliott Hughes 
1321*7485b225SElliott Hughes 
ShallowClone(XMLDocument * doc) const1322*7485b225SElliott Hughes XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1323*7485b225SElliott Hughes {
1324*7485b225SElliott Hughes     if ( !doc ) {
1325*7485b225SElliott Hughes         doc = _document;
1326*7485b225SElliott Hughes     }
1327*7485b225SElliott Hughes     XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
1328*7485b225SElliott Hughes     return comment;
1329*7485b225SElliott Hughes }
1330*7485b225SElliott Hughes 
1331*7485b225SElliott Hughes 
ShallowEqual(const XMLNode * compare) const1332*7485b225SElliott Hughes bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1333*7485b225SElliott Hughes {
1334*7485b225SElliott Hughes     TIXMLASSERT( compare );
1335*7485b225SElliott Hughes     const XMLComment* comment = compare->ToComment();
1336*7485b225SElliott Hughes     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1337*7485b225SElliott Hughes }
1338*7485b225SElliott Hughes 
1339*7485b225SElliott Hughes 
Accept(XMLVisitor * visitor) const1340*7485b225SElliott Hughes bool XMLComment::Accept( XMLVisitor* visitor ) const
1341*7485b225SElliott Hughes {
1342*7485b225SElliott Hughes     TIXMLASSERT( visitor );
1343*7485b225SElliott Hughes     return visitor->Visit( *this );
1344*7485b225SElliott Hughes }
1345*7485b225SElliott Hughes 
1346*7485b225SElliott Hughes 
1347*7485b225SElliott Hughes // --------- XMLDeclaration ---------- //
1348*7485b225SElliott Hughes 
XMLDeclaration(XMLDocument * doc)1349*7485b225SElliott Hughes XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1350*7485b225SElliott Hughes {
1351*7485b225SElliott Hughes }
1352*7485b225SElliott Hughes 
1353*7485b225SElliott Hughes 
~XMLDeclaration()1354*7485b225SElliott Hughes XMLDeclaration::~XMLDeclaration()
1355*7485b225SElliott Hughes {
1356*7485b225SElliott Hughes     //printf( "~XMLDeclaration\n" );
1357*7485b225SElliott Hughes }
1358*7485b225SElliott Hughes 
1359*7485b225SElliott Hughes 
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1360*7485b225SElliott Hughes char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1361*7485b225SElliott Hughes {
1362*7485b225SElliott Hughes     // Declaration parses as text.
1363*7485b225SElliott Hughes     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1364*7485b225SElliott Hughes     if ( p == 0 ) {
1365*7485b225SElliott Hughes         _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1366*7485b225SElliott Hughes     }
1367*7485b225SElliott Hughes     return p;
1368*7485b225SElliott Hughes }
1369*7485b225SElliott Hughes 
1370*7485b225SElliott Hughes 
ShallowClone(XMLDocument * doc) const1371*7485b225SElliott Hughes XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1372*7485b225SElliott Hughes {
1373*7485b225SElliott Hughes     if ( !doc ) {
1374*7485b225SElliott Hughes         doc = _document;
1375*7485b225SElliott Hughes     }
1376*7485b225SElliott Hughes     XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
1377*7485b225SElliott Hughes     return dec;
1378*7485b225SElliott Hughes }
1379*7485b225SElliott Hughes 
1380*7485b225SElliott Hughes 
ShallowEqual(const XMLNode * compare) const1381*7485b225SElliott Hughes bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1382*7485b225SElliott Hughes {
1383*7485b225SElliott Hughes     TIXMLASSERT( compare );
1384*7485b225SElliott Hughes     const XMLDeclaration* declaration = compare->ToDeclaration();
1385*7485b225SElliott Hughes     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1386*7485b225SElliott Hughes }
1387*7485b225SElliott Hughes 
1388*7485b225SElliott Hughes 
1389*7485b225SElliott Hughes 
Accept(XMLVisitor * visitor) const1390*7485b225SElliott Hughes bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1391*7485b225SElliott Hughes {
1392*7485b225SElliott Hughes     TIXMLASSERT( visitor );
1393*7485b225SElliott Hughes     return visitor->Visit( *this );
1394*7485b225SElliott Hughes }
1395*7485b225SElliott Hughes 
1396*7485b225SElliott Hughes // --------- XMLUnknown ---------- //
1397*7485b225SElliott Hughes 
XMLUnknown(XMLDocument * doc)1398*7485b225SElliott Hughes XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1399*7485b225SElliott Hughes {
1400*7485b225SElliott Hughes }
1401*7485b225SElliott Hughes 
1402*7485b225SElliott Hughes 
~XMLUnknown()1403*7485b225SElliott Hughes XMLUnknown::~XMLUnknown()
1404*7485b225SElliott Hughes {
1405*7485b225SElliott Hughes }
1406*7485b225SElliott Hughes 
1407*7485b225SElliott Hughes 
ParseDeep(char * p,StrPair *,int * curLineNumPtr)1408*7485b225SElliott Hughes char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1409*7485b225SElliott Hughes {
1410*7485b225SElliott Hughes     // Unknown parses as text.
1411*7485b225SElliott Hughes     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1412*7485b225SElliott Hughes     if ( !p ) {
1413*7485b225SElliott Hughes         _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1414*7485b225SElliott Hughes     }
1415*7485b225SElliott Hughes     return p;
1416*7485b225SElliott Hughes }
1417*7485b225SElliott Hughes 
1418*7485b225SElliott Hughes 
ShallowClone(XMLDocument * doc) const1419*7485b225SElliott Hughes XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1420*7485b225SElliott Hughes {
1421*7485b225SElliott Hughes     if ( !doc ) {
1422*7485b225SElliott Hughes         doc = _document;
1423*7485b225SElliott Hughes     }
1424*7485b225SElliott Hughes     XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
1425*7485b225SElliott Hughes     return text;
1426*7485b225SElliott Hughes }
1427*7485b225SElliott Hughes 
1428*7485b225SElliott Hughes 
ShallowEqual(const XMLNode * compare) const1429*7485b225SElliott Hughes bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1430*7485b225SElliott Hughes {
1431*7485b225SElliott Hughes     TIXMLASSERT( compare );
1432*7485b225SElliott Hughes     const XMLUnknown* unknown = compare->ToUnknown();
1433*7485b225SElliott Hughes     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1434*7485b225SElliott Hughes }
1435*7485b225SElliott Hughes 
1436*7485b225SElliott Hughes 
Accept(XMLVisitor * visitor) const1437*7485b225SElliott Hughes bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1438*7485b225SElliott Hughes {
1439*7485b225SElliott Hughes     TIXMLASSERT( visitor );
1440*7485b225SElliott Hughes     return visitor->Visit( *this );
1441*7485b225SElliott Hughes }
1442*7485b225SElliott Hughes 
1443*7485b225SElliott Hughes // --------- XMLAttribute ---------- //
1444*7485b225SElliott Hughes 
Name() const1445*7485b225SElliott Hughes const char* XMLAttribute::Name() const
1446*7485b225SElliott Hughes {
1447*7485b225SElliott Hughes     return _name.GetStr();
1448*7485b225SElliott Hughes }
1449*7485b225SElliott Hughes 
Value() const1450*7485b225SElliott Hughes const char* XMLAttribute::Value() const
1451*7485b225SElliott Hughes {
1452*7485b225SElliott Hughes     return _value.GetStr();
1453*7485b225SElliott Hughes }
1454*7485b225SElliott Hughes 
ParseDeep(char * p,bool processEntities,int * curLineNumPtr)1455*7485b225SElliott Hughes char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1456*7485b225SElliott Hughes {
1457*7485b225SElliott Hughes     // Parse using the name rules: bug fix, was using ParseText before
1458*7485b225SElliott Hughes     p = _name.ParseName( p );
1459*7485b225SElliott Hughes     if ( !p || !*p ) {
1460*7485b225SElliott Hughes         return 0;
1461*7485b225SElliott Hughes     }
1462*7485b225SElliott Hughes 
1463*7485b225SElliott Hughes     // Skip white space before =
1464*7485b225SElliott Hughes     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1465*7485b225SElliott Hughes     if ( *p != '=' ) {
1466*7485b225SElliott Hughes         return 0;
1467*7485b225SElliott Hughes     }
1468*7485b225SElliott Hughes 
1469*7485b225SElliott Hughes     ++p;	// move up to opening quote
1470*7485b225SElliott Hughes     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1471*7485b225SElliott Hughes     if ( *p != '\"' && *p != '\'' ) {
1472*7485b225SElliott Hughes         return 0;
1473*7485b225SElliott Hughes     }
1474*7485b225SElliott Hughes 
1475*7485b225SElliott Hughes     const char endTag[2] = { *p, 0 };
1476*7485b225SElliott Hughes     ++p;	// move past opening quote
1477*7485b225SElliott Hughes 
1478*7485b225SElliott Hughes     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1479*7485b225SElliott Hughes     return p;
1480*7485b225SElliott Hughes }
1481*7485b225SElliott Hughes 
1482*7485b225SElliott Hughes 
SetName(const char * n)1483*7485b225SElliott Hughes void XMLAttribute::SetName( const char* n )
1484*7485b225SElliott Hughes {
1485*7485b225SElliott Hughes     _name.SetStr( n );
1486*7485b225SElliott Hughes }
1487*7485b225SElliott Hughes 
1488*7485b225SElliott Hughes 
QueryIntValue(int * value) const1489*7485b225SElliott Hughes XMLError XMLAttribute::QueryIntValue( int* value ) const
1490*7485b225SElliott Hughes {
1491*7485b225SElliott Hughes     if ( XMLUtil::ToInt( Value(), value )) {
1492*7485b225SElliott Hughes         return XML_SUCCESS;
1493*7485b225SElliott Hughes     }
1494*7485b225SElliott Hughes     return XML_WRONG_ATTRIBUTE_TYPE;
1495*7485b225SElliott Hughes }
1496*7485b225SElliott Hughes 
1497*7485b225SElliott Hughes 
QueryUnsignedValue(unsigned int * value) const1498*7485b225SElliott Hughes XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1499*7485b225SElliott Hughes {
1500*7485b225SElliott Hughes     if ( XMLUtil::ToUnsigned( Value(), value )) {
1501*7485b225SElliott Hughes         return XML_SUCCESS;
1502*7485b225SElliott Hughes     }
1503*7485b225SElliott Hughes     return XML_WRONG_ATTRIBUTE_TYPE;
1504*7485b225SElliott Hughes }
1505*7485b225SElliott Hughes 
1506*7485b225SElliott Hughes 
QueryInt64Value(int64_t * value) const1507*7485b225SElliott Hughes XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1508*7485b225SElliott Hughes {
1509*7485b225SElliott Hughes 	if (XMLUtil::ToInt64(Value(), value)) {
1510*7485b225SElliott Hughes 		return XML_SUCCESS;
1511*7485b225SElliott Hughes 	}
1512*7485b225SElliott Hughes 	return XML_WRONG_ATTRIBUTE_TYPE;
1513*7485b225SElliott Hughes }
1514*7485b225SElliott Hughes 
1515*7485b225SElliott Hughes 
QueryUnsigned64Value(uint64_t * value) const1516*7485b225SElliott Hughes XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1517*7485b225SElliott Hughes {
1518*7485b225SElliott Hughes     if(XMLUtil::ToUnsigned64(Value(), value)) {
1519*7485b225SElliott Hughes         return XML_SUCCESS;
1520*7485b225SElliott Hughes     }
1521*7485b225SElliott Hughes     return XML_WRONG_ATTRIBUTE_TYPE;
1522*7485b225SElliott Hughes }
1523*7485b225SElliott Hughes 
1524*7485b225SElliott Hughes 
QueryBoolValue(bool * value) const1525*7485b225SElliott Hughes XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1526*7485b225SElliott Hughes {
1527*7485b225SElliott Hughes     if ( XMLUtil::ToBool( Value(), value )) {
1528*7485b225SElliott Hughes         return XML_SUCCESS;
1529*7485b225SElliott Hughes     }
1530*7485b225SElliott Hughes     return XML_WRONG_ATTRIBUTE_TYPE;
1531*7485b225SElliott Hughes }
1532*7485b225SElliott Hughes 
1533*7485b225SElliott Hughes 
QueryFloatValue(float * value) const1534*7485b225SElliott Hughes XMLError XMLAttribute::QueryFloatValue( float* value ) const
1535*7485b225SElliott Hughes {
1536*7485b225SElliott Hughes     if ( XMLUtil::ToFloat( Value(), value )) {
1537*7485b225SElliott Hughes         return XML_SUCCESS;
1538*7485b225SElliott Hughes     }
1539*7485b225SElliott Hughes     return XML_WRONG_ATTRIBUTE_TYPE;
1540*7485b225SElliott Hughes }
1541*7485b225SElliott Hughes 
1542*7485b225SElliott Hughes 
QueryDoubleValue(double * value) const1543*7485b225SElliott Hughes XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1544*7485b225SElliott Hughes {
1545*7485b225SElliott Hughes     if ( XMLUtil::ToDouble( Value(), value )) {
1546*7485b225SElliott Hughes         return XML_SUCCESS;
1547*7485b225SElliott Hughes     }
1548*7485b225SElliott Hughes     return XML_WRONG_ATTRIBUTE_TYPE;
1549*7485b225SElliott Hughes }
1550*7485b225SElliott Hughes 
1551*7485b225SElliott Hughes 
SetAttribute(const char * v)1552*7485b225SElliott Hughes void XMLAttribute::SetAttribute( const char* v )
1553*7485b225SElliott Hughes {
1554*7485b225SElliott Hughes     _value.SetStr( v );
1555*7485b225SElliott Hughes }
1556*7485b225SElliott Hughes 
1557*7485b225SElliott Hughes 
SetAttribute(int v)1558*7485b225SElliott Hughes void XMLAttribute::SetAttribute( int v )
1559*7485b225SElliott Hughes {
1560*7485b225SElliott Hughes     char buf[BUF_SIZE];
1561*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1562*7485b225SElliott Hughes     _value.SetStr( buf );
1563*7485b225SElliott Hughes }
1564*7485b225SElliott Hughes 
1565*7485b225SElliott Hughes 
SetAttribute(unsigned v)1566*7485b225SElliott Hughes void XMLAttribute::SetAttribute( unsigned v )
1567*7485b225SElliott Hughes {
1568*7485b225SElliott Hughes     char buf[BUF_SIZE];
1569*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1570*7485b225SElliott Hughes     _value.SetStr( buf );
1571*7485b225SElliott Hughes }
1572*7485b225SElliott Hughes 
1573*7485b225SElliott Hughes 
SetAttribute(int64_t v)1574*7485b225SElliott Hughes void XMLAttribute::SetAttribute(int64_t v)
1575*7485b225SElliott Hughes {
1576*7485b225SElliott Hughes 	char buf[BUF_SIZE];
1577*7485b225SElliott Hughes 	XMLUtil::ToStr(v, buf, BUF_SIZE);
1578*7485b225SElliott Hughes 	_value.SetStr(buf);
1579*7485b225SElliott Hughes }
1580*7485b225SElliott Hughes 
SetAttribute(uint64_t v)1581*7485b225SElliott Hughes void XMLAttribute::SetAttribute(uint64_t v)
1582*7485b225SElliott Hughes {
1583*7485b225SElliott Hughes     char buf[BUF_SIZE];
1584*7485b225SElliott Hughes     XMLUtil::ToStr(v, buf, BUF_SIZE);
1585*7485b225SElliott Hughes     _value.SetStr(buf);
1586*7485b225SElliott Hughes }
1587*7485b225SElliott Hughes 
1588*7485b225SElliott Hughes 
SetAttribute(bool v)1589*7485b225SElliott Hughes void XMLAttribute::SetAttribute( bool v )
1590*7485b225SElliott Hughes {
1591*7485b225SElliott Hughes     char buf[BUF_SIZE];
1592*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1593*7485b225SElliott Hughes     _value.SetStr( buf );
1594*7485b225SElliott Hughes }
1595*7485b225SElliott Hughes 
SetAttribute(double v)1596*7485b225SElliott Hughes void XMLAttribute::SetAttribute( double v )
1597*7485b225SElliott Hughes {
1598*7485b225SElliott Hughes     char buf[BUF_SIZE];
1599*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1600*7485b225SElliott Hughes     _value.SetStr( buf );
1601*7485b225SElliott Hughes }
1602*7485b225SElliott Hughes 
SetAttribute(float v)1603*7485b225SElliott Hughes void XMLAttribute::SetAttribute( float v )
1604*7485b225SElliott Hughes {
1605*7485b225SElliott Hughes     char buf[BUF_SIZE];
1606*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1607*7485b225SElliott Hughes     _value.SetStr( buf );
1608*7485b225SElliott Hughes }
1609*7485b225SElliott Hughes 
1610*7485b225SElliott Hughes 
1611*7485b225SElliott Hughes // --------- XMLElement ---------- //
XMLElement(XMLDocument * doc)1612*7485b225SElliott Hughes XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1613*7485b225SElliott Hughes     _closingType( OPEN ),
1614*7485b225SElliott Hughes     _rootAttribute( 0 )
1615*7485b225SElliott Hughes {
1616*7485b225SElliott Hughes }
1617*7485b225SElliott Hughes 
1618*7485b225SElliott Hughes 
~XMLElement()1619*7485b225SElliott Hughes XMLElement::~XMLElement()
1620*7485b225SElliott Hughes {
1621*7485b225SElliott Hughes     while( _rootAttribute ) {
1622*7485b225SElliott Hughes         XMLAttribute* next = _rootAttribute->_next;
1623*7485b225SElliott Hughes         DeleteAttribute( _rootAttribute );
1624*7485b225SElliott Hughes         _rootAttribute = next;
1625*7485b225SElliott Hughes     }
1626*7485b225SElliott Hughes }
1627*7485b225SElliott Hughes 
1628*7485b225SElliott Hughes 
FindAttribute(const char * name) const1629*7485b225SElliott Hughes const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1630*7485b225SElliott Hughes {
1631*7485b225SElliott Hughes     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1632*7485b225SElliott Hughes         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1633*7485b225SElliott Hughes             return a;
1634*7485b225SElliott Hughes         }
1635*7485b225SElliott Hughes     }
1636*7485b225SElliott Hughes     return 0;
1637*7485b225SElliott Hughes }
1638*7485b225SElliott Hughes 
1639*7485b225SElliott Hughes 
Attribute(const char * name,const char * value) const1640*7485b225SElliott Hughes const char* XMLElement::Attribute( const char* name, const char* value ) const
1641*7485b225SElliott Hughes {
1642*7485b225SElliott Hughes     const XMLAttribute* a = FindAttribute( name );
1643*7485b225SElliott Hughes     if ( !a ) {
1644*7485b225SElliott Hughes         return 0;
1645*7485b225SElliott Hughes     }
1646*7485b225SElliott Hughes     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1647*7485b225SElliott Hughes         return a->Value();
1648*7485b225SElliott Hughes     }
1649*7485b225SElliott Hughes     return 0;
1650*7485b225SElliott Hughes }
1651*7485b225SElliott Hughes 
IntAttribute(const char * name,int defaultValue) const1652*7485b225SElliott Hughes int XMLElement::IntAttribute(const char* name, int defaultValue) const
1653*7485b225SElliott Hughes {
1654*7485b225SElliott Hughes 	int i = defaultValue;
1655*7485b225SElliott Hughes 	QueryIntAttribute(name, &i);
1656*7485b225SElliott Hughes 	return i;
1657*7485b225SElliott Hughes }
1658*7485b225SElliott Hughes 
UnsignedAttribute(const char * name,unsigned defaultValue) const1659*7485b225SElliott Hughes unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1660*7485b225SElliott Hughes {
1661*7485b225SElliott Hughes 	unsigned i = defaultValue;
1662*7485b225SElliott Hughes 	QueryUnsignedAttribute(name, &i);
1663*7485b225SElliott Hughes 	return i;
1664*7485b225SElliott Hughes }
1665*7485b225SElliott Hughes 
Int64Attribute(const char * name,int64_t defaultValue) const1666*7485b225SElliott Hughes int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1667*7485b225SElliott Hughes {
1668*7485b225SElliott Hughes 	int64_t i = defaultValue;
1669*7485b225SElliott Hughes 	QueryInt64Attribute(name, &i);
1670*7485b225SElliott Hughes 	return i;
1671*7485b225SElliott Hughes }
1672*7485b225SElliott Hughes 
Unsigned64Attribute(const char * name,uint64_t defaultValue) const1673*7485b225SElliott Hughes uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1674*7485b225SElliott Hughes {
1675*7485b225SElliott Hughes 	uint64_t i = defaultValue;
1676*7485b225SElliott Hughes 	QueryUnsigned64Attribute(name, &i);
1677*7485b225SElliott Hughes 	return i;
1678*7485b225SElliott Hughes }
1679*7485b225SElliott Hughes 
BoolAttribute(const char * name,bool defaultValue) const1680*7485b225SElliott Hughes bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1681*7485b225SElliott Hughes {
1682*7485b225SElliott Hughes 	bool b = defaultValue;
1683*7485b225SElliott Hughes 	QueryBoolAttribute(name, &b);
1684*7485b225SElliott Hughes 	return b;
1685*7485b225SElliott Hughes }
1686*7485b225SElliott Hughes 
DoubleAttribute(const char * name,double defaultValue) const1687*7485b225SElliott Hughes double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1688*7485b225SElliott Hughes {
1689*7485b225SElliott Hughes 	double d = defaultValue;
1690*7485b225SElliott Hughes 	QueryDoubleAttribute(name, &d);
1691*7485b225SElliott Hughes 	return d;
1692*7485b225SElliott Hughes }
1693*7485b225SElliott Hughes 
FloatAttribute(const char * name,float defaultValue) const1694*7485b225SElliott Hughes float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1695*7485b225SElliott Hughes {
1696*7485b225SElliott Hughes 	float f = defaultValue;
1697*7485b225SElliott Hughes 	QueryFloatAttribute(name, &f);
1698*7485b225SElliott Hughes 	return f;
1699*7485b225SElliott Hughes }
1700*7485b225SElliott Hughes 
GetText() const1701*7485b225SElliott Hughes const char* XMLElement::GetText() const
1702*7485b225SElliott Hughes {
1703*7485b225SElliott Hughes     /* skip comment node */
1704*7485b225SElliott Hughes     const XMLNode* node = FirstChild();
1705*7485b225SElliott Hughes     while (node) {
1706*7485b225SElliott Hughes         if (node->ToComment()) {
1707*7485b225SElliott Hughes             node = node->NextSibling();
1708*7485b225SElliott Hughes             continue;
1709*7485b225SElliott Hughes         }
1710*7485b225SElliott Hughes         break;
1711*7485b225SElliott Hughes     }
1712*7485b225SElliott Hughes 
1713*7485b225SElliott Hughes     if ( node && node->ToText() ) {
1714*7485b225SElliott Hughes         return node->Value();
1715*7485b225SElliott Hughes     }
1716*7485b225SElliott Hughes     return 0;
1717*7485b225SElliott Hughes }
1718*7485b225SElliott Hughes 
1719*7485b225SElliott Hughes 
SetText(const char * inText)1720*7485b225SElliott Hughes void	XMLElement::SetText( const char* inText )
1721*7485b225SElliott Hughes {
1722*7485b225SElliott Hughes 	if ( FirstChild() && FirstChild()->ToText() )
1723*7485b225SElliott Hughes 		FirstChild()->SetValue( inText );
1724*7485b225SElliott Hughes 	else {
1725*7485b225SElliott Hughes 		XMLText*	theText = GetDocument()->NewText( inText );
1726*7485b225SElliott Hughes 		InsertFirstChild( theText );
1727*7485b225SElliott Hughes 	}
1728*7485b225SElliott Hughes }
1729*7485b225SElliott Hughes 
1730*7485b225SElliott Hughes 
SetText(int v)1731*7485b225SElliott Hughes void XMLElement::SetText( int v )
1732*7485b225SElliott Hughes {
1733*7485b225SElliott Hughes     char buf[BUF_SIZE];
1734*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1735*7485b225SElliott Hughes     SetText( buf );
1736*7485b225SElliott Hughes }
1737*7485b225SElliott Hughes 
1738*7485b225SElliott Hughes 
SetText(unsigned v)1739*7485b225SElliott Hughes void XMLElement::SetText( unsigned v )
1740*7485b225SElliott Hughes {
1741*7485b225SElliott Hughes     char buf[BUF_SIZE];
1742*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1743*7485b225SElliott Hughes     SetText( buf );
1744*7485b225SElliott Hughes }
1745*7485b225SElliott Hughes 
1746*7485b225SElliott Hughes 
SetText(int64_t v)1747*7485b225SElliott Hughes void XMLElement::SetText(int64_t v)
1748*7485b225SElliott Hughes {
1749*7485b225SElliott Hughes 	char buf[BUF_SIZE];
1750*7485b225SElliott Hughes 	XMLUtil::ToStr(v, buf, BUF_SIZE);
1751*7485b225SElliott Hughes 	SetText(buf);
1752*7485b225SElliott Hughes }
1753*7485b225SElliott Hughes 
SetText(uint64_t v)1754*7485b225SElliott Hughes void XMLElement::SetText(uint64_t v) {
1755*7485b225SElliott Hughes     char buf[BUF_SIZE];
1756*7485b225SElliott Hughes     XMLUtil::ToStr(v, buf, BUF_SIZE);
1757*7485b225SElliott Hughes     SetText(buf);
1758*7485b225SElliott Hughes }
1759*7485b225SElliott Hughes 
1760*7485b225SElliott Hughes 
SetText(bool v)1761*7485b225SElliott Hughes void XMLElement::SetText( bool v )
1762*7485b225SElliott Hughes {
1763*7485b225SElliott Hughes     char buf[BUF_SIZE];
1764*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1765*7485b225SElliott Hughes     SetText( buf );
1766*7485b225SElliott Hughes }
1767*7485b225SElliott Hughes 
1768*7485b225SElliott Hughes 
SetText(float v)1769*7485b225SElliott Hughes void XMLElement::SetText( float v )
1770*7485b225SElliott Hughes {
1771*7485b225SElliott Hughes     char buf[BUF_SIZE];
1772*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1773*7485b225SElliott Hughes     SetText( buf );
1774*7485b225SElliott Hughes }
1775*7485b225SElliott Hughes 
1776*7485b225SElliott Hughes 
SetText(double v)1777*7485b225SElliott Hughes void XMLElement::SetText( double v )
1778*7485b225SElliott Hughes {
1779*7485b225SElliott Hughes     char buf[BUF_SIZE];
1780*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
1781*7485b225SElliott Hughes     SetText( buf );
1782*7485b225SElliott Hughes }
1783*7485b225SElliott Hughes 
1784*7485b225SElliott Hughes 
QueryIntText(int * ival) const1785*7485b225SElliott Hughes XMLError XMLElement::QueryIntText( int* ival ) const
1786*7485b225SElliott Hughes {
1787*7485b225SElliott Hughes     if ( FirstChild() && FirstChild()->ToText() ) {
1788*7485b225SElliott Hughes         const char* t = FirstChild()->Value();
1789*7485b225SElliott Hughes         if ( XMLUtil::ToInt( t, ival ) ) {
1790*7485b225SElliott Hughes             return XML_SUCCESS;
1791*7485b225SElliott Hughes         }
1792*7485b225SElliott Hughes         return XML_CAN_NOT_CONVERT_TEXT;
1793*7485b225SElliott Hughes     }
1794*7485b225SElliott Hughes     return XML_NO_TEXT_NODE;
1795*7485b225SElliott Hughes }
1796*7485b225SElliott Hughes 
1797*7485b225SElliott Hughes 
QueryUnsignedText(unsigned * uval) const1798*7485b225SElliott Hughes XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1799*7485b225SElliott Hughes {
1800*7485b225SElliott Hughes     if ( FirstChild() && FirstChild()->ToText() ) {
1801*7485b225SElliott Hughes         const char* t = FirstChild()->Value();
1802*7485b225SElliott Hughes         if ( XMLUtil::ToUnsigned( t, uval ) ) {
1803*7485b225SElliott Hughes             return XML_SUCCESS;
1804*7485b225SElliott Hughes         }
1805*7485b225SElliott Hughes         return XML_CAN_NOT_CONVERT_TEXT;
1806*7485b225SElliott Hughes     }
1807*7485b225SElliott Hughes     return XML_NO_TEXT_NODE;
1808*7485b225SElliott Hughes }
1809*7485b225SElliott Hughes 
1810*7485b225SElliott Hughes 
QueryInt64Text(int64_t * ival) const1811*7485b225SElliott Hughes XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1812*7485b225SElliott Hughes {
1813*7485b225SElliott Hughes 	if (FirstChild() && FirstChild()->ToText()) {
1814*7485b225SElliott Hughes 		const char* t = FirstChild()->Value();
1815*7485b225SElliott Hughes 		if (XMLUtil::ToInt64(t, ival)) {
1816*7485b225SElliott Hughes 			return XML_SUCCESS;
1817*7485b225SElliott Hughes 		}
1818*7485b225SElliott Hughes 		return XML_CAN_NOT_CONVERT_TEXT;
1819*7485b225SElliott Hughes 	}
1820*7485b225SElliott Hughes 	return XML_NO_TEXT_NODE;
1821*7485b225SElliott Hughes }
1822*7485b225SElliott Hughes 
1823*7485b225SElliott Hughes 
QueryUnsigned64Text(uint64_t * uval) const1824*7485b225SElliott Hughes XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const
1825*7485b225SElliott Hughes {
1826*7485b225SElliott Hughes     if(FirstChild() && FirstChild()->ToText()) {
1827*7485b225SElliott Hughes         const char* t = FirstChild()->Value();
1828*7485b225SElliott Hughes         if(XMLUtil::ToUnsigned64(t, uval)) {
1829*7485b225SElliott Hughes             return XML_SUCCESS;
1830*7485b225SElliott Hughes         }
1831*7485b225SElliott Hughes         return XML_CAN_NOT_CONVERT_TEXT;
1832*7485b225SElliott Hughes     }
1833*7485b225SElliott Hughes     return XML_NO_TEXT_NODE;
1834*7485b225SElliott Hughes }
1835*7485b225SElliott Hughes 
1836*7485b225SElliott Hughes 
QueryBoolText(bool * bval) const1837*7485b225SElliott Hughes XMLError XMLElement::QueryBoolText( bool* bval ) const
1838*7485b225SElliott Hughes {
1839*7485b225SElliott Hughes     if ( FirstChild() && FirstChild()->ToText() ) {
1840*7485b225SElliott Hughes         const char* t = FirstChild()->Value();
1841*7485b225SElliott Hughes         if ( XMLUtil::ToBool( t, bval ) ) {
1842*7485b225SElliott Hughes             return XML_SUCCESS;
1843*7485b225SElliott Hughes         }
1844*7485b225SElliott Hughes         return XML_CAN_NOT_CONVERT_TEXT;
1845*7485b225SElliott Hughes     }
1846*7485b225SElliott Hughes     return XML_NO_TEXT_NODE;
1847*7485b225SElliott Hughes }
1848*7485b225SElliott Hughes 
1849*7485b225SElliott Hughes 
QueryDoubleText(double * dval) const1850*7485b225SElliott Hughes XMLError XMLElement::QueryDoubleText( double* dval ) const
1851*7485b225SElliott Hughes {
1852*7485b225SElliott Hughes     if ( FirstChild() && FirstChild()->ToText() ) {
1853*7485b225SElliott Hughes         const char* t = FirstChild()->Value();
1854*7485b225SElliott Hughes         if ( XMLUtil::ToDouble( t, dval ) ) {
1855*7485b225SElliott Hughes             return XML_SUCCESS;
1856*7485b225SElliott Hughes         }
1857*7485b225SElliott Hughes         return XML_CAN_NOT_CONVERT_TEXT;
1858*7485b225SElliott Hughes     }
1859*7485b225SElliott Hughes     return XML_NO_TEXT_NODE;
1860*7485b225SElliott Hughes }
1861*7485b225SElliott Hughes 
1862*7485b225SElliott Hughes 
QueryFloatText(float * fval) const1863*7485b225SElliott Hughes XMLError XMLElement::QueryFloatText( float* fval ) const
1864*7485b225SElliott Hughes {
1865*7485b225SElliott Hughes     if ( FirstChild() && FirstChild()->ToText() ) {
1866*7485b225SElliott Hughes         const char* t = FirstChild()->Value();
1867*7485b225SElliott Hughes         if ( XMLUtil::ToFloat( t, fval ) ) {
1868*7485b225SElliott Hughes             return XML_SUCCESS;
1869*7485b225SElliott Hughes         }
1870*7485b225SElliott Hughes         return XML_CAN_NOT_CONVERT_TEXT;
1871*7485b225SElliott Hughes     }
1872*7485b225SElliott Hughes     return XML_NO_TEXT_NODE;
1873*7485b225SElliott Hughes }
1874*7485b225SElliott Hughes 
IntText(int defaultValue) const1875*7485b225SElliott Hughes int XMLElement::IntText(int defaultValue) const
1876*7485b225SElliott Hughes {
1877*7485b225SElliott Hughes 	int i = defaultValue;
1878*7485b225SElliott Hughes 	QueryIntText(&i);
1879*7485b225SElliott Hughes 	return i;
1880*7485b225SElliott Hughes }
1881*7485b225SElliott Hughes 
UnsignedText(unsigned defaultValue) const1882*7485b225SElliott Hughes unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1883*7485b225SElliott Hughes {
1884*7485b225SElliott Hughes 	unsigned i = defaultValue;
1885*7485b225SElliott Hughes 	QueryUnsignedText(&i);
1886*7485b225SElliott Hughes 	return i;
1887*7485b225SElliott Hughes }
1888*7485b225SElliott Hughes 
Int64Text(int64_t defaultValue) const1889*7485b225SElliott Hughes int64_t XMLElement::Int64Text(int64_t defaultValue) const
1890*7485b225SElliott Hughes {
1891*7485b225SElliott Hughes 	int64_t i = defaultValue;
1892*7485b225SElliott Hughes 	QueryInt64Text(&i);
1893*7485b225SElliott Hughes 	return i;
1894*7485b225SElliott Hughes }
1895*7485b225SElliott Hughes 
Unsigned64Text(uint64_t defaultValue) const1896*7485b225SElliott Hughes uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1897*7485b225SElliott Hughes {
1898*7485b225SElliott Hughes 	uint64_t i = defaultValue;
1899*7485b225SElliott Hughes 	QueryUnsigned64Text(&i);
1900*7485b225SElliott Hughes 	return i;
1901*7485b225SElliott Hughes }
1902*7485b225SElliott Hughes 
BoolText(bool defaultValue) const1903*7485b225SElliott Hughes bool XMLElement::BoolText(bool defaultValue) const
1904*7485b225SElliott Hughes {
1905*7485b225SElliott Hughes 	bool b = defaultValue;
1906*7485b225SElliott Hughes 	QueryBoolText(&b);
1907*7485b225SElliott Hughes 	return b;
1908*7485b225SElliott Hughes }
1909*7485b225SElliott Hughes 
DoubleText(double defaultValue) const1910*7485b225SElliott Hughes double XMLElement::DoubleText(double defaultValue) const
1911*7485b225SElliott Hughes {
1912*7485b225SElliott Hughes 	double d = defaultValue;
1913*7485b225SElliott Hughes 	QueryDoubleText(&d);
1914*7485b225SElliott Hughes 	return d;
1915*7485b225SElliott Hughes }
1916*7485b225SElliott Hughes 
FloatText(float defaultValue) const1917*7485b225SElliott Hughes float XMLElement::FloatText(float defaultValue) const
1918*7485b225SElliott Hughes {
1919*7485b225SElliott Hughes 	float f = defaultValue;
1920*7485b225SElliott Hughes 	QueryFloatText(&f);
1921*7485b225SElliott Hughes 	return f;
1922*7485b225SElliott Hughes }
1923*7485b225SElliott Hughes 
1924*7485b225SElliott Hughes 
FindOrCreateAttribute(const char * name)1925*7485b225SElliott Hughes XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1926*7485b225SElliott Hughes {
1927*7485b225SElliott Hughes     XMLAttribute* last = 0;
1928*7485b225SElliott Hughes     XMLAttribute* attrib = 0;
1929*7485b225SElliott Hughes     for( attrib = _rootAttribute;
1930*7485b225SElliott Hughes             attrib;
1931*7485b225SElliott Hughes             last = attrib, attrib = attrib->_next ) {
1932*7485b225SElliott Hughes         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1933*7485b225SElliott Hughes             break;
1934*7485b225SElliott Hughes         }
1935*7485b225SElliott Hughes     }
1936*7485b225SElliott Hughes     if ( !attrib ) {
1937*7485b225SElliott Hughes         attrib = CreateAttribute();
1938*7485b225SElliott Hughes         TIXMLASSERT( attrib );
1939*7485b225SElliott Hughes         if ( last ) {
1940*7485b225SElliott Hughes             TIXMLASSERT( last->_next == 0 );
1941*7485b225SElliott Hughes             last->_next = attrib;
1942*7485b225SElliott Hughes         }
1943*7485b225SElliott Hughes         else {
1944*7485b225SElliott Hughes             TIXMLASSERT( _rootAttribute == 0 );
1945*7485b225SElliott Hughes             _rootAttribute = attrib;
1946*7485b225SElliott Hughes         }
1947*7485b225SElliott Hughes         attrib->SetName( name );
1948*7485b225SElliott Hughes     }
1949*7485b225SElliott Hughes     return attrib;
1950*7485b225SElliott Hughes }
1951*7485b225SElliott Hughes 
1952*7485b225SElliott Hughes 
DeleteAttribute(const char * name)1953*7485b225SElliott Hughes void XMLElement::DeleteAttribute( const char* name )
1954*7485b225SElliott Hughes {
1955*7485b225SElliott Hughes     XMLAttribute* prev = 0;
1956*7485b225SElliott Hughes     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1957*7485b225SElliott Hughes         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1958*7485b225SElliott Hughes             if ( prev ) {
1959*7485b225SElliott Hughes                 prev->_next = a->_next;
1960*7485b225SElliott Hughes             }
1961*7485b225SElliott Hughes             else {
1962*7485b225SElliott Hughes                 _rootAttribute = a->_next;
1963*7485b225SElliott Hughes             }
1964*7485b225SElliott Hughes             DeleteAttribute( a );
1965*7485b225SElliott Hughes             break;
1966*7485b225SElliott Hughes         }
1967*7485b225SElliott Hughes         prev = a;
1968*7485b225SElliott Hughes     }
1969*7485b225SElliott Hughes }
1970*7485b225SElliott Hughes 
1971*7485b225SElliott Hughes 
ParseAttributes(char * p,int * curLineNumPtr)1972*7485b225SElliott Hughes char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
1973*7485b225SElliott Hughes {
1974*7485b225SElliott Hughes     XMLAttribute* prevAttribute = 0;
1975*7485b225SElliott Hughes 
1976*7485b225SElliott Hughes     // Read the attributes.
1977*7485b225SElliott Hughes     while( p ) {
1978*7485b225SElliott Hughes         p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1979*7485b225SElliott Hughes         if ( !(*p) ) {
1980*7485b225SElliott Hughes             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1981*7485b225SElliott Hughes             return 0;
1982*7485b225SElliott Hughes         }
1983*7485b225SElliott Hughes 
1984*7485b225SElliott Hughes         // attribute.
1985*7485b225SElliott Hughes         if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
1986*7485b225SElliott Hughes             XMLAttribute* attrib = CreateAttribute();
1987*7485b225SElliott Hughes             TIXMLASSERT( attrib );
1988*7485b225SElliott Hughes             attrib->_parseLineNum = _document->_parseCurLineNum;
1989*7485b225SElliott Hughes 
1990*7485b225SElliott Hughes             const int attrLineNum = attrib->_parseLineNum;
1991*7485b225SElliott Hughes 
1992*7485b225SElliott Hughes             p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
1993*7485b225SElliott Hughes             if ( !p || Attribute( attrib->Name() ) ) {
1994*7485b225SElliott Hughes                 DeleteAttribute( attrib );
1995*7485b225SElliott Hughes                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
1996*7485b225SElliott Hughes                 return 0;
1997*7485b225SElliott Hughes             }
1998*7485b225SElliott Hughes             // There is a minor bug here: if the attribute in the source xml
1999*7485b225SElliott Hughes             // document is duplicated, it will not be detected and the
2000*7485b225SElliott Hughes             // attribute will be doubly added. However, tracking the 'prevAttribute'
2001*7485b225SElliott Hughes             // avoids re-scanning the attribute list. Preferring performance for
2002*7485b225SElliott Hughes             // now, may reconsider in the future.
2003*7485b225SElliott Hughes             if ( prevAttribute ) {
2004*7485b225SElliott Hughes                 TIXMLASSERT( prevAttribute->_next == 0 );
2005*7485b225SElliott Hughes                 prevAttribute->_next = attrib;
2006*7485b225SElliott Hughes             }
2007*7485b225SElliott Hughes             else {
2008*7485b225SElliott Hughes                 TIXMLASSERT( _rootAttribute == 0 );
2009*7485b225SElliott Hughes                 _rootAttribute = attrib;
2010*7485b225SElliott Hughes             }
2011*7485b225SElliott Hughes             prevAttribute = attrib;
2012*7485b225SElliott Hughes         }
2013*7485b225SElliott Hughes         // end of the tag
2014*7485b225SElliott Hughes         else if ( *p == '>' ) {
2015*7485b225SElliott Hughes             ++p;
2016*7485b225SElliott Hughes             break;
2017*7485b225SElliott Hughes         }
2018*7485b225SElliott Hughes         // end of the tag
2019*7485b225SElliott Hughes         else if ( *p == '/' && *(p+1) == '>' ) {
2020*7485b225SElliott Hughes             _closingType = CLOSED;
2021*7485b225SElliott Hughes             return p+2;	// done; sealed element.
2022*7485b225SElliott Hughes         }
2023*7485b225SElliott Hughes         else {
2024*7485b225SElliott Hughes             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
2025*7485b225SElliott Hughes             return 0;
2026*7485b225SElliott Hughes         }
2027*7485b225SElliott Hughes     }
2028*7485b225SElliott Hughes     return p;
2029*7485b225SElliott Hughes }
2030*7485b225SElliott Hughes 
DeleteAttribute(XMLAttribute * attribute)2031*7485b225SElliott Hughes void XMLElement::DeleteAttribute( XMLAttribute* attribute )
2032*7485b225SElliott Hughes {
2033*7485b225SElliott Hughes     if ( attribute == 0 ) {
2034*7485b225SElliott Hughes         return;
2035*7485b225SElliott Hughes     }
2036*7485b225SElliott Hughes     MemPool* pool = attribute->_memPool;
2037*7485b225SElliott Hughes     attribute->~XMLAttribute();
2038*7485b225SElliott Hughes     pool->Free( attribute );
2039*7485b225SElliott Hughes }
2040*7485b225SElliott Hughes 
CreateAttribute()2041*7485b225SElliott Hughes XMLAttribute* XMLElement::CreateAttribute()
2042*7485b225SElliott Hughes {
2043*7485b225SElliott Hughes     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
2044*7485b225SElliott Hughes     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
2045*7485b225SElliott Hughes     TIXMLASSERT( attrib );
2046*7485b225SElliott Hughes     attrib->_memPool = &_document->_attributePool;
2047*7485b225SElliott Hughes     attrib->_memPool->SetTracked();
2048*7485b225SElliott Hughes     return attrib;
2049*7485b225SElliott Hughes }
2050*7485b225SElliott Hughes 
2051*7485b225SElliott Hughes 
InsertNewChildElement(const char * name)2052*7485b225SElliott Hughes XMLElement* XMLElement::InsertNewChildElement(const char* name)
2053*7485b225SElliott Hughes {
2054*7485b225SElliott Hughes     XMLElement* node = _document->NewElement(name);
2055*7485b225SElliott Hughes     return InsertEndChild(node) ? node : 0;
2056*7485b225SElliott Hughes }
2057*7485b225SElliott Hughes 
InsertNewComment(const char * comment)2058*7485b225SElliott Hughes XMLComment* XMLElement::InsertNewComment(const char* comment)
2059*7485b225SElliott Hughes {
2060*7485b225SElliott Hughes     XMLComment* node = _document->NewComment(comment);
2061*7485b225SElliott Hughes     return InsertEndChild(node) ? node : 0;
2062*7485b225SElliott Hughes }
2063*7485b225SElliott Hughes 
InsertNewText(const char * text)2064*7485b225SElliott Hughes XMLText* XMLElement::InsertNewText(const char* text)
2065*7485b225SElliott Hughes {
2066*7485b225SElliott Hughes     XMLText* node = _document->NewText(text);
2067*7485b225SElliott Hughes     return InsertEndChild(node) ? node : 0;
2068*7485b225SElliott Hughes }
2069*7485b225SElliott Hughes 
InsertNewDeclaration(const char * text)2070*7485b225SElliott Hughes XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)
2071*7485b225SElliott Hughes {
2072*7485b225SElliott Hughes     XMLDeclaration* node = _document->NewDeclaration(text);
2073*7485b225SElliott Hughes     return InsertEndChild(node) ? node : 0;
2074*7485b225SElliott Hughes }
2075*7485b225SElliott Hughes 
InsertNewUnknown(const char * text)2076*7485b225SElliott Hughes XMLUnknown* XMLElement::InsertNewUnknown(const char* text)
2077*7485b225SElliott Hughes {
2078*7485b225SElliott Hughes     XMLUnknown* node = _document->NewUnknown(text);
2079*7485b225SElliott Hughes     return InsertEndChild(node) ? node : 0;
2080*7485b225SElliott Hughes }
2081*7485b225SElliott Hughes 
2082*7485b225SElliott Hughes 
2083*7485b225SElliott Hughes 
2084*7485b225SElliott Hughes //
2085*7485b225SElliott Hughes //	<ele></ele>
2086*7485b225SElliott Hughes //	<ele>foo<b>bar</b></ele>
2087*7485b225SElliott Hughes //
ParseDeep(char * p,StrPair * parentEndTag,int * curLineNumPtr)2088*7485b225SElliott Hughes char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
2089*7485b225SElliott Hughes {
2090*7485b225SElliott Hughes     // Read the element name.
2091*7485b225SElliott Hughes     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
2092*7485b225SElliott Hughes 
2093*7485b225SElliott Hughes     // The closing element is the </element> form. It is
2094*7485b225SElliott Hughes     // parsed just like a regular element then deleted from
2095*7485b225SElliott Hughes     // the DOM.
2096*7485b225SElliott Hughes     if ( *p == '/' ) {
2097*7485b225SElliott Hughes         _closingType = CLOSING;
2098*7485b225SElliott Hughes         ++p;
2099*7485b225SElliott Hughes     }
2100*7485b225SElliott Hughes 
2101*7485b225SElliott Hughes     p = _value.ParseName( p );
2102*7485b225SElliott Hughes     if ( _value.Empty() ) {
2103*7485b225SElliott Hughes         return 0;
2104*7485b225SElliott Hughes     }
2105*7485b225SElliott Hughes 
2106*7485b225SElliott Hughes     p = ParseAttributes( p, curLineNumPtr );
2107*7485b225SElliott Hughes     if ( !p || !*p || _closingType != OPEN ) {
2108*7485b225SElliott Hughes         return p;
2109*7485b225SElliott Hughes     }
2110*7485b225SElliott Hughes 
2111*7485b225SElliott Hughes     p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2112*7485b225SElliott Hughes     return p;
2113*7485b225SElliott Hughes }
2114*7485b225SElliott Hughes 
2115*7485b225SElliott Hughes 
2116*7485b225SElliott Hughes 
ShallowClone(XMLDocument * doc) const2117*7485b225SElliott Hughes XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2118*7485b225SElliott Hughes {
2119*7485b225SElliott Hughes     if ( !doc ) {
2120*7485b225SElliott Hughes         doc = _document;
2121*7485b225SElliott Hughes     }
2122*7485b225SElliott Hughes     XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
2123*7485b225SElliott Hughes     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2124*7485b225SElliott Hughes         element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
2125*7485b225SElliott Hughes     }
2126*7485b225SElliott Hughes     return element;
2127*7485b225SElliott Hughes }
2128*7485b225SElliott Hughes 
2129*7485b225SElliott Hughes 
ShallowEqual(const XMLNode * compare) const2130*7485b225SElliott Hughes bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2131*7485b225SElliott Hughes {
2132*7485b225SElliott Hughes     TIXMLASSERT( compare );
2133*7485b225SElliott Hughes     const XMLElement* other = compare->ToElement();
2134*7485b225SElliott Hughes     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
2135*7485b225SElliott Hughes 
2136*7485b225SElliott Hughes         const XMLAttribute* a=FirstAttribute();
2137*7485b225SElliott Hughes         const XMLAttribute* b=other->FirstAttribute();
2138*7485b225SElliott Hughes 
2139*7485b225SElliott Hughes         while ( a && b ) {
2140*7485b225SElliott Hughes             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2141*7485b225SElliott Hughes                 return false;
2142*7485b225SElliott Hughes             }
2143*7485b225SElliott Hughes             a = a->Next();
2144*7485b225SElliott Hughes             b = b->Next();
2145*7485b225SElliott Hughes         }
2146*7485b225SElliott Hughes         if ( a || b ) {
2147*7485b225SElliott Hughes             // different count
2148*7485b225SElliott Hughes             return false;
2149*7485b225SElliott Hughes         }
2150*7485b225SElliott Hughes         return true;
2151*7485b225SElliott Hughes     }
2152*7485b225SElliott Hughes     return false;
2153*7485b225SElliott Hughes }
2154*7485b225SElliott Hughes 
2155*7485b225SElliott Hughes 
Accept(XMLVisitor * visitor) const2156*7485b225SElliott Hughes bool XMLElement::Accept( XMLVisitor* visitor ) const
2157*7485b225SElliott Hughes {
2158*7485b225SElliott Hughes     TIXMLASSERT( visitor );
2159*7485b225SElliott Hughes     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
2160*7485b225SElliott Hughes         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2161*7485b225SElliott Hughes             if ( !node->Accept( visitor ) ) {
2162*7485b225SElliott Hughes                 break;
2163*7485b225SElliott Hughes             }
2164*7485b225SElliott Hughes         }
2165*7485b225SElliott Hughes     }
2166*7485b225SElliott Hughes     return visitor->VisitExit( *this );
2167*7485b225SElliott Hughes }
2168*7485b225SElliott Hughes 
2169*7485b225SElliott Hughes 
2170*7485b225SElliott Hughes // --------- XMLDocument ----------- //
2171*7485b225SElliott Hughes 
2172*7485b225SElliott Hughes // Warning: List must match 'enum XMLError'
2173*7485b225SElliott Hughes const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2174*7485b225SElliott Hughes     "XML_SUCCESS",
2175*7485b225SElliott Hughes     "XML_NO_ATTRIBUTE",
2176*7485b225SElliott Hughes     "XML_WRONG_ATTRIBUTE_TYPE",
2177*7485b225SElliott Hughes     "XML_ERROR_FILE_NOT_FOUND",
2178*7485b225SElliott Hughes     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2179*7485b225SElliott Hughes     "XML_ERROR_FILE_READ_ERROR",
2180*7485b225SElliott Hughes     "XML_ERROR_PARSING_ELEMENT",
2181*7485b225SElliott Hughes     "XML_ERROR_PARSING_ATTRIBUTE",
2182*7485b225SElliott Hughes     "XML_ERROR_PARSING_TEXT",
2183*7485b225SElliott Hughes     "XML_ERROR_PARSING_CDATA",
2184*7485b225SElliott Hughes     "XML_ERROR_PARSING_COMMENT",
2185*7485b225SElliott Hughes     "XML_ERROR_PARSING_DECLARATION",
2186*7485b225SElliott Hughes     "XML_ERROR_PARSING_UNKNOWN",
2187*7485b225SElliott Hughes     "XML_ERROR_EMPTY_DOCUMENT",
2188*7485b225SElliott Hughes     "XML_ERROR_MISMATCHED_ELEMENT",
2189*7485b225SElliott Hughes     "XML_ERROR_PARSING",
2190*7485b225SElliott Hughes     "XML_CAN_NOT_CONVERT_TEXT",
2191*7485b225SElliott Hughes     "XML_NO_TEXT_NODE",
2192*7485b225SElliott Hughes 	"XML_ELEMENT_DEPTH_EXCEEDED"
2193*7485b225SElliott Hughes };
2194*7485b225SElliott Hughes 
2195*7485b225SElliott Hughes 
XMLDocument(bool processEntities,Whitespace whitespaceMode)2196*7485b225SElliott Hughes XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
2197*7485b225SElliott Hughes     XMLNode( 0 ),
2198*7485b225SElliott Hughes     _writeBOM( false ),
2199*7485b225SElliott Hughes     _processEntities( processEntities ),
2200*7485b225SElliott Hughes     _errorID(XML_SUCCESS),
2201*7485b225SElliott Hughes     _whitespaceMode( whitespaceMode ),
2202*7485b225SElliott Hughes     _errorStr(),
2203*7485b225SElliott Hughes     _errorLineNum( 0 ),
2204*7485b225SElliott Hughes     _charBuffer( 0 ),
2205*7485b225SElliott Hughes     _parseCurLineNum( 0 ),
2206*7485b225SElliott Hughes 	_parsingDepth(0),
2207*7485b225SElliott Hughes     _unlinked(),
2208*7485b225SElliott Hughes     _elementPool(),
2209*7485b225SElliott Hughes     _attributePool(),
2210*7485b225SElliott Hughes     _textPool(),
2211*7485b225SElliott Hughes     _commentPool()
2212*7485b225SElliott Hughes {
2213*7485b225SElliott Hughes     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
2214*7485b225SElliott Hughes     _document = this;
2215*7485b225SElliott Hughes }
2216*7485b225SElliott Hughes 
2217*7485b225SElliott Hughes 
~XMLDocument()2218*7485b225SElliott Hughes XMLDocument::~XMLDocument()
2219*7485b225SElliott Hughes {
2220*7485b225SElliott Hughes     Clear();
2221*7485b225SElliott Hughes }
2222*7485b225SElliott Hughes 
2223*7485b225SElliott Hughes 
MarkInUse(const XMLNode * const node)2224*7485b225SElliott Hughes void XMLDocument::MarkInUse(const XMLNode* const node)
2225*7485b225SElliott Hughes {
2226*7485b225SElliott Hughes 	TIXMLASSERT(node);
2227*7485b225SElliott Hughes 	TIXMLASSERT(node->_parent == 0);
2228*7485b225SElliott Hughes 
2229*7485b225SElliott Hughes 	for (int i = 0; i < _unlinked.Size(); ++i) {
2230*7485b225SElliott Hughes 		if (node == _unlinked[i]) {
2231*7485b225SElliott Hughes 			_unlinked.SwapRemove(i);
2232*7485b225SElliott Hughes 			break;
2233*7485b225SElliott Hughes 		}
2234*7485b225SElliott Hughes 	}
2235*7485b225SElliott Hughes }
2236*7485b225SElliott Hughes 
Clear()2237*7485b225SElliott Hughes void XMLDocument::Clear()
2238*7485b225SElliott Hughes {
2239*7485b225SElliott Hughes     DeleteChildren();
2240*7485b225SElliott Hughes 	while( _unlinked.Size()) {
2241*7485b225SElliott Hughes 		DeleteNode(_unlinked[0]);	// Will remove from _unlinked as part of delete.
2242*7485b225SElliott Hughes 	}
2243*7485b225SElliott Hughes 
2244*7485b225SElliott Hughes #ifdef TINYXML2_DEBUG
2245*7485b225SElliott Hughes     const bool hadError = Error();
2246*7485b225SElliott Hughes #endif
2247*7485b225SElliott Hughes     ClearError();
2248*7485b225SElliott Hughes 
2249*7485b225SElliott Hughes     delete [] _charBuffer;
2250*7485b225SElliott Hughes     _charBuffer = 0;
2251*7485b225SElliott Hughes 	_parsingDepth = 0;
2252*7485b225SElliott Hughes 
2253*7485b225SElliott Hughes #if 0
2254*7485b225SElliott Hughes     _textPool.Trace( "text" );
2255*7485b225SElliott Hughes     _elementPool.Trace( "element" );
2256*7485b225SElliott Hughes     _commentPool.Trace( "comment" );
2257*7485b225SElliott Hughes     _attributePool.Trace( "attribute" );
2258*7485b225SElliott Hughes #endif
2259*7485b225SElliott Hughes 
2260*7485b225SElliott Hughes #ifdef TINYXML2_DEBUG
2261*7485b225SElliott Hughes     if ( !hadError ) {
2262*7485b225SElliott Hughes         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
2263*7485b225SElliott Hughes         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2264*7485b225SElliott Hughes         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
2265*7485b225SElliott Hughes         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
2266*7485b225SElliott Hughes     }
2267*7485b225SElliott Hughes #endif
2268*7485b225SElliott Hughes }
2269*7485b225SElliott Hughes 
2270*7485b225SElliott Hughes 
DeepCopy(XMLDocument * target) const2271*7485b225SElliott Hughes void XMLDocument::DeepCopy(XMLDocument* target) const
2272*7485b225SElliott Hughes {
2273*7485b225SElliott Hughes 	TIXMLASSERT(target);
2274*7485b225SElliott Hughes     if (target == this) {
2275*7485b225SElliott Hughes         return; // technically success - a no-op.
2276*7485b225SElliott Hughes     }
2277*7485b225SElliott Hughes 
2278*7485b225SElliott Hughes 	target->Clear();
2279*7485b225SElliott Hughes 	for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2280*7485b225SElliott Hughes 		target->InsertEndChild(node->DeepClone(target));
2281*7485b225SElliott Hughes 	}
2282*7485b225SElliott Hughes }
2283*7485b225SElliott Hughes 
NewElement(const char * name)2284*7485b225SElliott Hughes XMLElement* XMLDocument::NewElement( const char* name )
2285*7485b225SElliott Hughes {
2286*7485b225SElliott Hughes     XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
2287*7485b225SElliott Hughes     ele->SetName( name );
2288*7485b225SElliott Hughes     return ele;
2289*7485b225SElliott Hughes }
2290*7485b225SElliott Hughes 
2291*7485b225SElliott Hughes 
NewComment(const char * str)2292*7485b225SElliott Hughes XMLComment* XMLDocument::NewComment( const char* str )
2293*7485b225SElliott Hughes {
2294*7485b225SElliott Hughes     XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
2295*7485b225SElliott Hughes     comment->SetValue( str );
2296*7485b225SElliott Hughes     return comment;
2297*7485b225SElliott Hughes }
2298*7485b225SElliott Hughes 
2299*7485b225SElliott Hughes 
NewText(const char * str)2300*7485b225SElliott Hughes XMLText* XMLDocument::NewText( const char* str )
2301*7485b225SElliott Hughes {
2302*7485b225SElliott Hughes     XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
2303*7485b225SElliott Hughes     text->SetValue( str );
2304*7485b225SElliott Hughes     return text;
2305*7485b225SElliott Hughes }
2306*7485b225SElliott Hughes 
2307*7485b225SElliott Hughes 
NewDeclaration(const char * str)2308*7485b225SElliott Hughes XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2309*7485b225SElliott Hughes {
2310*7485b225SElliott Hughes     XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
2311*7485b225SElliott Hughes     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2312*7485b225SElliott Hughes     return dec;
2313*7485b225SElliott Hughes }
2314*7485b225SElliott Hughes 
2315*7485b225SElliott Hughes 
NewUnknown(const char * str)2316*7485b225SElliott Hughes XMLUnknown* XMLDocument::NewUnknown( const char* str )
2317*7485b225SElliott Hughes {
2318*7485b225SElliott Hughes     XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
2319*7485b225SElliott Hughes     unk->SetValue( str );
2320*7485b225SElliott Hughes     return unk;
2321*7485b225SElliott Hughes }
2322*7485b225SElliott Hughes 
callfopen(const char * filepath,const char * mode)2323*7485b225SElliott Hughes static FILE* callfopen( const char* filepath, const char* mode )
2324*7485b225SElliott Hughes {
2325*7485b225SElliott Hughes     TIXMLASSERT( filepath );
2326*7485b225SElliott Hughes     TIXMLASSERT( mode );
2327*7485b225SElliott Hughes #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2328*7485b225SElliott Hughes     FILE* fp = 0;
2329*7485b225SElliott Hughes     const errno_t err = fopen_s( &fp, filepath, mode );
2330*7485b225SElliott Hughes     if ( err ) {
2331*7485b225SElliott Hughes         return 0;
2332*7485b225SElliott Hughes     }
2333*7485b225SElliott Hughes #else
2334*7485b225SElliott Hughes     FILE* fp = fopen( filepath, mode );
2335*7485b225SElliott Hughes #endif
2336*7485b225SElliott Hughes     return fp;
2337*7485b225SElliott Hughes }
2338*7485b225SElliott Hughes 
DeleteNode(XMLNode * node)2339*7485b225SElliott Hughes void XMLDocument::DeleteNode( XMLNode* node )	{
2340*7485b225SElliott Hughes     TIXMLASSERT( node );
2341*7485b225SElliott Hughes     TIXMLASSERT(node->_document == this );
2342*7485b225SElliott Hughes     if (node->_parent) {
2343*7485b225SElliott Hughes         node->_parent->DeleteChild( node );
2344*7485b225SElliott Hughes     }
2345*7485b225SElliott Hughes     else {
2346*7485b225SElliott Hughes         // Isn't in the tree.
2347*7485b225SElliott Hughes         // Use the parent delete.
2348*7485b225SElliott Hughes         // Also, we need to mark it tracked: we 'know'
2349*7485b225SElliott Hughes         // it was never used.
2350*7485b225SElliott Hughes         node->_memPool->SetTracked();
2351*7485b225SElliott Hughes         // Call the static XMLNode version:
2352*7485b225SElliott Hughes         XMLNode::DeleteNode(node);
2353*7485b225SElliott Hughes     }
2354*7485b225SElliott Hughes }
2355*7485b225SElliott Hughes 
2356*7485b225SElliott Hughes 
LoadFile(const char * filename)2357*7485b225SElliott Hughes XMLError XMLDocument::LoadFile( const char* filename )
2358*7485b225SElliott Hughes {
2359*7485b225SElliott Hughes     if ( !filename ) {
2360*7485b225SElliott Hughes         TIXMLASSERT( false );
2361*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2362*7485b225SElliott Hughes         return _errorID;
2363*7485b225SElliott Hughes     }
2364*7485b225SElliott Hughes 
2365*7485b225SElliott Hughes     Clear();
2366*7485b225SElliott Hughes     FILE* fp = callfopen( filename, "rb" );
2367*7485b225SElliott Hughes     if ( !fp ) {
2368*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
2369*7485b225SElliott Hughes         return _errorID;
2370*7485b225SElliott Hughes     }
2371*7485b225SElliott Hughes     LoadFile( fp );
2372*7485b225SElliott Hughes     fclose( fp );
2373*7485b225SElliott Hughes     return _errorID;
2374*7485b225SElliott Hughes }
2375*7485b225SElliott Hughes 
LoadFile(FILE * fp)2376*7485b225SElliott Hughes XMLError XMLDocument::LoadFile( FILE* fp )
2377*7485b225SElliott Hughes {
2378*7485b225SElliott Hughes     Clear();
2379*7485b225SElliott Hughes 
2380*7485b225SElliott Hughes     TIXML_FSEEK( fp, 0, SEEK_SET );
2381*7485b225SElliott Hughes     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
2382*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2383*7485b225SElliott Hughes         return _errorID;
2384*7485b225SElliott Hughes     }
2385*7485b225SElliott Hughes 
2386*7485b225SElliott Hughes     TIXML_FSEEK( fp, 0, SEEK_END );
2387*7485b225SElliott Hughes 
2388*7485b225SElliott Hughes     unsigned long long filelength;
2389*7485b225SElliott Hughes     {
2390*7485b225SElliott Hughes         const long long fileLengthSigned = TIXML_FTELL( fp );
2391*7485b225SElliott Hughes         TIXML_FSEEK( fp, 0, SEEK_SET );
2392*7485b225SElliott Hughes         if ( fileLengthSigned == -1L ) {
2393*7485b225SElliott Hughes             SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2394*7485b225SElliott Hughes             return _errorID;
2395*7485b225SElliott Hughes         }
2396*7485b225SElliott Hughes         TIXMLASSERT( fileLengthSigned >= 0 );
2397*7485b225SElliott Hughes         filelength = static_cast<unsigned long long>(fileLengthSigned);
2398*7485b225SElliott Hughes     }
2399*7485b225SElliott Hughes 
2400*7485b225SElliott Hughes     const size_t maxSizeT = static_cast<size_t>(-1);
2401*7485b225SElliott Hughes     // We'll do the comparison as an unsigned long long, because that's guaranteed to be at
2402*7485b225SElliott Hughes     // least 8 bytes, even on a 32-bit platform.
2403*7485b225SElliott Hughes     if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {
2404*7485b225SElliott Hughes         // Cannot handle files which won't fit in buffer together with null terminator
2405*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2406*7485b225SElliott Hughes         return _errorID;
2407*7485b225SElliott Hughes     }
2408*7485b225SElliott Hughes 
2409*7485b225SElliott Hughes     if ( filelength == 0 ) {
2410*7485b225SElliott Hughes         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2411*7485b225SElliott Hughes         return _errorID;
2412*7485b225SElliott Hughes     }
2413*7485b225SElliott Hughes 
2414*7485b225SElliott Hughes     const size_t size = static_cast<size_t>(filelength);
2415*7485b225SElliott Hughes     TIXMLASSERT( _charBuffer == 0 );
2416*7485b225SElliott Hughes     _charBuffer = new char[size+1];
2417*7485b225SElliott Hughes     const size_t read = fread( _charBuffer, 1, size, fp );
2418*7485b225SElliott Hughes     if ( read != size ) {
2419*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2420*7485b225SElliott Hughes         return _errorID;
2421*7485b225SElliott Hughes     }
2422*7485b225SElliott Hughes 
2423*7485b225SElliott Hughes     _charBuffer[size] = 0;
2424*7485b225SElliott Hughes 
2425*7485b225SElliott Hughes     Parse();
2426*7485b225SElliott Hughes     return _errorID;
2427*7485b225SElliott Hughes }
2428*7485b225SElliott Hughes 
2429*7485b225SElliott Hughes 
SaveFile(const char * filename,bool compact)2430*7485b225SElliott Hughes XMLError XMLDocument::SaveFile( const char* filename, bool compact )
2431*7485b225SElliott Hughes {
2432*7485b225SElliott Hughes     if ( !filename ) {
2433*7485b225SElliott Hughes         TIXMLASSERT( false );
2434*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2435*7485b225SElliott Hughes         return _errorID;
2436*7485b225SElliott Hughes     }
2437*7485b225SElliott Hughes 
2438*7485b225SElliott Hughes     FILE* fp = callfopen( filename, "w" );
2439*7485b225SElliott Hughes     if ( !fp ) {
2440*7485b225SElliott Hughes         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
2441*7485b225SElliott Hughes         return _errorID;
2442*7485b225SElliott Hughes     }
2443*7485b225SElliott Hughes     SaveFile(fp, compact);
2444*7485b225SElliott Hughes     fclose( fp );
2445*7485b225SElliott Hughes     return _errorID;
2446*7485b225SElliott Hughes }
2447*7485b225SElliott Hughes 
2448*7485b225SElliott Hughes 
SaveFile(FILE * fp,bool compact)2449*7485b225SElliott Hughes XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2450*7485b225SElliott Hughes {
2451*7485b225SElliott Hughes     // Clear any error from the last save, otherwise it will get reported
2452*7485b225SElliott Hughes     // for *this* call.
2453*7485b225SElliott Hughes     ClearError();
2454*7485b225SElliott Hughes     XMLPrinter stream( fp, compact );
2455*7485b225SElliott Hughes     Print( &stream );
2456*7485b225SElliott Hughes     return _errorID;
2457*7485b225SElliott Hughes }
2458*7485b225SElliott Hughes 
2459*7485b225SElliott Hughes 
Parse(const char * xml,size_t nBytes)2460*7485b225SElliott Hughes XMLError XMLDocument::Parse( const char* xml, size_t nBytes )
2461*7485b225SElliott Hughes {
2462*7485b225SElliott Hughes     Clear();
2463*7485b225SElliott Hughes 
2464*7485b225SElliott Hughes     if ( nBytes == 0 || !xml || !*xml ) {
2465*7485b225SElliott Hughes         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2466*7485b225SElliott Hughes         return _errorID;
2467*7485b225SElliott Hughes     }
2468*7485b225SElliott Hughes     if ( nBytes == static_cast<size_t>(-1) ) {
2469*7485b225SElliott Hughes         nBytes = strlen( xml );
2470*7485b225SElliott Hughes     }
2471*7485b225SElliott Hughes     TIXMLASSERT( _charBuffer == 0 );
2472*7485b225SElliott Hughes     _charBuffer = new char[ nBytes+1 ];
2473*7485b225SElliott Hughes     memcpy( _charBuffer, xml, nBytes );
2474*7485b225SElliott Hughes     _charBuffer[nBytes] = 0;
2475*7485b225SElliott Hughes 
2476*7485b225SElliott Hughes     Parse();
2477*7485b225SElliott Hughes     if ( Error() ) {
2478*7485b225SElliott Hughes         // clean up now essentially dangling memory.
2479*7485b225SElliott Hughes         // and the parse fail can put objects in the
2480*7485b225SElliott Hughes         // pools that are dead and inaccessible.
2481*7485b225SElliott Hughes         DeleteChildren();
2482*7485b225SElliott Hughes         _elementPool.Clear();
2483*7485b225SElliott Hughes         _attributePool.Clear();
2484*7485b225SElliott Hughes         _textPool.Clear();
2485*7485b225SElliott Hughes         _commentPool.Clear();
2486*7485b225SElliott Hughes     }
2487*7485b225SElliott Hughes     return _errorID;
2488*7485b225SElliott Hughes }
2489*7485b225SElliott Hughes 
2490*7485b225SElliott Hughes 
Print(XMLPrinter * streamer) const2491*7485b225SElliott Hughes void XMLDocument::Print( XMLPrinter* streamer ) const
2492*7485b225SElliott Hughes {
2493*7485b225SElliott Hughes     if ( streamer ) {
2494*7485b225SElliott Hughes         Accept( streamer );
2495*7485b225SElliott Hughes     }
2496*7485b225SElliott Hughes     else {
2497*7485b225SElliott Hughes         XMLPrinter stdoutStreamer( stdout );
2498*7485b225SElliott Hughes         Accept( &stdoutStreamer );
2499*7485b225SElliott Hughes     }
2500*7485b225SElliott Hughes }
2501*7485b225SElliott Hughes 
2502*7485b225SElliott Hughes 
ClearError()2503*7485b225SElliott Hughes void XMLDocument::ClearError() {
2504*7485b225SElliott Hughes     _errorID = XML_SUCCESS;
2505*7485b225SElliott Hughes     _errorLineNum = 0;
2506*7485b225SElliott Hughes     _errorStr.Reset();
2507*7485b225SElliott Hughes }
2508*7485b225SElliott Hughes 
2509*7485b225SElliott Hughes 
SetError(XMLError error,int lineNum,const char * format,...)2510*7485b225SElliott Hughes void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2511*7485b225SElliott Hughes {
2512*7485b225SElliott Hughes     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2513*7485b225SElliott Hughes     _errorID = error;
2514*7485b225SElliott Hughes     _errorLineNum = lineNum;
2515*7485b225SElliott Hughes 	_errorStr.Reset();
2516*7485b225SElliott Hughes 
2517*7485b225SElliott Hughes     const size_t BUFFER_SIZE = 1000;
2518*7485b225SElliott Hughes     char* buffer = new char[BUFFER_SIZE];
2519*7485b225SElliott Hughes 
2520*7485b225SElliott Hughes     TIXMLASSERT(sizeof(error) <= sizeof(int));
2521*7485b225SElliott Hughes     TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
2522*7485b225SElliott Hughes 
2523*7485b225SElliott Hughes 	if (format) {
2524*7485b225SElliott Hughes 		size_t len = strlen(buffer);
2525*7485b225SElliott Hughes 		TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2526*7485b225SElliott Hughes 		len = strlen(buffer);
2527*7485b225SElliott Hughes 
2528*7485b225SElliott Hughes 		va_list va;
2529*7485b225SElliott Hughes 		va_start(va, format);
2530*7485b225SElliott Hughes 		TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2531*7485b225SElliott Hughes 		va_end(va);
2532*7485b225SElliott Hughes 	}
2533*7485b225SElliott Hughes 	_errorStr.SetStr(buffer);
2534*7485b225SElliott Hughes 	delete[] buffer;
2535*7485b225SElliott Hughes }
2536*7485b225SElliott Hughes 
2537*7485b225SElliott Hughes 
ErrorIDToName(XMLError errorID)2538*7485b225SElliott Hughes /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
2539*7485b225SElliott Hughes {
2540*7485b225SElliott Hughes 	TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2541*7485b225SElliott Hughes     const char* errorName = _errorNames[errorID];
2542*7485b225SElliott Hughes     TIXMLASSERT( errorName && errorName[0] );
2543*7485b225SElliott Hughes     return errorName;
2544*7485b225SElliott Hughes }
2545*7485b225SElliott Hughes 
ErrorStr() const2546*7485b225SElliott Hughes const char* XMLDocument::ErrorStr() const
2547*7485b225SElliott Hughes {
2548*7485b225SElliott Hughes 	return _errorStr.Empty() ? "" : _errorStr.GetStr();
2549*7485b225SElliott Hughes }
2550*7485b225SElliott Hughes 
2551*7485b225SElliott Hughes 
PrintError() const2552*7485b225SElliott Hughes void XMLDocument::PrintError() const
2553*7485b225SElliott Hughes {
2554*7485b225SElliott Hughes     printf("%s\n", ErrorStr());
2555*7485b225SElliott Hughes }
2556*7485b225SElliott Hughes 
ErrorName() const2557*7485b225SElliott Hughes const char* XMLDocument::ErrorName() const
2558*7485b225SElliott Hughes {
2559*7485b225SElliott Hughes     return ErrorIDToName(_errorID);
2560*7485b225SElliott Hughes }
2561*7485b225SElliott Hughes 
Parse()2562*7485b225SElliott Hughes void XMLDocument::Parse()
2563*7485b225SElliott Hughes {
2564*7485b225SElliott Hughes     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
2565*7485b225SElliott Hughes     TIXMLASSERT( _charBuffer );
2566*7485b225SElliott Hughes     _parseCurLineNum = 1;
2567*7485b225SElliott Hughes     _parseLineNum = 1;
2568*7485b225SElliott Hughes     char* p = _charBuffer;
2569*7485b225SElliott Hughes     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2570*7485b225SElliott Hughes     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2571*7485b225SElliott Hughes     if ( !*p ) {
2572*7485b225SElliott Hughes         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2573*7485b225SElliott Hughes         return;
2574*7485b225SElliott Hughes     }
2575*7485b225SElliott Hughes     ParseDeep(p, 0, &_parseCurLineNum );
2576*7485b225SElliott Hughes }
2577*7485b225SElliott Hughes 
PushDepth()2578*7485b225SElliott Hughes void XMLDocument::PushDepth()
2579*7485b225SElliott Hughes {
2580*7485b225SElliott Hughes 	_parsingDepth++;
2581*7485b225SElliott Hughes 	if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2582*7485b225SElliott Hughes 		SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2583*7485b225SElliott Hughes 	}
2584*7485b225SElliott Hughes }
2585*7485b225SElliott Hughes 
PopDepth()2586*7485b225SElliott Hughes void XMLDocument::PopDepth()
2587*7485b225SElliott Hughes {
2588*7485b225SElliott Hughes 	TIXMLASSERT(_parsingDepth > 0);
2589*7485b225SElliott Hughes 	--_parsingDepth;
2590*7485b225SElliott Hughes }
2591*7485b225SElliott Hughes 
XMLPrinter(FILE * file,bool compact,int depth)2592*7485b225SElliott Hughes XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2593*7485b225SElliott Hughes     _elementJustOpened( false ),
2594*7485b225SElliott Hughes     _stack(),
2595*7485b225SElliott Hughes     _firstElement( true ),
2596*7485b225SElliott Hughes     _fp( file ),
2597*7485b225SElliott Hughes     _depth( depth ),
2598*7485b225SElliott Hughes     _textDepth( -1 ),
2599*7485b225SElliott Hughes     _processEntities( true ),
2600*7485b225SElliott Hughes     _compactMode( compact ),
2601*7485b225SElliott Hughes     _buffer()
2602*7485b225SElliott Hughes {
2603*7485b225SElliott Hughes     for( int i=0; i<ENTITY_RANGE; ++i ) {
2604*7485b225SElliott Hughes         _entityFlag[i] = false;
2605*7485b225SElliott Hughes         _restrictedEntityFlag[i] = false;
2606*7485b225SElliott Hughes     }
2607*7485b225SElliott Hughes     for( int i=0; i<NUM_ENTITIES; ++i ) {
2608*7485b225SElliott Hughes         const char entityValue = entities[i].value;
2609*7485b225SElliott Hughes         const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
2610*7485b225SElliott Hughes         TIXMLASSERT( flagIndex < ENTITY_RANGE );
2611*7485b225SElliott Hughes         _entityFlag[flagIndex] = true;
2612*7485b225SElliott Hughes     }
2613*7485b225SElliott Hughes     _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2614*7485b225SElliott Hughes     _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2615*7485b225SElliott Hughes     _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;	// not required, but consistency is nice
2616*7485b225SElliott Hughes     _buffer.Push( 0 );
2617*7485b225SElliott Hughes }
2618*7485b225SElliott Hughes 
2619*7485b225SElliott Hughes 
Print(const char * format,...)2620*7485b225SElliott Hughes void XMLPrinter::Print( const char* format, ... )
2621*7485b225SElliott Hughes {
2622*7485b225SElliott Hughes     va_list     va;
2623*7485b225SElliott Hughes     va_start( va, format );
2624*7485b225SElliott Hughes 
2625*7485b225SElliott Hughes     if ( _fp ) {
2626*7485b225SElliott Hughes         vfprintf( _fp, format, va );
2627*7485b225SElliott Hughes     }
2628*7485b225SElliott Hughes     else {
2629*7485b225SElliott Hughes         const int len = TIXML_VSCPRINTF( format, va );
2630*7485b225SElliott Hughes         // Close out and re-start the va-args
2631*7485b225SElliott Hughes         va_end( va );
2632*7485b225SElliott Hughes         TIXMLASSERT( len >= 0 );
2633*7485b225SElliott Hughes         va_start( va, format );
2634*7485b225SElliott Hughes         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2635*7485b225SElliott Hughes         char* p = _buffer.PushArr( len ) - 1;	// back up over the null terminator.
2636*7485b225SElliott Hughes 		TIXML_VSNPRINTF( p, len+1, format, va );
2637*7485b225SElliott Hughes     }
2638*7485b225SElliott Hughes     va_end( va );
2639*7485b225SElliott Hughes }
2640*7485b225SElliott Hughes 
2641*7485b225SElliott Hughes 
Write(const char * data,size_t size)2642*7485b225SElliott Hughes void XMLPrinter::Write( const char* data, size_t size )
2643*7485b225SElliott Hughes {
2644*7485b225SElliott Hughes     if ( _fp ) {
2645*7485b225SElliott Hughes         fwrite ( data , sizeof(char), size, _fp);
2646*7485b225SElliott Hughes     }
2647*7485b225SElliott Hughes     else {
2648*7485b225SElliott Hughes         char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.
2649*7485b225SElliott Hughes         memcpy( p, data, size );
2650*7485b225SElliott Hughes         p[size] = 0;
2651*7485b225SElliott Hughes     }
2652*7485b225SElliott Hughes }
2653*7485b225SElliott Hughes 
2654*7485b225SElliott Hughes 
Putc(char ch)2655*7485b225SElliott Hughes void XMLPrinter::Putc( char ch )
2656*7485b225SElliott Hughes {
2657*7485b225SElliott Hughes     if ( _fp ) {
2658*7485b225SElliott Hughes         fputc ( ch, _fp);
2659*7485b225SElliott Hughes     }
2660*7485b225SElliott Hughes     else {
2661*7485b225SElliott Hughes         char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.
2662*7485b225SElliott Hughes         p[0] = ch;
2663*7485b225SElliott Hughes         p[1] = 0;
2664*7485b225SElliott Hughes     }
2665*7485b225SElliott Hughes }
2666*7485b225SElliott Hughes 
2667*7485b225SElliott Hughes 
PrintSpace(int depth)2668*7485b225SElliott Hughes void XMLPrinter::PrintSpace( int depth )
2669*7485b225SElliott Hughes {
2670*7485b225SElliott Hughes     for( int i=0; i<depth; ++i ) {
2671*7485b225SElliott Hughes         Write( "    " );
2672*7485b225SElliott Hughes     }
2673*7485b225SElliott Hughes }
2674*7485b225SElliott Hughes 
2675*7485b225SElliott Hughes 
PrintString(const char * p,bool restricted)2676*7485b225SElliott Hughes void XMLPrinter::PrintString( const char* p, bool restricted )
2677*7485b225SElliott Hughes {
2678*7485b225SElliott Hughes     // Look for runs of bytes between entities to print.
2679*7485b225SElliott Hughes     const char* q = p;
2680*7485b225SElliott Hughes 
2681*7485b225SElliott Hughes     if ( _processEntities ) {
2682*7485b225SElliott Hughes         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2683*7485b225SElliott Hughes         while ( *q ) {
2684*7485b225SElliott Hughes             TIXMLASSERT( p <= q );
2685*7485b225SElliott Hughes             // Remember, char is sometimes signed. (How many times has that bitten me?)
2686*7485b225SElliott Hughes             if ( *q > 0 && *q < ENTITY_RANGE ) {
2687*7485b225SElliott Hughes                 // Check for entities. If one is found, flush
2688*7485b225SElliott Hughes                 // the stream up until the entity, write the
2689*7485b225SElliott Hughes                 // entity, and keep looking.
2690*7485b225SElliott Hughes                 if ( flag[static_cast<unsigned char>(*q)] ) {
2691*7485b225SElliott Hughes                     while ( p < q ) {
2692*7485b225SElliott Hughes                         const size_t delta = q - p;
2693*7485b225SElliott Hughes                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2694*7485b225SElliott Hughes                         Write( p, toPrint );
2695*7485b225SElliott Hughes                         p += toPrint;
2696*7485b225SElliott Hughes                     }
2697*7485b225SElliott Hughes                     bool entityPatternPrinted = false;
2698*7485b225SElliott Hughes                     for( int i=0; i<NUM_ENTITIES; ++i ) {
2699*7485b225SElliott Hughes                         if ( entities[i].value == *q ) {
2700*7485b225SElliott Hughes                             Putc( '&' );
2701*7485b225SElliott Hughes                             Write( entities[i].pattern, entities[i].length );
2702*7485b225SElliott Hughes                             Putc( ';' );
2703*7485b225SElliott Hughes                             entityPatternPrinted = true;
2704*7485b225SElliott Hughes                             break;
2705*7485b225SElliott Hughes                         }
2706*7485b225SElliott Hughes                     }
2707*7485b225SElliott Hughes                     if ( !entityPatternPrinted ) {
2708*7485b225SElliott Hughes                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
2709*7485b225SElliott Hughes                         TIXMLASSERT( false );
2710*7485b225SElliott Hughes                     }
2711*7485b225SElliott Hughes                     ++p;
2712*7485b225SElliott Hughes                 }
2713*7485b225SElliott Hughes             }
2714*7485b225SElliott Hughes             ++q;
2715*7485b225SElliott Hughes             TIXMLASSERT( p <= q );
2716*7485b225SElliott Hughes         }
2717*7485b225SElliott Hughes         // Flush the remaining string. This will be the entire
2718*7485b225SElliott Hughes         // string if an entity wasn't found.
2719*7485b225SElliott Hughes         if ( p < q ) {
2720*7485b225SElliott Hughes             const size_t delta = q - p;
2721*7485b225SElliott Hughes             const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2722*7485b225SElliott Hughes             Write( p, toPrint );
2723*7485b225SElliott Hughes         }
2724*7485b225SElliott Hughes     }
2725*7485b225SElliott Hughes     else {
2726*7485b225SElliott Hughes         Write( p );
2727*7485b225SElliott Hughes     }
2728*7485b225SElliott Hughes }
2729*7485b225SElliott Hughes 
2730*7485b225SElliott Hughes 
PushHeader(bool writeBOM,bool writeDec)2731*7485b225SElliott Hughes void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2732*7485b225SElliott Hughes {
2733*7485b225SElliott Hughes     if ( writeBOM ) {
2734*7485b225SElliott Hughes         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2735*7485b225SElliott Hughes         Write( reinterpret_cast< const char* >( bom ) );
2736*7485b225SElliott Hughes     }
2737*7485b225SElliott Hughes     if ( writeDec ) {
2738*7485b225SElliott Hughes         PushDeclaration( "xml version=\"1.0\"" );
2739*7485b225SElliott Hughes     }
2740*7485b225SElliott Hughes }
2741*7485b225SElliott Hughes 
PrepareForNewNode(bool compactMode)2742*7485b225SElliott Hughes void XMLPrinter::PrepareForNewNode( bool compactMode )
2743*7485b225SElliott Hughes {
2744*7485b225SElliott Hughes     SealElementIfJustOpened();
2745*7485b225SElliott Hughes 
2746*7485b225SElliott Hughes     if ( compactMode ) {
2747*7485b225SElliott Hughes         return;
2748*7485b225SElliott Hughes     }
2749*7485b225SElliott Hughes 
2750*7485b225SElliott Hughes     if ( _firstElement ) {
2751*7485b225SElliott Hughes         PrintSpace (_depth);
2752*7485b225SElliott Hughes     } else if ( _textDepth < 0) {
2753*7485b225SElliott Hughes         Putc( '\n' );
2754*7485b225SElliott Hughes         PrintSpace( _depth );
2755*7485b225SElliott Hughes     }
2756*7485b225SElliott Hughes 
2757*7485b225SElliott Hughes     _firstElement = false;
2758*7485b225SElliott Hughes }
2759*7485b225SElliott Hughes 
OpenElement(const char * name,bool compactMode)2760*7485b225SElliott Hughes void XMLPrinter::OpenElement( const char* name, bool compactMode )
2761*7485b225SElliott Hughes {
2762*7485b225SElliott Hughes     PrepareForNewNode( compactMode );
2763*7485b225SElliott Hughes     _stack.Push( name );
2764*7485b225SElliott Hughes 
2765*7485b225SElliott Hughes     Write ( "<" );
2766*7485b225SElliott Hughes     Write ( name );
2767*7485b225SElliott Hughes 
2768*7485b225SElliott Hughes     _elementJustOpened = true;
2769*7485b225SElliott Hughes     ++_depth;
2770*7485b225SElliott Hughes }
2771*7485b225SElliott Hughes 
2772*7485b225SElliott Hughes 
PushAttribute(const char * name,const char * value)2773*7485b225SElliott Hughes void XMLPrinter::PushAttribute( const char* name, const char* value )
2774*7485b225SElliott Hughes {
2775*7485b225SElliott Hughes     TIXMLASSERT( _elementJustOpened );
2776*7485b225SElliott Hughes     Putc ( ' ' );
2777*7485b225SElliott Hughes     Write( name );
2778*7485b225SElliott Hughes     Write( "=\"" );
2779*7485b225SElliott Hughes     PrintString( value, false );
2780*7485b225SElliott Hughes     Putc ( '\"' );
2781*7485b225SElliott Hughes }
2782*7485b225SElliott Hughes 
2783*7485b225SElliott Hughes 
PushAttribute(const char * name,int v)2784*7485b225SElliott Hughes void XMLPrinter::PushAttribute( const char* name, int v )
2785*7485b225SElliott Hughes {
2786*7485b225SElliott Hughes     char buf[BUF_SIZE];
2787*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
2788*7485b225SElliott Hughes     PushAttribute( name, buf );
2789*7485b225SElliott Hughes }
2790*7485b225SElliott Hughes 
2791*7485b225SElliott Hughes 
PushAttribute(const char * name,unsigned v)2792*7485b225SElliott Hughes void XMLPrinter::PushAttribute( const char* name, unsigned v )
2793*7485b225SElliott Hughes {
2794*7485b225SElliott Hughes     char buf[BUF_SIZE];
2795*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
2796*7485b225SElliott Hughes     PushAttribute( name, buf );
2797*7485b225SElliott Hughes }
2798*7485b225SElliott Hughes 
2799*7485b225SElliott Hughes 
PushAttribute(const char * name,int64_t v)2800*7485b225SElliott Hughes void XMLPrinter::PushAttribute(const char* name, int64_t v)
2801*7485b225SElliott Hughes {
2802*7485b225SElliott Hughes 	char buf[BUF_SIZE];
2803*7485b225SElliott Hughes 	XMLUtil::ToStr(v, buf, BUF_SIZE);
2804*7485b225SElliott Hughes 	PushAttribute(name, buf);
2805*7485b225SElliott Hughes }
2806*7485b225SElliott Hughes 
2807*7485b225SElliott Hughes 
PushAttribute(const char * name,uint64_t v)2808*7485b225SElliott Hughes void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2809*7485b225SElliott Hughes {
2810*7485b225SElliott Hughes 	char buf[BUF_SIZE];
2811*7485b225SElliott Hughes 	XMLUtil::ToStr(v, buf, BUF_SIZE);
2812*7485b225SElliott Hughes 	PushAttribute(name, buf);
2813*7485b225SElliott Hughes }
2814*7485b225SElliott Hughes 
2815*7485b225SElliott Hughes 
PushAttribute(const char * name,bool v)2816*7485b225SElliott Hughes void XMLPrinter::PushAttribute( const char* name, bool v )
2817*7485b225SElliott Hughes {
2818*7485b225SElliott Hughes     char buf[BUF_SIZE];
2819*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
2820*7485b225SElliott Hughes     PushAttribute( name, buf );
2821*7485b225SElliott Hughes }
2822*7485b225SElliott Hughes 
2823*7485b225SElliott Hughes 
PushAttribute(const char * name,double v)2824*7485b225SElliott Hughes void XMLPrinter::PushAttribute( const char* name, double v )
2825*7485b225SElliott Hughes {
2826*7485b225SElliott Hughes     char buf[BUF_SIZE];
2827*7485b225SElliott Hughes     XMLUtil::ToStr( v, buf, BUF_SIZE );
2828*7485b225SElliott Hughes     PushAttribute( name, buf );
2829*7485b225SElliott Hughes }
2830*7485b225SElliott Hughes 
2831*7485b225SElliott Hughes 
CloseElement(bool compactMode)2832*7485b225SElliott Hughes void XMLPrinter::CloseElement( bool compactMode )
2833*7485b225SElliott Hughes {
2834*7485b225SElliott Hughes     --_depth;
2835*7485b225SElliott Hughes     const char* name = _stack.Pop();
2836*7485b225SElliott Hughes 
2837*7485b225SElliott Hughes     if ( _elementJustOpened ) {
2838*7485b225SElliott Hughes         Write( "/>" );
2839*7485b225SElliott Hughes     }
2840*7485b225SElliott Hughes     else {
2841*7485b225SElliott Hughes         if ( _textDepth < 0 && !compactMode) {
2842*7485b225SElliott Hughes             Putc( '\n' );
2843*7485b225SElliott Hughes             PrintSpace( _depth );
2844*7485b225SElliott Hughes         }
2845*7485b225SElliott Hughes         Write ( "</" );
2846*7485b225SElliott Hughes         Write ( name );
2847*7485b225SElliott Hughes         Write ( ">" );
2848*7485b225SElliott Hughes     }
2849*7485b225SElliott Hughes 
2850*7485b225SElliott Hughes     if ( _textDepth == _depth ) {
2851*7485b225SElliott Hughes         _textDepth = -1;
2852*7485b225SElliott Hughes     }
2853*7485b225SElliott Hughes     if ( _depth == 0 && !compactMode) {
2854*7485b225SElliott Hughes         Putc( '\n' );
2855*7485b225SElliott Hughes     }
2856*7485b225SElliott Hughes     _elementJustOpened = false;
2857*7485b225SElliott Hughes }
2858*7485b225SElliott Hughes 
2859*7485b225SElliott Hughes 
SealElementIfJustOpened()2860*7485b225SElliott Hughes void XMLPrinter::SealElementIfJustOpened()
2861*7485b225SElliott Hughes {
2862*7485b225SElliott Hughes     if ( !_elementJustOpened ) {
2863*7485b225SElliott Hughes         return;
2864*7485b225SElliott Hughes     }
2865*7485b225SElliott Hughes     _elementJustOpened = false;
2866*7485b225SElliott Hughes     Putc( '>' );
2867*7485b225SElliott Hughes }
2868*7485b225SElliott Hughes 
2869*7485b225SElliott Hughes 
PushText(const char * text,bool cdata)2870*7485b225SElliott Hughes void XMLPrinter::PushText( const char* text, bool cdata )
2871*7485b225SElliott Hughes {
2872*7485b225SElliott Hughes     _textDepth = _depth-1;
2873*7485b225SElliott Hughes 
2874*7485b225SElliott Hughes     SealElementIfJustOpened();
2875*7485b225SElliott Hughes     if ( cdata ) {
2876*7485b225SElliott Hughes         Write( "<![CDATA[" );
2877*7485b225SElliott Hughes         Write( text );
2878*7485b225SElliott Hughes         Write( "]]>" );
2879*7485b225SElliott Hughes     }
2880*7485b225SElliott Hughes     else {
2881*7485b225SElliott Hughes         PrintString( text, true );
2882*7485b225SElliott Hughes     }
2883*7485b225SElliott Hughes }
2884*7485b225SElliott Hughes 
2885*7485b225SElliott Hughes 
PushText(int64_t value)2886*7485b225SElliott Hughes void XMLPrinter::PushText( int64_t value )
2887*7485b225SElliott Hughes {
2888*7485b225SElliott Hughes     char buf[BUF_SIZE];
2889*7485b225SElliott Hughes     XMLUtil::ToStr( value, buf, BUF_SIZE );
2890*7485b225SElliott Hughes     PushText( buf, false );
2891*7485b225SElliott Hughes }
2892*7485b225SElliott Hughes 
2893*7485b225SElliott Hughes 
PushText(uint64_t value)2894*7485b225SElliott Hughes void XMLPrinter::PushText( uint64_t value )
2895*7485b225SElliott Hughes {
2896*7485b225SElliott Hughes 	char buf[BUF_SIZE];
2897*7485b225SElliott Hughes 	XMLUtil::ToStr(value, buf, BUF_SIZE);
2898*7485b225SElliott Hughes 	PushText(buf, false);
2899*7485b225SElliott Hughes }
2900*7485b225SElliott Hughes 
2901*7485b225SElliott Hughes 
PushText(int value)2902*7485b225SElliott Hughes void XMLPrinter::PushText( int value )
2903*7485b225SElliott Hughes {
2904*7485b225SElliott Hughes     char buf[BUF_SIZE];
2905*7485b225SElliott Hughes     XMLUtil::ToStr( value, buf, BUF_SIZE );
2906*7485b225SElliott Hughes     PushText( buf, false );
2907*7485b225SElliott Hughes }
2908*7485b225SElliott Hughes 
2909*7485b225SElliott Hughes 
PushText(unsigned value)2910*7485b225SElliott Hughes void XMLPrinter::PushText( unsigned value )
2911*7485b225SElliott Hughes {
2912*7485b225SElliott Hughes     char buf[BUF_SIZE];
2913*7485b225SElliott Hughes     XMLUtil::ToStr( value, buf, BUF_SIZE );
2914*7485b225SElliott Hughes     PushText( buf, false );
2915*7485b225SElliott Hughes }
2916*7485b225SElliott Hughes 
2917*7485b225SElliott Hughes 
PushText(bool value)2918*7485b225SElliott Hughes void XMLPrinter::PushText( bool value )
2919*7485b225SElliott Hughes {
2920*7485b225SElliott Hughes     char buf[BUF_SIZE];
2921*7485b225SElliott Hughes     XMLUtil::ToStr( value, buf, BUF_SIZE );
2922*7485b225SElliott Hughes     PushText( buf, false );
2923*7485b225SElliott Hughes }
2924*7485b225SElliott Hughes 
2925*7485b225SElliott Hughes 
PushText(float value)2926*7485b225SElliott Hughes void XMLPrinter::PushText( float value )
2927*7485b225SElliott Hughes {
2928*7485b225SElliott Hughes     char buf[BUF_SIZE];
2929*7485b225SElliott Hughes     XMLUtil::ToStr( value, buf, BUF_SIZE );
2930*7485b225SElliott Hughes     PushText( buf, false );
2931*7485b225SElliott Hughes }
2932*7485b225SElliott Hughes 
2933*7485b225SElliott Hughes 
PushText(double value)2934*7485b225SElliott Hughes void XMLPrinter::PushText( double value )
2935*7485b225SElliott Hughes {
2936*7485b225SElliott Hughes     char buf[BUF_SIZE];
2937*7485b225SElliott Hughes     XMLUtil::ToStr( value, buf, BUF_SIZE );
2938*7485b225SElliott Hughes     PushText( buf, false );
2939*7485b225SElliott Hughes }
2940*7485b225SElliott Hughes 
2941*7485b225SElliott Hughes 
PushComment(const char * comment)2942*7485b225SElliott Hughes void XMLPrinter::PushComment( const char* comment )
2943*7485b225SElliott Hughes {
2944*7485b225SElliott Hughes     PrepareForNewNode( _compactMode );
2945*7485b225SElliott Hughes 
2946*7485b225SElliott Hughes     Write( "<!--" );
2947*7485b225SElliott Hughes     Write( comment );
2948*7485b225SElliott Hughes     Write( "-->" );
2949*7485b225SElliott Hughes }
2950*7485b225SElliott Hughes 
2951*7485b225SElliott Hughes 
PushDeclaration(const char * value)2952*7485b225SElliott Hughes void XMLPrinter::PushDeclaration( const char* value )
2953*7485b225SElliott Hughes {
2954*7485b225SElliott Hughes     PrepareForNewNode( _compactMode );
2955*7485b225SElliott Hughes 
2956*7485b225SElliott Hughes     Write( "<?" );
2957*7485b225SElliott Hughes     Write( value );
2958*7485b225SElliott Hughes     Write( "?>" );
2959*7485b225SElliott Hughes }
2960*7485b225SElliott Hughes 
2961*7485b225SElliott Hughes 
PushUnknown(const char * value)2962*7485b225SElliott Hughes void XMLPrinter::PushUnknown( const char* value )
2963*7485b225SElliott Hughes {
2964*7485b225SElliott Hughes     PrepareForNewNode( _compactMode );
2965*7485b225SElliott Hughes 
2966*7485b225SElliott Hughes     Write( "<!" );
2967*7485b225SElliott Hughes     Write( value );
2968*7485b225SElliott Hughes     Putc( '>' );
2969*7485b225SElliott Hughes }
2970*7485b225SElliott Hughes 
2971*7485b225SElliott Hughes 
VisitEnter(const XMLDocument & doc)2972*7485b225SElliott Hughes bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2973*7485b225SElliott Hughes {
2974*7485b225SElliott Hughes     _processEntities = doc.ProcessEntities();
2975*7485b225SElliott Hughes     if ( doc.HasBOM() ) {
2976*7485b225SElliott Hughes         PushHeader( true, false );
2977*7485b225SElliott Hughes     }
2978*7485b225SElliott Hughes     return true;
2979*7485b225SElliott Hughes }
2980*7485b225SElliott Hughes 
2981*7485b225SElliott Hughes 
VisitEnter(const XMLElement & element,const XMLAttribute * attribute)2982*7485b225SElliott Hughes bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2983*7485b225SElliott Hughes {
2984*7485b225SElliott Hughes     const XMLElement* parentElem = 0;
2985*7485b225SElliott Hughes     if ( element.Parent() ) {
2986*7485b225SElliott Hughes         parentElem = element.Parent()->ToElement();
2987*7485b225SElliott Hughes     }
2988*7485b225SElliott Hughes     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2989*7485b225SElliott Hughes     OpenElement( element.Name(), compactMode );
2990*7485b225SElliott Hughes     while ( attribute ) {
2991*7485b225SElliott Hughes         PushAttribute( attribute->Name(), attribute->Value() );
2992*7485b225SElliott Hughes         attribute = attribute->Next();
2993*7485b225SElliott Hughes     }
2994*7485b225SElliott Hughes     return true;
2995*7485b225SElliott Hughes }
2996*7485b225SElliott Hughes 
2997*7485b225SElliott Hughes 
VisitExit(const XMLElement & element)2998*7485b225SElliott Hughes bool XMLPrinter::VisitExit( const XMLElement& element )
2999*7485b225SElliott Hughes {
3000*7485b225SElliott Hughes     CloseElement( CompactMode(element) );
3001*7485b225SElliott Hughes     return true;
3002*7485b225SElliott Hughes }
3003*7485b225SElliott Hughes 
3004*7485b225SElliott Hughes 
Visit(const XMLText & text)3005*7485b225SElliott Hughes bool XMLPrinter::Visit( const XMLText& text )
3006*7485b225SElliott Hughes {
3007*7485b225SElliott Hughes     PushText( text.Value(), text.CData() );
3008*7485b225SElliott Hughes     return true;
3009*7485b225SElliott Hughes }
3010*7485b225SElliott Hughes 
3011*7485b225SElliott Hughes 
Visit(const XMLComment & comment)3012*7485b225SElliott Hughes bool XMLPrinter::Visit( const XMLComment& comment )
3013*7485b225SElliott Hughes {
3014*7485b225SElliott Hughes     PushComment( comment.Value() );
3015*7485b225SElliott Hughes     return true;
3016*7485b225SElliott Hughes }
3017*7485b225SElliott Hughes 
Visit(const XMLDeclaration & declaration)3018*7485b225SElliott Hughes bool XMLPrinter::Visit( const XMLDeclaration& declaration )
3019*7485b225SElliott Hughes {
3020*7485b225SElliott Hughes     PushDeclaration( declaration.Value() );
3021*7485b225SElliott Hughes     return true;
3022*7485b225SElliott Hughes }
3023*7485b225SElliott Hughes 
3024*7485b225SElliott Hughes 
Visit(const XMLUnknown & unknown)3025*7485b225SElliott Hughes bool XMLPrinter::Visit( const XMLUnknown& unknown )
3026*7485b225SElliott Hughes {
3027*7485b225SElliott Hughes     PushUnknown( unknown.Value() );
3028*7485b225SElliott Hughes     return true;
3029*7485b225SElliott Hughes }
3030*7485b225SElliott Hughes 
3031*7485b225SElliott Hughes }   // namespace tinyxml2
3032