Upgrade to tinyxml2 6.0.0 (2017-12-11)

Bug: http://b/64459264
Test: builds, boots

(cherry picked from commit 934754db26de0bbad010fc663279b5019521b738)

Change-Id: I476b4ef566a6eb3a0877b943fe1e7d8c26c9b305
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 1972e1c..04cf697 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -20,46 +20,104 @@
 3. This notice may not be removed or altered from any source

 distribution.

 */

+

 #include "tinyxml2.h"

 

-#include <cstdio>

-#include <cstdlib>

-#include <new>

-#include <cstddef>

+#include <new>		// yes, this one new style header, is in the Android SDK.

+#if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)

+#   include <stddef.h>

+#   include <stdarg.h>

+#else

+#   include <cstddef>

+#   include <cstdarg>

+#endif

 

-#include <fcntl.h>

-using namespace tinyxml2;

+#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)

+	// Microsoft Visual Studio, version 2005 and higher. Not WinCE.

+	/*int _snprintf_s(

+	   char *buffer,

+	   size_t sizeOfBuffer,

+	   size_t count,

+	   const char *format [,

+		  argument] ...

+	);*/

+	static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )

+	{

+		va_list va;

+		va_start( va, format );

+		int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );

+		va_end( va );

+		return result;

+	}

 

-static const char LINE_FEED                = (char)0x0a;            // all line endings are normalized to LF

+	static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )

+	{

+		int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );

+		return result;

+	}

+

+	#define TIXML_VSCPRINTF	_vscprintf

+	#define TIXML_SSCANF	sscanf_s

+#elif defined _MSC_VER

+	// Microsoft Visual Studio 2003 and earlier or WinCE

+	#define TIXML_SNPRINTF	_snprintf

+	#define TIXML_VSNPRINTF _vsnprintf

+	#define TIXML_SSCANF	sscanf

+	#if (_MSC_VER < 1400 ) && (!defined WINCE)

+		// Microsoft Visual Studio 2003 and not WinCE.

+		#define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.

+	#else

+		// Microsoft Visual Studio 2003 and earlier or WinCE.

+		static inline int TIXML_VSCPRINTF( const char* format, va_list va )

+		{

+			int len = 512;

+			for (;;) {

+				len = len*2;

+				char* str = new char[len]();

+				const int required = _vsnprintf(str, len, format, va);

+				delete[] str;

+				if ( required != -1 ) {

+					TIXMLASSERT( required >= 0 );

+					len = required;

+					break;

+				}

+			}

+			TIXMLASSERT( len >= 0 );

+			return len;

+		}

+	#endif

+#else

+	// GCC version 3 and higher

+	//#warning( "Using sn* functions." )

+	#define TIXML_SNPRINTF	snprintf

+	#define TIXML_VSNPRINTF	vsnprintf

+	static inline int TIXML_VSCPRINTF( const char* format, va_list va )

+	{

+		int len = vsnprintf( 0, 0, format, va );

+		TIXMLASSERT( len >= 0 );

+		return len;

+	}

+	#define TIXML_SSCANF   sscanf

+#endif

+

+

+static const char LINE_FEED				= (char)0x0a;			// all line endings are normalized to LF

 static const char LF = LINE_FEED;

-static const char CARRIAGE_RETURN        = (char)0x0d;            // CR gets filtered out

+static const char CARRIAGE_RETURN		= (char)0x0d;			// CR gets filtered out

 static const char CR = CARRIAGE_RETURN;

-static const char SINGLE_QUOTE            = '\'';

-static const char DOUBLE_QUOTE            = '\"';

+static const char SINGLE_QUOTE			= '\'';

+static const char DOUBLE_QUOTE			= '\"';

 

 // Bunch of unicode info at:

-//        http://www.unicode.org/faq/utf_bom.html

-//    ef bb bf (Microsoft "lead bytes") - designates UTF-8

+//		http://www.unicode.org/faq/utf_bom.html

+//	ef bb bf (Microsoft "lead bytes") - designates UTF-8

 

 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;

 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;

 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;

 

-

-#define DELETE_NODE( node )    {            \

-    if ( node ) {                        \

-        MemPool* pool = node->memPool;    \

-        node->~XMLNode();                \

-        pool->Free( node );                \

-    }                                    \

-}

-#define DELETE_ATTRIBUTE( attrib ) {        \

-    if ( attrib ) {                            \

-        MemPool* pool = attrib->memPool;    \

-        attrib->~XMLAttribute();            \

-        pool->Free( attrib );                \

-    }                                        \

-}

+namespace tinyxml2

+{

 

 struct Entity {

     const char* pattern;

@@ -68,13 +126,12 @@
 };

 

 static const int NUM_ENTITIES = 5;

-static const Entity entities[NUM_ENTITIES] =

-{

-    { "quot", 4,    DOUBLE_QUOTE },

-    { "amp", 3,        '&'  },

-    { "apos", 4,    SINGLE_QUOTE },

-    { "lt",    2,         '<'     },

-    { "gt",    2,        '>'     }

+static const Entity entities[NUM_ENTITIES] = {

+    { "quot", 4,	DOUBLE_QUOTE },

+    { "amp", 3,		'&'  },

+    { "apos", 4,	SINGLE_QUOTE },

+    { "lt",	2, 		'<'	 },

+    { "gt",	2,		'>'	 }

 };

 

 

@@ -84,33 +141,62 @@
 }

 

 

+void StrPair::TransferTo( StrPair* other )

+{

+    if ( this == other ) {

+        return;

+    }

+    // This in effect implements the assignment operator by "moving"

+    // ownership (as in auto_ptr).

+

+    TIXMLASSERT( other != 0 );

+    TIXMLASSERT( other->_flags == 0 );

+    TIXMLASSERT( other->_start == 0 );

+    TIXMLASSERT( other->_end == 0 );

+

+    other->Reset();

+

+    other->_flags = _flags;

+    other->_start = _start;

+    other->_end = _end;

+

+    _flags = 0;

+    _start = 0;

+    _end = 0;

+}

+

+

 void StrPair::Reset()

 {

-    if ( flags & NEEDS_DELETE ) {

-        delete [] start;

+    if ( _flags & NEEDS_DELETE ) {

+        delete [] _start;

     }

-    flags = 0;

-    start = 0;

-    end = 0;

+    _flags = 0;

+    _start = 0;

+    _end = 0;

 }

 

 

 void StrPair::SetStr( const char* str, int flags )

 {

+    TIXMLASSERT( str );

     Reset();

     size_t len = strlen( str );

-    start = new char[ len+1 ];

-    memcpy( start, str, len+1 );

-    end = start + len;

-    this->flags = flags | NEEDS_DELETE;

+    TIXMLASSERT( _start == 0 );

+    _start = new char[ len+1 ];

+    memcpy( _start, str, len+1 );

+    _end = _start + len;

+    _flags = flags | NEEDS_DELETE;

 }

 

 

-char* StrPair::ParseText( char* p, const char* endTag, int strFlags )

+char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )

 {

+    TIXMLASSERT( p );

     TIXMLASSERT( endTag && *endTag );

+	TIXMLASSERT(curLineNumPtr);

 

-    char* start = p;    // fixme: hides a member

+    char* start = p;

     char  endChar = *endTag;

     size_t length = strlen( endTag );

 

@@ -119,8 +205,11 @@
         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {

             Set( start, p, strFlags );

             return p + length;

+        } else if (*p == '\n') {

+            ++(*curLineNumPtr);

         }

         ++p;

+        TIXMLASSERT( p );

     }

     return 0;

 }

@@ -128,47 +217,67 @@
 

 char* StrPair::ParseName( char* p )

 {

-    char* start = p;

-

-    if ( !start || !(*start) ) {

+    if ( !p || !(*p) ) {

+        return 0;

+    }

+    if ( !XMLUtil::IsNameStartChar( *p ) ) {

         return 0;

     }

 

-    if ( !XMLUtil::IsAlpha( *p ) ) {

-        return 0;

-    }

-

-    while( *p && (

-               XMLUtil::IsAlphaNum( (unsigned char) *p )

-            || *p == '_'

-            || *p == '-'

-            || *p == '.'

-            || *p == ':' ))

-    {

+    char* const start = p;

+    ++p;

+    while ( *p && XMLUtil::IsNameChar( *p ) ) {

         ++p;

     }

 

-    if ( p > start ) {

-        Set( start, p, 0 );

-        return p;

-    }

-    return 0;

+    Set( start, p, 0 );

+    return p;

 }

 

 

+void StrPair::CollapseWhitespace()

+{

+    // Adjusting _start would cause undefined behavior on delete[]

+    TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );

+    // Trim leading space.

+    _start = XMLUtil::SkipWhiteSpace( _start, 0 );

+

+    if ( *_start ) {

+        const char* p = _start;	// the read pointer

+        char* q = _start;	// the write pointer

+

+        while( *p ) {

+            if ( XMLUtil::IsWhiteSpace( *p )) {

+                p = XMLUtil::SkipWhiteSpace( p, 0 );

+                if ( *p == 0 ) {

+                    break;    // don't write to q; this trims the trailing space.

+                }

+                *q = ' ';

+                ++q;

+            }

+            *q = *p;

+            ++q;

+            ++p;

+        }

+        *q = 0;

+    }

+}

+

 

 const char* StrPair::GetStr()

 {

-    if ( flags & NEEDS_FLUSH ) {

-        *end = 0;

-        flags ^= NEEDS_FLUSH;

+    TIXMLASSERT( _start );

+    TIXMLASSERT( _end );

+    if ( _flags & NEEDS_FLUSH ) {

+        *_end = 0;

+        _flags ^= NEEDS_FLUSH;

 

-        if ( flags ) {

-            char* p = start;    // the read pointer

-            char* q = start;    // the write pointer

+        if ( _flags ) {

+            const char* p = _start;	// the read pointer

+            char* q = _start;	// the write pointer

 

-            while( p < end ) {

-                if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {

+            while( p < _end ) {

+                if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {

                     // CR-LF pair becomes LF

                     // CR alone becomes LF

                     // LF-CR becomes LF

@@ -178,46 +287,58 @@
                     else {

                         ++p;

                     }

-                    *q++ = LF;

+                    *q = LF;

+                    ++q;

                 }

-                else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {

+                else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {

                     if ( *(p+1) == CR ) {

                         p += 2;

                     }

                     else {

                         ++p;

                     }

-                    *q++ = LF;

+                    *q = LF;

+                    ++q;

                 }

-                else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {

+                else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {

                     // Entities handled by tinyXML2:

                     // - special entities in the entity table [in/out]

                     // - numeric character reference [in]

                     //   &#20013; or &#x4e2d;

 

                     if ( *(p+1) == '#' ) {

-                        char buf[10] = { 0 };

-                        int len;

-                        p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );

-                        for( int i=0; i<len; ++i ) {

-                            *q++ = buf[i];

+                        const int buflen = 10;

+                        char buf[buflen] = { 0 };

+                        int len = 0;

+                        char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );

+                        if ( adjusted == 0 ) {

+                            *q = *p;

+                            ++p;

+                            ++q;

                         }

-                        TIXMLASSERT( q <= p );

+                        else {

+                            TIXMLASSERT( 0 <= len && len <= buflen );

+                            TIXMLASSERT( q + len <= adjusted );

+                            p = adjusted;

+                            memcpy( q, buf, len );

+                            q += len;

+                        }

                     }

                     else {

-                        int i=0;

-                        for(; i<NUM_ENTITIES; ++i ) {

-                            if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0

-                                 && *(p+entities[i].length+1) == ';' )

-                            {

-                                // Found an entity convert;

-                                *q = entities[i].value;

+                        bool entityFound = false;

+                        for( int i = 0; i < NUM_ENTITIES; ++i ) {

+                            const Entity& entity = entities[i];

+                            if ( strncmp( p + 1, entity.pattern, entity.length ) == 0

+                                    && *( p + entity.length + 1 ) == ';' ) {

+                                // Found an entity - convert.

+                                *q = entity.value;

                                 ++q;

-                                p += entities[i].length + 2;

+                                p += entity.length + 2;

+                                entityFound = true;

                                 break;

                             }

                         }

-                        if ( i == NUM_ENTITIES ) {

+                        if ( !entityFound ) {

                             // fixme: treat as error?

                             ++p;

                             ++q;

@@ -232,9 +353,15 @@
             }

             *q = 0;

         }

-        flags = (flags & NEEDS_DELETE);

+        // The loop below has plenty going on, and this

+        // is a less useful mode. Break it out.

+        if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {

+            CollapseWhitespace();

+        }

+        _flags = (_flags & NEEDS_DELETE);

     }

-    return start;

+    TIXMLASSERT( _start );

+    return _start;

 }

 

 

@@ -242,18 +369,33 @@
 

 // --------- XMLUtil ----------- //

 

+const char* XMLUtil::writeBoolTrue  = "true";

+const char* XMLUtil::writeBoolFalse = "false";

+

+void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)

+{

+	static const char* defTrue  = "true";

+	static const char* defFalse = "false";

+

+	writeBoolTrue = (writeTrue) ? writeTrue : defTrue;

+	writeBoolFalse = (writeFalse) ? writeFalse : defFalse;

+}

+

+

 const char* XMLUtil::ReadBOM( const char* p, bool* bom )

 {

+    TIXMLASSERT( p );

+    TIXMLASSERT( bom );

     *bom = false;

     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);

     // Check for BOM:

     if (    *(pu+0) == TIXML_UTF_LEAD_0

-         && *(pu+1) == TIXML_UTF_LEAD_1

-         && *(pu+2) == TIXML_UTF_LEAD_2 )

-    {

+            && *(pu+1) == TIXML_UTF_LEAD_1

+            && *(pu+2) == TIXML_UTF_LEAD_2 ) {

         *bom = true;

         p += 3;

     }

+    TIXMLASSERT( p );

     return p;

 }

 

@@ -264,37 +406,49 @@
     const unsigned long BYTE_MARK = 0x80;

     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };

 

-    if (input < 0x80)

+    if (input < 0x80) {

         *length = 1;

-    else if ( input < 0x800 )

+    }

+    else if ( input < 0x800 ) {

         *length = 2;

-    else if ( input < 0x10000 )

+    }

+    else if ( input < 0x10000 ) {

         *length = 3;

-    else if ( input < 0x200000 )

+    }

+    else if ( input < 0x200000 ) {

         *length = 4;

-    else

-        { *length = 0; return; }    // This code won't covert this correctly anyway.

+    }

+    else {

+        *length = 0;    // This code won't convert this correctly anyway.

+        return;

+    }

 

     output += *length;

 

-    // Scary scary fall throughs.

-    switch (*length)

-    {

+    // Scary scary fall throughs are annotated with carefully designed comments

+    // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc

+    switch (*length) {

         case 4:

             --output;

             *output = (char)((input | BYTE_MARK) & BYTE_MASK);

             input >>= 6;

+            //fall through

         case 3:

             --output;

             *output = (char)((input | BYTE_MARK) & BYTE_MASK);

             input >>= 6;

+            //fall through

         case 2:

             --output;

             *output = (char)((input | BYTE_MARK) & BYTE_MASK);

             input >>= 6;

+            //fall through

         case 1:

             --output;

             *output = (char)(input | FIRST_BYTE_MARK[*length]);

+            break;

+        default:

+            TIXMLASSERT( false );

     }

 }

 

@@ -304,58 +458,85 @@
     // Presume an entity, and pull it out.

     *length = 0;

 

-    if ( *(p+1) == '#' && *(p+2) )

-    {

+    if ( *(p+1) == '#' && *(p+2) ) {

         unsigned long ucs = 0;

+        TIXMLASSERT( sizeof( ucs ) >= 4 );

         ptrdiff_t delta = 0;

         unsigned mult = 1;

+        static const char SEMICOLON = ';';

 

-        if ( *(p+2) == 'x' )

-        {

+        if ( *(p+2) == 'x' ) {

             // Hexadecimal.

-            if ( !*(p+3) ) return 0;

-

             const char* q = p+3;

-            q = strchr( q, ';' );

+            if ( !(*q) ) {

+                return 0;

+            }

 

-            if ( !q || !*q ) return 0;

+            q = strchr( q, SEMICOLON );

+

+            if ( !q ) {

+                return 0;

+            }

+            TIXMLASSERT( *q == SEMICOLON );

 

             delta = q-p;

             --q;

 

-            while ( *q != 'x' )

-            {

-                if ( *q >= '0' && *q <= '9' )

-                    ucs += mult * (*q - '0');

-                else if ( *q >= 'a' && *q <= 'f' )

-                    ucs += mult * (*q - 'a' + 10);

-                else if ( *q >= 'A' && *q <= 'F' )

-                    ucs += mult * (*q - 'A' + 10 );

-                else

+            while ( *q != 'x' ) {

+                unsigned int digit = 0;

+

+                if ( *q >= '0' && *q <= '9' ) {

+                    digit = *q - '0';

+                }

+                else if ( *q >= 'a' && *q <= 'f' ) {

+                    digit = *q - 'a' + 10;

+                }

+                else if ( *q >= 'A' && *q <= 'F' ) {

+                    digit = *q - 'A' + 10;

+                }

+                else {

                     return 0;

+                }

+                TIXMLASSERT( digit < 16 );

+                TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );

+                const unsigned int digitScaled = mult * digit;

+                TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );

+                ucs += digitScaled;

+                TIXMLASSERT( mult <= UINT_MAX / 16 );

                 mult *= 16;

                 --q;

             }

         }

-        else

-        {

+        else {

             // Decimal.

-            if ( !*(p+2) ) return 0;

-

             const char* q = p+2;

-            q = strchr( q, ';' );

+            if ( !(*q) ) {

+                return 0;

+            }

 

-            if ( !q || !*q ) return 0;

+            q = strchr( q, SEMICOLON );

+

+            if ( !q ) {

+                return 0;

+            }

+            TIXMLASSERT( *q == SEMICOLON );

 

             delta = q-p;

             --q;

 

-            while ( *q != '#' )

-            {

-                if ( *q >= '0' && *q <= '9' )

-                    ucs += mult * (*q - '0');

-                else

+            while ( *q != '#' ) {

+                if ( *q >= '0' && *q <= '9' ) {

+                    const unsigned int digit = *q - '0';

+                    TIXMLASSERT( digit < 10 );

+                    TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );

+                    const unsigned int digitScaled = mult * digit;

+                    TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );

+                    ucs += digitScaled;

+                }

+                else {

                     return 0;

+                }

+                TIXMLASSERT( mult <= UINT_MAX / 10 );

                 mult *= 10;

                 --q;

             }

@@ -382,33 +563,45 @@
 

 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )

 {

-    TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );

+    TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);

 }

 

-

+/*

+	ToStr() of a number is a very tricky topic.

+	https://github.com/leethomason/tinyxml2/issues/106

+*/

 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )

 {

-    TIXML_SNPRINTF( buffer, bufferSize, "%f", v );

+    TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );

 }

 

 

 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )

 {

-    TIXML_SNPRINTF( buffer, bufferSize, "%f", v );

+    TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );

+}

+

+

+void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)

+{

+	// horrible syntax trick to make the compiler happy about %lld

+	TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);

 }

 

 

 bool XMLUtil::ToInt( const char* str, int* value )

 {

-    if ( TIXML_SSCANF( str, "%d", value ) == 1 )

+    if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {

         return true;

+    }

     return false;

 }

 

 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )

 {

-    if ( TIXML_SSCANF( str, "%u", value ) == 1 )

+    if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {

         return true;

+    }

     return false;

 }

 

@@ -439,6 +632,7 @@
     return false;

 }

 

+

 bool XMLUtil::ToDouble( const char* str, double* value )

 {

     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {

@@ -448,77 +642,82 @@
 }

 

 

+bool XMLUtil::ToInt64(const char* str, int64_t* value)

+{

+	long long v = 0;	// horrible syntax trick to make the compiler happy about %lld

+	if (TIXML_SSCANF(str, "%lld", &v) == 1) {

+		*value = (int64_t)v;

+		return true;

+	}

+	return false;

+}

+

+

 char* XMLDocument::Identify( char* p, XMLNode** node )

 {

-    XMLNode* returnNode = 0;

-    char* start = p;

-    p = XMLUtil::SkipWhiteSpace( p );

-    if( !p || !*p )

-    {

+    TIXMLASSERT( node );

+    TIXMLASSERT( p );

+    char* const start = p;

+    int const startLine = _parseCurLineNum;

+    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );

+    if( !*p ) {

+        *node = 0;

+        TIXMLASSERT( p );

         return p;

     }

 

-    // What is this thing?

-    // - Elements start with a letter or underscore, but xml is reserved.

-    // - Comments: <!--

-    // - Decleration: <?

-    // - Everthing else is unknown to tinyxml.

-    //

+    // These strings define the matching patterns:

+    static const char* xmlHeader		= { "<?" };

+    static const char* commentHeader	= { "<!--" };

+    static const char* cdataHeader		= { "<![CDATA[" };

+    static const char* dtdHeader		= { "<!" };

+    static const char* elementHeader	= { "<" };	// and a header for everything else; check last.

 

-    static const char* xmlHeader        = { "<?" };

-    static const char* commentHeader    = { "<!--" };

-    static const char* dtdHeader        = { "<!" };

-    static const char* cdataHeader        = { "<![CDATA[" };

-    static const char* elementHeader    = { "<" };    // and a header for everything else; check last.

+    static const int xmlHeaderLen		= 2;

+    static const int commentHeaderLen	= 4;

+    static const int cdataHeaderLen		= 9;

+    static const int dtdHeaderLen		= 2;

+    static const int elementHeaderLen	= 1;

 

-    static const int xmlHeaderLen        = 2;

-    static const int commentHeaderLen    = 4;

-    static const int dtdHeaderLen        = 2;

-    static const int cdataHeaderLen        = 9;

-    static const int elementHeaderLen    = 1;

-

-#if defined(_MSC_VER)

-#pragma warning ( push )

-#pragma warning ( disable : 4127 )

-#endif

-    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );        // use same memory pool

-    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool

-#if defined(_MSC_VER)

-#pragma warning (pop)

-#endif

+    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool

+    TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool

+    XMLNode* returnNode = 0;

     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {

-        returnNode = new (commentPool.Alloc()) XMLDeclaration( this );

-        returnNode->memPool = &commentPool;

+        returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );

+        returnNode->_parseLineNum = _parseCurLineNum;

         p += xmlHeaderLen;

     }

     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {

-        returnNode = new (commentPool.Alloc()) XMLComment( this );

-        returnNode->memPool = &commentPool;

+        returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );

+        returnNode->_parseLineNum = _parseCurLineNum;

         p += commentHeaderLen;

     }

     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {

-        XMLText* text = new (textPool.Alloc()) XMLText( this );

+        XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );

         returnNode = text;

-        returnNode->memPool = &textPool;

+        returnNode->_parseLineNum = _parseCurLineNum;

         p += cdataHeaderLen;

         text->SetCData( true );

     }

     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {

-        returnNode = new (commentPool.Alloc()) XMLUnknown( this );

-        returnNode->memPool = &commentPool;

+        returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );

+        returnNode->_parseLineNum = _parseCurLineNum;

         p += dtdHeaderLen;

     }

     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {

-        returnNode = new (elementPool.Alloc()) XMLElement( this );

-        returnNode->memPool = &elementPool;

+        returnNode =  CreateUnlinkedNode<XMLElement>( _elementPool );

+        returnNode->_parseLineNum = _parseCurLineNum;

         p += elementHeaderLen;

     }

     else {

-        returnNode = new (textPool.Alloc()) XMLText( this );

-        returnNode->memPool = &textPool;

-        p = start;    // Back it up, all the text counts.

+        returnNode = CreateUnlinkedNode<XMLText>( _textPool );

+        returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character

+        p = start;	// Back it up, all the text counts.

+        _parseCurLineNum = startLine;

     }

 

+    TIXMLASSERT( returnNode );

+    TIXMLASSERT( p );

     *node = returnNode;

     return p;

 }

@@ -526,12 +725,12 @@
 

 bool XMLDocument::Accept( XMLVisitor* visitor ) const

 {

-    if ( visitor->VisitEnter( *this ) )

-    {

-        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )

-        {

-            if ( !node->Accept( visitor ) )

+    TIXMLASSERT( visitor );

+    if ( visitor->VisitEnter( *this ) ) {

+        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {

+            if ( !node->Accept( visitor ) ) {

                 break;

+            }

         }

     }

     return visitor->VisitExit( *this );

@@ -541,10 +740,14 @@
 // --------- XMLNode ----------- //

 

 XMLNode::XMLNode( XMLDocument* doc ) :

-    document( doc ),

-    parent( 0 ),

-    firstChild( 0 ), lastChild( 0 ),

-    prev( 0 ), next( 0 )

+    _document( doc ),

+    _parent( 0 ),

+    _value(),

+    _parseLineNum( 0 ),

+    _firstChild( 0 ), _lastChild( 0 ),

+    _prev( 0 ), _next( 0 ),

+	_userData( 0 ),

+    _memPool( 0 )

 {

 }

 

@@ -552,191 +755,247 @@
 XMLNode::~XMLNode()

 {

     DeleteChildren();

-    if ( parent ) {

-        parent->Unlink( this );

+    if ( _parent ) {

+        _parent->Unlink( this );

     }

 }

 

+const char* XMLNode::Value() const 

+{

+    // Edge case: XMLDocuments don't have a Value. Return null.

+    if ( this->ToDocument() )

+        return 0;

+    return _value.GetStr();

+}

 

 void XMLNode::SetValue( const char* str, bool staticMem )

 {

-    if ( staticMem )

-        value.SetInternedStr( str );

-    else

-        value.SetStr( str );

+    if ( staticMem ) {

+        _value.SetInternedStr( str );

+    }

+    else {

+        _value.SetStr( str );

+    }

 }

 

+XMLNode* XMLNode::DeepClone(XMLDocument* target) const

+{

+	XMLNode* clone = this->ShallowClone(target);

+	if (!clone) return 0;

+

+	for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {

+		XMLNode* childClone = child->DeepClone(target);

+		TIXMLASSERT(childClone);

+		clone->InsertEndChild(childClone);

+	}

+	return clone;

+}

 

 void XMLNode::DeleteChildren()

 {

-    while( firstChild ) {

-        XMLNode* node = firstChild;

-        Unlink( node );

-

-        DELETE_NODE( node );

+    while( _firstChild ) {

+        TIXMLASSERT( _lastChild );

+        DeleteChild( _firstChild );

     }

-    firstChild = lastChild = 0;

+    _firstChild = _lastChild = 0;

 }

 

 

 void XMLNode::Unlink( XMLNode* child )

 {

-    TIXMLASSERT( child->parent == this );

-    if ( child == firstChild )

-        firstChild = firstChild->next;

-    if ( child == lastChild )

-        lastChild = lastChild->prev;

+    TIXMLASSERT( child );

+    TIXMLASSERT( child->_document == _document );

+    TIXMLASSERT( child->_parent == this );

+    if ( child == _firstChild ) {

+        _firstChild = _firstChild->_next;

+    }

+    if ( child == _lastChild ) {

+        _lastChild = _lastChild->_prev;

+    }

 

-    if ( child->prev ) {

-        child->prev->next = child->next;

+    if ( child->_prev ) {

+        child->_prev->_next = child->_next;

     }

-    if ( child->next ) {

-        child->next->prev = child->prev;

+    if ( child->_next ) {

+        child->_next->_prev = child->_prev;

     }

-    child->parent = 0;

+	child->_next = 0;

+	child->_prev = 0;

+	child->_parent = 0;

 }

 

 

 void XMLNode::DeleteChild( XMLNode* node )

 {

-    TIXMLASSERT( node->parent == this );

-    DELETE_NODE( node );

+    TIXMLASSERT( node );

+    TIXMLASSERT( node->_document == _document );

+    TIXMLASSERT( node->_parent == this );

+    Unlink( node );

+	TIXMLASSERT(node->_prev == 0);

+	TIXMLASSERT(node->_next == 0);

+	TIXMLASSERT(node->_parent == 0);

+    DeleteNode( node );

 }

 

 

 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )

 {

-    if ( lastChild ) {

-        TIXMLASSERT( firstChild );

-        TIXMLASSERT( lastChild->next == 0 );

-        lastChild->next = addThis;

-        addThis->prev = lastChild;

-        lastChild = addThis;

+    TIXMLASSERT( addThis );

+    if ( addThis->_document != _document ) {

+        TIXMLASSERT( false );

+        return 0;

+    }

+    InsertChildPreamble( addThis );

 

-        addThis->next = 0;

+    if ( _lastChild ) {

+        TIXMLASSERT( _firstChild );

+        TIXMLASSERT( _lastChild->_next == 0 );

+        _lastChild->_next = addThis;

+        addThis->_prev = _lastChild;

+        _lastChild = addThis;

+

+        addThis->_next = 0;

     }

     else {

-        TIXMLASSERT( firstChild == 0 );

-        firstChild = lastChild = addThis;

+        TIXMLASSERT( _firstChild == 0 );

+        _firstChild = _lastChild = addThis;

 

-        addThis->prev = 0;

-        addThis->next = 0;

+        addThis->_prev = 0;

+        addThis->_next = 0;

     }

-    addThis->parent = this;

+    addThis->_parent = this;

     return addThis;

 }

 

 

 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )

 {

-    if ( firstChild ) {

-        TIXMLASSERT( lastChild );

-        TIXMLASSERT( firstChild->prev == 0 );

+    TIXMLASSERT( addThis );

+    if ( addThis->_document != _document ) {

+        TIXMLASSERT( false );

+        return 0;

+    }

+    InsertChildPreamble( addThis );

 

-        firstChild->prev = addThis;

-        addThis->next = firstChild;

-        firstChild = addThis;

+    if ( _firstChild ) {

+        TIXMLASSERT( _lastChild );

+        TIXMLASSERT( _firstChild->_prev == 0 );

 

-        addThis->prev = 0;

+        _firstChild->_prev = addThis;

+        addThis->_next = _firstChild;

+        _firstChild = addThis;

+

+        addThis->_prev = 0;

     }

     else {

-        TIXMLASSERT( lastChild == 0 );

-        firstChild = lastChild = addThis;

+        TIXMLASSERT( _lastChild == 0 );

+        _firstChild = _lastChild = addThis;

 

-        addThis->prev = 0;

-        addThis->next = 0;

+        addThis->_prev = 0;

+        addThis->_next = 0;

     }

-    addThis->parent = this;

+    addThis->_parent = this;

     return addThis;

 }

 

 

 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )

 {

-    TIXMLASSERT( afterThis->parent == this );

-    if ( afterThis->parent != this )

+    TIXMLASSERT( addThis );

+    if ( addThis->_document != _document ) {

+        TIXMLASSERT( false );

         return 0;

+    }

 

-    if ( afterThis->next == 0 ) {

+    TIXMLASSERT( afterThis );

+

+    if ( afterThis->_parent != this ) {

+        TIXMLASSERT( false );

+        return 0;

+    }

+    if ( afterThis == addThis ) {

+        // Current state: BeforeThis -> AddThis -> OneAfterAddThis

+        // Now AddThis must disappear from it's location and then

+        // reappear between BeforeThis and OneAfterAddThis.

+        // So just leave it where it is.

+        return addThis;

+    }

+

+    if ( afterThis->_next == 0 ) {

         // The last node or the only node.

         return InsertEndChild( addThis );

     }

-    addThis->prev = afterThis;

-    addThis->next = afterThis->next;

-    afterThis->next->prev = addThis;

-    afterThis->next = addThis;

-    addThis->parent = this;

+    InsertChildPreamble( addThis );

+    addThis->_prev = afterThis;

+    addThis->_next = afterThis->_next;

+    afterThis->_next->_prev = addThis;

+    afterThis->_next = addThis;

+    addThis->_parent = this;

     return addThis;

 }

 

 

 

 

-const XMLElement* XMLNode::FirstChildElement( const char* value ) const

+const XMLElement* XMLNode::FirstChildElement( const char* name ) const

 {

-    for( XMLNode* node=firstChild; node; node=node->next ) {

-        XMLElement* element = node->ToElement();

+    for( const XMLNode* node = _firstChild; node; node = node->_next ) {

+        const XMLElement* element = node->ToElementWithName( name );

         if ( element ) {

-            if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {

-                return element;

-            }

+            return element;

         }

     }

     return 0;

 }

 

 

-const XMLElement* XMLNode::LastChildElement( const char* value ) const

+const XMLElement* XMLNode::LastChildElement( const char* name ) const

 {

-    for( XMLNode* node=lastChild; node; node=node->prev ) {

-        XMLElement* element = node->ToElement();

+    for( const XMLNode* node = _lastChild; node; node = node->_prev ) {

+        const XMLElement* element = node->ToElementWithName( name );

         if ( element ) {

-            if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {

-                return element;

-            }

+            return element;

         }

     }

     return 0;

 }

 

 

-const XMLElement* XMLNode::NextSiblingElement( const char* value ) const

+const XMLElement* XMLNode::NextSiblingElement( const char* name ) const

 {

-    for( XMLNode* element=this->next; element; element = element->next ) {

-        if (    element->ToElement()

-             && (!value || XMLUtil::StringEqual( value, element->Value() )))

-        {

-            return element->ToElement();

+    for( const XMLNode* node = _next; node; node = node->_next ) {

+        const XMLElement* element = node->ToElementWithName( name );

+        if ( element ) {

+            return element;

         }

     }

     return 0;

 }

 

 

-const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const

+const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const

 {

-    for( XMLNode* element=this->prev; element; element = element->prev ) {

-        if (    element->ToElement()

-             && (!value || XMLUtil::StringEqual( value, element->Value() )))

-        {

-            return element->ToElement();

+    for( const XMLNode* node = _prev; node; node = node->_prev ) {

+        const XMLElement* element = node->ToElementWithName( name );

+        if ( element ) {

+            return element;

         }

     }

     return 0;

 }

 

 

-char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )

+char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )

 {

     // This is a recursive method, but thinking about it "at the current level"

     // it is a pretty simple flat list:

-    //        <foo/>

-    //        <!-- comment -->

+    //		<foo/>

+    //		<!-- comment -->

     //

     // With a special case:

-    //        <foo>

-    //        </foo>

-    //        <!-- comment -->

+    //		<foo>

+    //		</foo>

+    //		<!-- comment -->

     //

     // Where the closing element (/foo) *must* be the next thing after the opening

     // element, and the names must match. BUT the tricky bit is that the closing

@@ -748,80 +1007,151 @@
     while( p && *p ) {

         XMLNode* node = 0;

 

-        p = document->Identify( p, &node );

-        if ( p == 0 || node == 0 ) {

+        p = _document->Identify( p, &node );

+        TIXMLASSERT( p );

+        if ( node == 0 ) {

             break;

         }

 

+        int initialLineNum = node->_parseLineNum;

+

         StrPair endTag;

-        p = node->ParseDeep( p, &endTag );

+        p = node->ParseDeep( p, &endTag, curLineNumPtr );

         if ( !p ) {

-            DELETE_NODE( node );

-            node = 0;

-            if ( !document->Error() ) {

-                document->SetError( XML_ERROR_PARSING, 0, 0 );

+            DeleteNode( node );

+            if ( !_document->Error() ) {

+                _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);

             }

             break;

         }

 

-        // We read the end tag. Return it to the parent.

-        if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {

-            if ( parentEnd ) {

-                *parentEnd = static_cast<XMLElement*>(node)->value;

-            }

-            DELETE_NODE( node );

-            return p;

-        }

-

-        // Handle an end tag returned to this level.

-        // And handle a bunch of annoying errors.

-        XMLElement* ele = node->ToElement();

-        if ( ele ) {

-            if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {

-                document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );

-                p = 0;

-            }

-            else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {

-                document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );

-                p = 0;

-            }

-            else if ( !endTag.Empty() ) {

-                if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {

-                    document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );

-                    p = 0;

+        XMLDeclaration* decl = node->ToDeclaration();

+        if ( decl ) {

+            // Declarations are only allowed at document level

+            bool wellLocated = ( ToDocument() != 0 );

+            if ( wellLocated ) {

+                // Multiple declarations are allowed but all declarations

+                // must occur before anything else

+                for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {

+                    if ( !existingNode->ToDeclaration() ) {

+                        wellLocated = false;

+                        break;

+                    }

                 }

             }

+            if ( !wellLocated ) {

+                _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());

+                DeleteNode( node );

+                break;

+            }

         }

-        if ( p == 0 ) {

-            DELETE_NODE( node );

-            node = 0;

+

+        XMLElement* ele = node->ToElement();

+        if ( ele ) {

+            // We read the end tag. Return it to the parent.

+            if ( ele->ClosingType() == XMLElement::CLOSING ) {

+                if ( parentEndTag ) {

+                    ele->_value.TransferTo( parentEndTag );

+                }

+                node->_memPool->SetTracked();   // created and then immediately deleted.

+                DeleteNode( node );

+                return p;

+            }

+

+            // Handle an end tag returned to this level.

+            // And handle a bunch of annoying errors.

+            bool mismatch = false;

+            if ( endTag.Empty() ) {

+                if ( ele->ClosingType() == XMLElement::OPEN ) {

+                    mismatch = true;

+                }

+            }

+            else {

+                if ( ele->ClosingType() != XMLElement::OPEN ) {

+                    mismatch = true;

+                }

+                else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {

+                    mismatch = true;

+                }

+            }

+            if ( mismatch ) {

+                _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());

+                DeleteNode( node );

+                break;

+            }

         }

-        if ( node ) {

-            this->InsertEndChild( node );

-        }

+        InsertEndChild( node );

+    }

+    return 0;

+}

+

+/*static*/ void XMLNode::DeleteNode( XMLNode* node )

+{

+    if ( node == 0 ) {

+        return;

+    }

+	TIXMLASSERT(node->_document);

+	if (!node->ToDocument()) {

+		node->_document->MarkInUse(node);

+	}

+

+    MemPool* pool = node->_memPool;

+    node->~XMLNode();

+    pool->Free( node );

+}

+

+void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const

+{

+    TIXMLASSERT( insertThis );

+    TIXMLASSERT( insertThis->_document == _document );

+

+	if (insertThis->_parent) {

+        insertThis->_parent->Unlink( insertThis );

+	}

+	else {

+		insertThis->_document->MarkInUse(insertThis);

+        insertThis->_memPool->SetTracked();

+	}

+}

+

+const XMLElement* XMLNode::ToElementWithName( const char* name ) const

+{

+    const XMLElement* element = this->ToElement();

+    if ( element == 0 ) {

+        return 0;

+    }

+    if ( name == 0 ) {

+        return element;

+    }

+    if ( XMLUtil::StringEqual( element->Name(), name ) ) {

+       return element;

     }

     return 0;

 }

 

 // --------- XMLText ---------- //

-char* XMLText::ParseDeep( char* p, StrPair* )

+char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )

 {

-    const char* start = p;

     if ( this->CData() ) {

-        p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );

+        p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );

         if ( !p ) {

-            document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );

+            _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );

         }

         return p;

     }

     else {

-        p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );

-        if ( !p ) {

-            document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );

+        int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;

+        if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {

+            flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;

         }

+

+        p = _value.ParseText( p, "<", flags, curLineNumPtr );

         if ( p && *p ) {

             return p-1;

         }

+        if ( !p ) {

+            _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );

+        }

     }

     return 0;

 }

@@ -830,9 +1160,9 @@
 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const

 {

     if ( !doc ) {

-        doc = document;

+        doc = _document;

     }

-    XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?

+    XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?

     text->SetCData( this->CData() );

     return text;

 }

@@ -840,12 +1170,15 @@
 

 bool XMLText::ShallowEqual( const XMLNode* compare ) const

 {

-    return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));

+    TIXMLASSERT( compare );

+    const XMLText* text = compare->ToText();

+    return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );

 }

 

 

 bool XMLText::Accept( XMLVisitor* visitor ) const

 {

+    TIXMLASSERT( visitor );

     return visitor->Visit( *this );

 }

 

@@ -859,17 +1192,15 @@
 

 XMLComment::~XMLComment()

 {

-    //printf( "~XMLComment\n" );

 }

 

 

-char* XMLComment::ParseDeep( char* p, StrPair* )

+char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )

 {

     // Comment parses as text.

-    const char* start = p;

-    p = value.ParseText( p, "-->", StrPair::COMMENT );

+    p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );

     if ( p == 0 ) {

-        document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );

+        _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );

     }

     return p;

 }

@@ -878,21 +1209,24 @@
 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const

 {

     if ( !doc ) {

-        doc = document;

+        doc = _document;

     }

-    XMLComment* comment = doc->NewComment( Value() );    // fixme: this will always allocate memory. Intern?

+    XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?

     return comment;

 }

 

 

 bool XMLComment::ShallowEqual( const XMLNode* compare ) const

 {

-    return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));

+    TIXMLASSERT( compare );

+    const XMLComment* comment = compare->ToComment();

+    return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));

 }

 

 

 bool XMLComment::Accept( XMLVisitor* visitor ) const

 {

+    TIXMLASSERT( visitor );

     return visitor->Visit( *this );

 }

 

@@ -910,13 +1244,12 @@
 }

 

 

-char* XMLDeclaration::ParseDeep( char* p, StrPair* )

+char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )

 {

     // Declaration parses as text.

-    const char* start = p;

-    p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );

+    p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );

     if ( p == 0 ) {

-        document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );

+        _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );

     }

     return p;

 }

@@ -925,22 +1258,25 @@
 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const

 {

     if ( !doc ) {

-        doc = document;

+        doc = _document;

     }

-    XMLDeclaration* dec = doc->NewDeclaration( Value() );    // fixme: this will always allocate memory. Intern?

+    XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?

     return dec;

 }

 

 

 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const

 {

-    return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));

+    TIXMLASSERT( compare );

+    const XMLDeclaration* declaration = compare->ToDeclaration();

+    return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));

 }

 

 

 

 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const

 {

+    TIXMLASSERT( visitor );

     return visitor->Visit( *this );

 }

 

@@ -956,14 +1292,12 @@
 }

 

 

-char* XMLUnknown::ParseDeep( char* p, StrPair* )

+char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )

 {

     // Unknown parses as text.

-    const char* start = p;

-

-    p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );

+    p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );

     if ( !p ) {

-        document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );

+        _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );

     }

     return p;

 }

@@ -972,97 +1306,130 @@
 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const

 {

     if ( !doc ) {

-        doc = document;

+        doc = _document;

     }

-    XMLUnknown* text = doc->NewUnknown( Value() );    // fixme: this will always allocate memory. Intern?

+    XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?

     return text;

 }

 

 

 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const

 {

-    return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));

+    TIXMLASSERT( compare );

+    const XMLUnknown* unknown = compare->ToUnknown();

+    return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));

 }

 

 

 bool XMLUnknown::Accept( XMLVisitor* visitor ) const

 {

+    TIXMLASSERT( visitor );

     return visitor->Visit( *this );

 }

 

 // --------- XMLAttribute ---------- //

-char* XMLAttribute::ParseDeep( char* p, bool processEntities )

+

+const char* XMLAttribute::Name() const 

+{

+    return _name.GetStr();

+}

+

+const char* XMLAttribute::Value() const 

+{

+    return _value.GetStr();

+}

+

+char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )

 {

     // Parse using the name rules: bug fix, was using ParseText before

-    p = name.ParseName( p );

-    if ( !p || !*p ) return 0;

+    p = _name.ParseName( p );

+    if ( !p || !*p ) {

+        return 0;

+    }

 

     // Skip white space before =

-    p = XMLUtil::SkipWhiteSpace( p );

-    if ( !p || *p != '=' ) return 0;

+    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );

+    if ( *p != '=' ) {

+        return 0;

+    }

 

-    ++p;    // move up to opening quote

-    p = XMLUtil::SkipWhiteSpace( p );

-    if ( *p != '\"' && *p != '\'' ) return 0;

+    ++p;	// move up to opening quote

+    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );

+    if ( *p != '\"' && *p != '\'' ) {

+        return 0;

+    }

 

     char endTag[2] = { *p, 0 };

-    ++p;    // move past opening quote

+    ++p;	// move past opening quote

 

-    p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );

+    p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );

     return p;

 }

 

 

 void XMLAttribute::SetName( const char* n )

 {

-    name.SetStr( n );

+    _name.SetStr( n );

 }

 

 

-int XMLAttribute::QueryIntValue( int* value ) const

+XMLError XMLAttribute::QueryIntValue( int* value ) const

 {

-    if ( XMLUtil::ToInt( Value(), value ))

-        return XML_NO_ERROR;

-    return XML_WRONG_ATTRIBUTE_TYPE;

-}

-

-

-int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const

-{

-    if ( XMLUtil::ToUnsigned( Value(), value ))

-        return XML_NO_ERROR;

-    return XML_WRONG_ATTRIBUTE_TYPE;

-}

-

-

-int XMLAttribute::QueryBoolValue( bool* value ) const

-{

-    if ( XMLUtil::ToBool( Value(), value )) {

-        return XML_NO_ERROR;

+    if ( XMLUtil::ToInt( Value(), value )) {

+        return XML_SUCCESS;

     }

     return XML_WRONG_ATTRIBUTE_TYPE;

 }

 

 

-int XMLAttribute::QueryFloatValue( float* value ) const

+XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const

 {

-    if ( XMLUtil::ToFloat( Value(), value ))

-        return XML_NO_ERROR;

+    if ( XMLUtil::ToUnsigned( Value(), value )) {

+        return XML_SUCCESS;

+    }

     return XML_WRONG_ATTRIBUTE_TYPE;

 }

 

 

-int XMLAttribute::QueryDoubleValue( double* value ) const

+XMLError XMLAttribute::QueryInt64Value(int64_t* value) const

 {

-    if ( XMLUtil::ToDouble( Value(), value ))

-        return XML_NO_ERROR;

+	if (XMLUtil::ToInt64(Value(), value)) {

+		return XML_SUCCESS;

+	}

+	return XML_WRONG_ATTRIBUTE_TYPE;

+}

+

+

+XMLError XMLAttribute::QueryBoolValue( bool* value ) const

+{

+    if ( XMLUtil::ToBool( Value(), value )) {

+        return XML_SUCCESS;

+    }

+    return XML_WRONG_ATTRIBUTE_TYPE;

+}

+

+

+XMLError XMLAttribute::QueryFloatValue( float* value ) const

+{

+    if ( XMLUtil::ToFloat( Value(), value )) {

+        return XML_SUCCESS;

+    }

+    return XML_WRONG_ATTRIBUTE_TYPE;

+}

+

+

+XMLError XMLAttribute::QueryDoubleValue( double* value ) const

+{

+    if ( XMLUtil::ToDouble( Value(), value )) {

+        return XML_SUCCESS;

+    }

     return XML_WRONG_ATTRIBUTE_TYPE;

 }

 

 

 void XMLAttribute::SetAttribute( const char* v )

 {

-    value.SetStr( v );

+    _value.SetStr( v );

 }

 

 

@@ -1070,7 +1437,7 @@
 {

     char buf[BUF_SIZE];

     XMLUtil::ToStr( v, buf, BUF_SIZE );

-    value.SetStr( buf );

+    _value.SetStr( buf );

 }

 

 

@@ -1078,67 +1445,65 @@
 {

     char buf[BUF_SIZE];

     XMLUtil::ToStr( v, buf, BUF_SIZE );

-    value.SetStr( buf );

+    _value.SetStr( buf );

 }

 

 

+void XMLAttribute::SetAttribute(int64_t v)

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr(v, buf, BUF_SIZE);

+	_value.SetStr(buf);

+}

+

+

+

 void XMLAttribute::SetAttribute( bool v )

 {

     char buf[BUF_SIZE];

     XMLUtil::ToStr( v, buf, BUF_SIZE );

-    value.SetStr( buf );

+    _value.SetStr( buf );

 }

 

 void XMLAttribute::SetAttribute( double v )

 {

     char buf[BUF_SIZE];

     XMLUtil::ToStr( v, buf, BUF_SIZE );

-    value.SetStr( buf );

+    _value.SetStr( buf );

 }

 

 void XMLAttribute::SetAttribute( float v )

 {

     char buf[BUF_SIZE];

     XMLUtil::ToStr( v, buf, BUF_SIZE );

-    value.SetStr( buf );

+    _value.SetStr( buf );

 }

 

 

 // --------- XMLElement ---------- //

 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),

-    closingType( 0 ),

-    rootAttribute( 0 )

+    _closingType( OPEN ),

+    _rootAttribute( 0 )

 {

 }

 

 

 XMLElement::~XMLElement()

 {

-    while( rootAttribute ) {

-        XMLAttribute* next = rootAttribute->next;

-        DELETE_ATTRIBUTE( rootAttribute );

-        rootAttribute = next;

+    while( _rootAttribute ) {

+        XMLAttribute* next = _rootAttribute->_next;

+        DeleteAttribute( _rootAttribute );

+        _rootAttribute = next;

     }

 }

 

 

-XMLAttribute* XMLElement::FindAttribute( const char* name )

-{

-    XMLAttribute* a = 0;

-    for( a=rootAttribute; a; a = a->next ) {

-        if ( XMLUtil::StringEqual( a->Name(), name ) )

-            return a;

-    }

-    return 0;

-}

-

-

 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const

 {

-    XMLAttribute* a = 0;

-    for( a=rootAttribute; a; a = a->next ) {

-        if ( XMLUtil::StringEqual( a->Name(), name ) )

+    for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {

+        if ( XMLUtil::StringEqual( a->Name(), name ) ) {

             return a;

+        }

     }

     return 0;

 }

@@ -1147,28 +1512,130 @@
 const char* XMLElement::Attribute( const char* name, const char* value ) const

 {

     const XMLAttribute* a = FindAttribute( name );

-    if ( !a )

+    if ( !a ) {

         return 0;

-    if ( !value || XMLUtil::StringEqual( a->Value(), value ))

+    }

+    if ( !value || XMLUtil::StringEqual( a->Value(), value )) {

         return a->Value();

+    }

     return 0;

 }

 

+int XMLElement::IntAttribute(const char* name, int defaultValue) const 

+{

+	int i = defaultValue;

+	QueryIntAttribute(name, &i);

+	return i;

+}

+

+unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const 

+{

+	unsigned i = defaultValue;

+	QueryUnsignedAttribute(name, &i);

+	return i;

+}

+

+int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const 

+{

+	int64_t i = defaultValue;

+	QueryInt64Attribute(name, &i);

+	return i;

+}

+

+bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const 

+{

+	bool b = defaultValue;

+	QueryBoolAttribute(name, &b);

+	return b;

+}

+

+double XMLElement::DoubleAttribute(const char* name, double defaultValue) const 

+{

+	double d = defaultValue;

+	QueryDoubleAttribute(name, &d);

+	return d;

+}

+

+float XMLElement::FloatAttribute(const char* name, float defaultValue) const 

+{

+	float f = defaultValue;

+	QueryFloatAttribute(name, &f);

+	return f;

+}

 

 const char* XMLElement::GetText() const

 {

     if ( FirstChild() && FirstChild()->ToText() ) {

-        return FirstChild()->ToText()->Value();

+        return FirstChild()->Value();

     }

     return 0;

 }

 

 

-int XMLElement::QueryIntText( int* _value ) const

+void	XMLElement::SetText( const char* inText )

+{

+	if ( FirstChild() && FirstChild()->ToText() )

+		FirstChild()->SetValue( inText );

+	else {

+		XMLText*	theText = GetDocument()->NewText( inText );

+		InsertFirstChild( theText );

+	}

+}

+

+

+void XMLElement::SetText( int v ) 

+{

+    char buf[BUF_SIZE];

+    XMLUtil::ToStr( v, buf, BUF_SIZE );

+    SetText( buf );

+}

+

+

+void XMLElement::SetText( unsigned v ) 

+{

+    char buf[BUF_SIZE];

+    XMLUtil::ToStr( v, buf, BUF_SIZE );

+    SetText( buf );

+}

+

+

+void XMLElement::SetText(int64_t v)

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr(v, buf, BUF_SIZE);

+	SetText(buf);

+}

+

+

+void XMLElement::SetText( bool v )

+{

+    char buf[BUF_SIZE];

+    XMLUtil::ToStr( v, buf, BUF_SIZE );

+    SetText( buf );

+}

+

+

+void XMLElement::SetText( float v ) 

+{

+    char buf[BUF_SIZE];

+    XMLUtil::ToStr( v, buf, BUF_SIZE );

+    SetText( buf );

+}

+

+

+void XMLElement::SetText( double v ) 

+{

+    char buf[BUF_SIZE];

+    XMLUtil::ToStr( v, buf, BUF_SIZE );

+    SetText( buf );

+}

+

+

+XMLError XMLElement::QueryIntText( int* ival ) const

 {

     if ( FirstChild() && FirstChild()->ToText() ) {

-        const char* t = FirstChild()->ToText()->Value();

-        if ( XMLUtil::ToInt( t, _value ) ) {

+        const char* t = FirstChild()->Value();

+        if ( XMLUtil::ToInt( t, ival ) ) {

             return XML_SUCCESS;

         }

         return XML_CAN_NOT_CONVERT_TEXT;

@@ -1177,11 +1644,11 @@
 }

 

 

-int XMLElement::QueryUnsignedText( unsigned* _value ) const

+XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const

 {

     if ( FirstChild() && FirstChild()->ToText() ) {

-        const char* t = FirstChild()->ToText()->Value();

-        if ( XMLUtil::ToUnsigned( t, _value ) ) {

+        const char* t = FirstChild()->Value();

+        if ( XMLUtil::ToUnsigned( t, uval ) ) {

             return XML_SUCCESS;

         }

         return XML_CAN_NOT_CONVERT_TEXT;

@@ -1190,11 +1657,24 @@
 }

 

 

-int XMLElement::QueryBoolText( bool* _value ) const

+XMLError XMLElement::QueryInt64Text(int64_t* ival) const

+{

+	if (FirstChild() && FirstChild()->ToText()) {

+		const char* t = FirstChild()->Value();

+		if (XMLUtil::ToInt64(t, ival)) {

+			return XML_SUCCESS;

+		}

+		return XML_CAN_NOT_CONVERT_TEXT;

+	}

+	return XML_NO_TEXT_NODE;

+}

+

+

+XMLError XMLElement::QueryBoolText( bool* bval ) const

 {

     if ( FirstChild() && FirstChild()->ToText() ) {

-        const char* t = FirstChild()->ToText()->Value();

-        if ( XMLUtil::ToBool( t, _value ) ) {

+        const char* t = FirstChild()->Value();

+        if ( XMLUtil::ToBool( t, bval ) ) {

             return XML_SUCCESS;

         }

         return XML_CAN_NOT_CONVERT_TEXT;

@@ -1203,11 +1683,11 @@
 }

 

 

-int XMLElement::QueryDoubleText( double* _value ) const

+XMLError XMLElement::QueryDoubleText( double* dval ) const

 {

     if ( FirstChild() && FirstChild()->ToText() ) {

-        const char* t = FirstChild()->ToText()->Value();

-        if ( XMLUtil::ToDouble( t, _value ) ) {

+        const char* t = FirstChild()->Value();

+        if ( XMLUtil::ToDouble( t, dval ) ) {

             return XML_SUCCESS;

         }

         return XML_CAN_NOT_CONVERT_TEXT;

@@ -1216,11 +1696,11 @@
 }

 

 

-int XMLElement::QueryFloatText( float* _value ) const

+XMLError XMLElement::QueryFloatText( float* fval ) const

 {

     if ( FirstChild() && FirstChild()->ToText() ) {

-        const char* t = FirstChild()->ToText()->Value();

-        if ( XMLUtil::ToFloat( t, _value ) ) {

+        const char* t = FirstChild()->Value();

+        if ( XMLUtil::ToFloat( t, fval ) ) {

             return XML_SUCCESS;

         }

         return XML_CAN_NOT_CONVERT_TEXT;

@@ -1228,28 +1708,70 @@
     return XML_NO_TEXT_NODE;

 }

 

+int XMLElement::IntText(int defaultValue) const

+{

+	int i = defaultValue;

+	QueryIntText(&i);

+	return i;

+}

+

+unsigned XMLElement::UnsignedText(unsigned defaultValue) const

+{

+	unsigned i = defaultValue;

+	QueryUnsignedText(&i);

+	return i;

+}

+

+int64_t XMLElement::Int64Text(int64_t defaultValue) const

+{

+	int64_t i = defaultValue;

+	QueryInt64Text(&i);

+	return i;

+}

+

+bool XMLElement::BoolText(bool defaultValue) const

+{

+	bool b = defaultValue;

+	QueryBoolText(&b);

+	return b;

+}

+

+double XMLElement::DoubleText(double defaultValue) const

+{

+	double d = defaultValue;

+	QueryDoubleText(&d);

+	return d;

+}

+

+float XMLElement::FloatText(float defaultValue) const

+{

+	float f = defaultValue;

+	QueryFloatText(&f);

+	return f;

+}

 

 

 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )

 {

     XMLAttribute* last = 0;

     XMLAttribute* attrib = 0;

-    for( attrib = rootAttribute;

-         attrib;

-         last = attrib, attrib = attrib->next )

-    {

+    for( attrib = _rootAttribute;

+            attrib;

+            last = attrib, attrib = attrib->_next ) {

         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {

             break;

         }

     }

     if ( !attrib ) {

-        attrib = new (document->attributePool.Alloc() ) XMLAttribute();

-        attrib->memPool = &document->attributePool;

+        attrib = CreateAttribute();

+        TIXMLASSERT( attrib );

         if ( last ) {

-            last->next = attrib;

+            TIXMLASSERT( last->_next == 0 );

+            last->_next = attrib;

         }

         else {

-            rootAttribute = attrib;

+            TIXMLASSERT( _rootAttribute == 0 );

+            _rootAttribute = attrib;

         }

         attrib->SetName( name );

     }

@@ -1260,15 +1782,15 @@
 void XMLElement::DeleteAttribute( const char* name )

 {

     XMLAttribute* prev = 0;

-    for( XMLAttribute* a=rootAttribute; a; a=a->next ) {

+    for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {

         if ( XMLUtil::StringEqual( name, a->Name() ) ) {

             if ( prev ) {

-                prev->next = a->next;

+                prev->_next = a->_next;

             }

             else {

-                rootAttribute = a->next;

+                _rootAttribute = a->_next;

             }

-            DELETE_ATTRIBUTE( a );

+            DeleteAttribute( a );

             break;

         }

         prev = a;

@@ -1276,28 +1798,30 @@
 }

 

 

-char* XMLElement::ParseAttributes( char* p )

+char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )

 {

-    const char* start = p;

     XMLAttribute* prevAttribute = 0;

 

     // Read the attributes.

     while( p ) {

-        p = XMLUtil::SkipWhiteSpace( p );

-        if ( !p || !(*p) ) {

-            document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );

+        p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );

+        if ( !(*p) ) {

+            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );

             return 0;

         }

 

         // attribute.

-        if ( XMLUtil::IsAlpha( *p ) ) {

-            XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();

-            attrib->memPool = &document->attributePool;

+        if (XMLUtil::IsNameStartChar( *p ) ) {

+            XMLAttribute* attrib = CreateAttribute();

+            TIXMLASSERT( attrib );

+            attrib->_parseLineNum = _document->_parseCurLineNum;

 

-            p = attrib->ParseDeep( p, document->ProcessEntities() );

+            int attrLineNum = attrib->_parseLineNum;

+

+            p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );

             if ( !p || Attribute( attrib->Name() ) ) {

-                DELETE_ATTRIBUTE( attrib );

-                document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );

+                DeleteAttribute( attrib );

+                _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );

                 return 0;

             }

             // There is a minor bug here: if the attribute in the source xml

@@ -1306,58 +1830,81 @@
             // avoids re-scanning the attribute list. Preferring performance for

             // now, may reconsider in the future.

             if ( prevAttribute ) {

-                prevAttribute->next = attrib;

+                TIXMLASSERT( prevAttribute->_next == 0 );

+                prevAttribute->_next = attrib;

             }

             else {

-                rootAttribute = attrib;

+                TIXMLASSERT( _rootAttribute == 0 );

+                _rootAttribute = attrib;

             }

             prevAttribute = attrib;

         }

         // end of the tag

-        else if ( *p == '/' && *(p+1) == '>' ) {

-            closingType = CLOSED;

-            return p+2;    // done; sealed element.

-        }

-        // end of the tag

         else if ( *p == '>' ) {

             ++p;

             break;

         }

+        // end of the tag

+        else if ( *p == '/' && *(p+1) == '>' ) {

+            _closingType = CLOSED;

+            return p+2;	// done; sealed element.

+        }

         else {

-            document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );

+            _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );

             return 0;

         }

     }

     return p;

 }

 

+void XMLElement::DeleteAttribute( XMLAttribute* attribute )

+{

+    if ( attribute == 0 ) {

+        return;

+    }

+    MemPool* pool = attribute->_memPool;

+    attribute->~XMLAttribute();

+    pool->Free( attribute );

+}

+

+XMLAttribute* XMLElement::CreateAttribute()

+{

+    TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );

+    XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();

+    TIXMLASSERT( attrib );

+    attrib->_memPool = &_document->_attributePool;

+    attrib->_memPool->SetTracked();

+    return attrib;

+}

 

 //

-//    <ele></ele>

-//    <ele>foo<b>bar</b></ele>

+//	<ele></ele>

+//	<ele>foo<b>bar</b></ele>

 //

-char* XMLElement::ParseDeep( char* p, StrPair* strPair )

+char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )

 {

     // Read the element name.

-    p = XMLUtil::SkipWhiteSpace( p );

-    if ( !p ) return 0;

+    p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );

 

     // The closing element is the </element> form. It is

     // parsed just like a regular element then deleted from

     // the DOM.

     if ( *p == '/' ) {

-        closingType = CLOSING;

+        _closingType = CLOSING;

         ++p;

     }

 

-    p = value.ParseName( p );

-    if ( value.Empty() ) return 0;

+    p = _value.ParseName( p );

+    if ( _value.Empty() ) {

+        return 0;

+    }

 

-    p = ParseAttributes( p );

-    if ( !p || !*p || closingType )

+    p = ParseAttributes( p, curLineNumPtr );

+    if ( !p || !*p || _closingType != OPEN ) {

         return p;

+    }

 

-    p = XMLNode::ParseDeep( p, strPair );

+    p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );

     return p;

 }

 

@@ -1366,11 +1913,11 @@
 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const

 {

     if ( !doc ) {

-        doc = document;

+        doc = _document;

     }

-    XMLElement* element = doc->NewElement( Value() );                    // fixme: this will always allocate memory. Intern?

+    XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?

     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {

-        element->SetAttribute( a->Name(), a->Value() );                    // fixme: this will always allocate memory. Intern?

+        element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?

     }

     return element;

 }

@@ -1378,8 +1925,9 @@
 

 bool XMLElement::ShallowEqual( const XMLNode* compare ) const

 {

+    TIXMLASSERT( compare );

     const XMLElement* other = compare->ToElement();

-    if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {

+    if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {

 

         const XMLAttribute* a=FirstAttribute();

         const XMLAttribute* b=other->FirstAttribute();

@@ -1403,12 +1951,12 @@
 

 bool XMLElement::Accept( XMLVisitor* visitor ) const

 {

-    if ( visitor->VisitEnter( *this, rootAttribute ) )

-    {

-        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )

-        {

-            if ( !node->Accept( visitor ) )

+    TIXMLASSERT( visitor );

+    if ( visitor->VisitEnter( *this, _rootAttribute ) ) {

+        for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {

+            if ( !node->Accept( visitor ) ) {

                 break;

+            }

         }

     }

     return visitor->VisitExit( *this );

@@ -1416,54 +1964,121 @@
 

 

 // --------- XMLDocument ----------- //

-XMLDocument::XMLDocument( bool _processEntities ) :

+

+// Warning: List must match 'enum XMLError'

+const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {

+    "XML_SUCCESS",

+    "XML_NO_ATTRIBUTE",

+    "XML_WRONG_ATTRIBUTE_TYPE",

+    "XML_ERROR_FILE_NOT_FOUND",

+    "XML_ERROR_FILE_COULD_NOT_BE_OPENED",

+    "XML_ERROR_FILE_READ_ERROR",

+    "UNUSED_XML_ERROR_ELEMENT_MISMATCH",

+    "XML_ERROR_PARSING_ELEMENT",

+    "XML_ERROR_PARSING_ATTRIBUTE",

+    "UNUSED_XML_ERROR_IDENTIFYING_TAG",

+    "XML_ERROR_PARSING_TEXT",

+    "XML_ERROR_PARSING_CDATA",

+    "XML_ERROR_PARSING_COMMENT",

+    "XML_ERROR_PARSING_DECLARATION",

+    "XML_ERROR_PARSING_UNKNOWN",

+    "XML_ERROR_EMPTY_DOCUMENT",

+    "XML_ERROR_MISMATCHED_ELEMENT",

+    "XML_ERROR_PARSING",

+    "XML_CAN_NOT_CONVERT_TEXT",

+    "XML_NO_TEXT_NODE"

+};

+

+

+XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :

     XMLNode( 0 ),

-    writeBOM( false ),

-    processEntities( _processEntities ),

-    errorID( 0 ),

-    errorStr1( 0 ),

-    errorStr2( 0 ),

-    charBuffer( 0 )

+    _writeBOM( false ),

+    _processEntities( processEntities ),

+    _errorID(XML_SUCCESS),

+    _whitespaceMode( whitespaceMode ),

+    _errorStr(),

+    _errorLineNum( 0 ),

+    _charBuffer( 0 ),

+    _parseCurLineNum( 0 ),

+    _unlinked(),

+    _elementPool(),

+    _attributePool(),

+    _textPool(),

+    _commentPool()

 {

-    document = this;    // avoid warning about 'this' in initializer list

+    // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)

+    _document = this;

 }

 

 

 XMLDocument::~XMLDocument()

 {

+    Clear();

+}

+

+

+void XMLDocument::MarkInUse(XMLNode* node)

+{

+	TIXMLASSERT(node);

+	TIXMLASSERT(node->_parent == 0);

+

+	for (int i = 0; i < _unlinked.Size(); ++i) {

+		if (node == _unlinked[i]) {

+			_unlinked.SwapRemove(i);

+			break;

+		}

+	}

+}

+

+void XMLDocument::Clear()

+{

     DeleteChildren();

-    delete [] charBuffer;

+	while( _unlinked.Size()) {

+		DeleteNode(_unlinked[0]);	// Will remove from _unlinked as part of delete.

+	}

+

+#ifdef DEBUG

+    const bool hadError = Error();

+#endif

+    ClearError();

+

+    delete [] _charBuffer;

+    _charBuffer = 0;

 

 #if 0

-    textPool.Trace( "text" );

-    elementPool.Trace( "element" );

-    commentPool.Trace( "comment" );

-    attributePool.Trace( "attribute" );

+    _textPool.Trace( "text" );

+    _elementPool.Trace( "element" );

+    _commentPool.Trace( "comment" );

+    _attributePool.Trace( "attribute" );

 #endif

-

-    TIXMLASSERT( textPool.CurrentAllocs() == 0 );

-    TIXMLASSERT( elementPool.CurrentAllocs() == 0 );

-    TIXMLASSERT( commentPool.CurrentAllocs() == 0 );

-    TIXMLASSERT( attributePool.CurrentAllocs() == 0 );

+    

+#ifdef DEBUG

+    if ( !hadError ) {

+        TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );

+        TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );

+        TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );

+        TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );

+    }

+#endif

 }

 

 

-void XMLDocument::InitDocument()

+void XMLDocument::DeepCopy(XMLDocument* target) const

 {

-    errorID = XML_NO_ERROR;

-    errorStr1 = 0;

-    errorStr2 = 0;

+	TIXMLASSERT(target);

+    if (target == this) {

+        return; // technically success - a no-op.

+    }

 

-    delete [] charBuffer;

-    charBuffer = 0;

-

+	target->Clear();

+	for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {

+		target->InsertEndChild(node->DeepClone(target));

+	}

 }

 

-

 XMLElement* XMLDocument::NewElement( const char* name )

 {

-    XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );

-    ele->memPool = &elementPool;

+    XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );

     ele->SetName( name );

     return ele;

 }

@@ -1471,8 +2086,7 @@
 

 XMLComment* XMLDocument::NewComment( const char* str )

 {

-    XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );

-    comment->memPool = &commentPool;

+    XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );

     comment->SetValue( str );

     return comment;

 }

@@ -1480,8 +2094,7 @@
 

 XMLText* XMLDocument::NewText( const char* str )

 {

-    XMLText* text = new (textPool.Alloc()) XMLText( this );

-    text->memPool = &textPool;

+    XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );

     text->SetValue( str );

     return text;

 }

@@ -1489,8 +2102,7 @@
 

 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )

 {

-    XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );

-    dec->memPool = &commentPool;

+    XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );

     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );

     return dec;

 }

@@ -1498,187 +2110,283 @@
 

 XMLUnknown* XMLDocument::NewUnknown( const char* str )

 {

-    XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );

-    unk->memPool = &commentPool;

+    XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );

     unk->SetValue( str );

     return unk;

 }

 

-

-int XMLDocument::LoadFile( const char* filename )

+static FILE* callfopen( const char* filepath, const char* mode )

 {

-    DeleteChildren();

-    InitDocument();

+    TIXMLASSERT( filepath );

+    TIXMLASSERT( mode );

+#if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)

+    FILE* fp = 0;

+    errno_t err = fopen_s( &fp, filepath, mode );

+    if ( err ) {

+        return 0;

+    }

+#else

+    FILE* fp = fopen( filepath, mode );

+#endif

+    return fp;

+}

+    

+void XMLDocument::DeleteNode( XMLNode* node )	{

+    TIXMLASSERT( node );

+    TIXMLASSERT(node->_document == this );

+    if (node->_parent) {

+        node->_parent->DeleteChild( node );

+    }

+    else {

+        // Isn't in the tree.

+        // Use the parent delete.

+        // Also, we need to mark it tracked: we 'know'

+        // it was never used.

+        node->_memPool->SetTracked();

+        // Call the static XMLNode version:

+        XMLNode::DeleteNode(node);

+    }

+}

 

-#if defined(_MSC_VER)

-#pragma warning ( push )

-#pragma warning ( disable : 4996 )        // Fail to see a compelling reason why this should be deprecated.

-#endif

-    FILE* fp = fopen( filename, "rb" );

-#if defined(_MSC_VER)

-#pragma warning ( pop )

-#endif

+

+XMLError XMLDocument::LoadFile( const char* filename )

+{

+    Clear();

+    FILE* fp = callfopen( filename, "rb" );

     if ( !fp ) {

-        SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );

-        return errorID;

+        SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename ? filename : "<null>");

+        return _errorID;

     }

     LoadFile( fp );

     fclose( fp );

-    return errorID;

+    return _errorID;

 }

 

+// This is likely overengineered template art to have a check that unsigned long value incremented

+// by one still fits into size_t. If size_t type is larger than unsigned long type

+// (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit

+// -Wtype-limits warning. This piece makes the compiler select code with a check when a check

+// is useful and code with no check when a check is redundant depending on how size_t and unsigned long

+// types sizes relate to each other.

+template

+<bool = (sizeof(unsigned long) >= sizeof(size_t))>

+struct LongFitsIntoSizeTMinusOne {

+    static bool Fits( unsigned long value )

+    {

+        return value < (size_t)-1;

+    }

+};

 

-int XMLDocument::LoadFile( FILE* fp )

+template <>

+struct LongFitsIntoSizeTMinusOne<false> {

+    static bool Fits( unsigned long )

+    {

+        return true;

+    }

+};

+

+XMLError XMLDocument::LoadFile( FILE* fp )

 {

-    DeleteChildren();

-    InitDocument();

+    Clear();

+

+    fseek( fp, 0, SEEK_SET );

+    if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {

+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );

+        return _errorID;

+    }

 

     fseek( fp, 0, SEEK_END );

-    unsigned size = ftell( fp );

+    const long filelength = ftell( fp );

     fseek( fp, 0, SEEK_SET );

+    if ( filelength == -1L ) {

+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );

+        return _errorID;

+    }

+    TIXMLASSERT( filelength >= 0 );

 

-    if ( size == 0 ) {

-        return errorID;

+    if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {

+        // Cannot handle files which won't fit in buffer together with null terminator

+        SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );

+        return _errorID;

     }

 

-    charBuffer = new char[size+1];

-    size_t read = fread( charBuffer, 1, size, fp );

+    if ( filelength == 0 ) {

+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );

+        return _errorID;

+    }

+

+    const size_t size = filelength;

+    TIXMLASSERT( _charBuffer == 0 );

+    _charBuffer = new char[size+1];

+    size_t read = fread( _charBuffer, 1, size, fp );

     if ( read != size ) {

         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );

-        return errorID;

+        return _errorID;

     }

 

-    charBuffer[size] = 0;

+    _charBuffer[size] = 0;

 

-    const char* p = charBuffer;

-    p = XMLUtil::SkipWhiteSpace( p );

-    p = XMLUtil::ReadBOM( p, &writeBOM );

-    if ( !p || !*p ) {

-        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );

-        return errorID;

-    }

-

-    ParseDeep( charBuffer + (p-charBuffer), 0 );

-    return errorID;

+    Parse();

+    return _errorID;

 }

 

 

-int XMLDocument::SaveFile( const char* filename )

+XMLError XMLDocument::SaveFile( const char* filename, bool compact )

 {

-#if defined(_MSC_VER)

-#pragma warning ( push )

-#pragma warning ( disable : 4996 )        // Fail to see a compelling reason why this should be deprecated.

-#endif

-    int fd = open(filename, O_RDWR|O_CREAT, 0644);

-    FILE* fp = fdopen(fd, "w");

-    //FILE* fp = fopen( filename, "w" );

-#if defined(_MSC_VER)

-#pragma warning ( pop )

-#endif

+    FILE* fp = callfopen( filename, "w" );

     if ( !fp ) {

-        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );

-        return errorID;

+        SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename ? filename : "<null>");

+        return _errorID;

     }

-    SaveFile(fp);

+    SaveFile(fp, compact);

     fclose( fp );

-    return errorID;

+    return _errorID;

 }

 

 

-int XMLDocument::SaveFile( FILE* fp )

+XMLError XMLDocument::SaveFile( FILE* fp, bool compact )

 {

-    XMLPrinter stream( fp );

+    // Clear any error from the last save, otherwise it will get reported

+    // for *this* call.

+    ClearError();

+    XMLPrinter stream( fp, compact );

     Print( &stream );

-    return errorID;

+    return _errorID;

 }

 

 

-int XMLDocument::Parse( const char* p )

+XMLError XMLDocument::Parse( const char* p, size_t len )

 {

-    DeleteChildren();

-    InitDocument();

+    Clear();

 

-    if ( !p || !*p ) {

+    if ( len == 0 || !p || !*p ) {

         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );

-        return errorID;

+        return _errorID;

     }

-    p = XMLUtil::SkipWhiteSpace( p );

-    p = XMLUtil::ReadBOM( p, &writeBOM );

-    if ( !p || !*p ) {

-        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );

-        return errorID;

+    if ( len == (size_t)(-1) ) {

+        len = strlen( p );

     }

+    TIXMLASSERT( _charBuffer == 0 );

+    _charBuffer = new char[ len+1 ];

+    memcpy( _charBuffer, p, len );

+    _charBuffer[len] = 0;

 

-    size_t len = strlen( p );

-    charBuffer = new char[ len+1 ];

-    memcpy( charBuffer, p, len+1 );

-

-

-    ParseDeep( charBuffer, 0 );

-    return errorID;

+    Parse();

+    if ( Error() ) {

+        // clean up now essentially dangling memory.

+        // and the parse fail can put objects in the

+        // pools that are dead and inaccessible.

+        DeleteChildren();

+        _elementPool.Clear();

+        _attributePool.Clear();

+        _textPool.Clear();

+        _commentPool.Clear();

+    }

+    return _errorID;

 }

 

 

-void XMLDocument::Print( XMLPrinter* streamer )

+void XMLDocument::Print( XMLPrinter* streamer ) const

 {

-    XMLPrinter stdStreamer( stdout );

-    if ( !streamer )

-        streamer = &stdStreamer;

-    Accept( streamer );

+    if ( streamer ) {

+        Accept( streamer );

+    }

+    else {

+        XMLPrinter stdoutStreamer( stdout );

+        Accept( &stdoutStreamer );

+    }

 }

 

 

-void XMLDocument::SetError( int error, const char* str1, const char* str2 )

+void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )

 {

-    errorID = error;

-    errorStr1 = str1;

-    errorStr2 = str2;

+    TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );

+    _errorID = error;

+    _errorLineNum = lineNum;

+	_errorStr.Reset();

+

+    if (format) {

+        size_t BUFFER_SIZE = 1000;

+        char* buffer = new char[BUFFER_SIZE];

+        TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d: ", ErrorIDToName(error), int(error), int(error), lineNum);

+        size_t len = strlen(buffer);

+

+        va_list va;

+        va_start( va, format );

+        TIXML_VSNPRINTF( buffer + len, BUFFER_SIZE - len, format, va );

+        va_end( va );

+

+        _errorStr.SetStr(buffer);

+        delete [] buffer;

+    }

+}

+

+

+/*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)

+{

+	TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );

+    const char* errorName = _errorNames[errorID];

+    TIXMLASSERT( errorName && errorName[0] );

+    return errorName;

+}

+

+const char* XMLDocument::ErrorStr() const 

+{

+	return _errorStr.Empty() ? "" : _errorStr.GetStr();

 }

 

 

 void XMLDocument::PrintError() const

 {

-    if ( errorID ) {

-        static const int LEN = 20;

-        char buf1[LEN] = { 0 };

-        char buf2[LEN] = { 0 };

-

-        if ( errorStr1 ) {

-            TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );

-        }

-        if ( errorStr2 ) {

-            TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );

-        }

-

-        printf( "XMLDocument error id=%d str1=%s str2=%s\n",

-                errorID, buf1, buf2 );

-    }

+    printf("%s\n", ErrorStr());

 }

 

+const char* XMLDocument::ErrorName() const

+{

+    return ErrorIDToName(_errorID);

+}

 

-XMLPrinter::XMLPrinter( FILE* file, bool compact ) :

-    elementJustOpened( false ),

-    firstElement( true ),

-    fp( file ),

-    depth( 0 ),

-    textDepth( -1 ),

-    processEntities( true ),

-    compactMode( compact )

+void XMLDocument::Parse()

+{

+    TIXMLASSERT( NoChildren() ); // Clear() must have been called previously

+    TIXMLASSERT( _charBuffer );

+    _parseCurLineNum = 1;

+    _parseLineNum = 1;

+    char* p = _charBuffer;

+    p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );

+    p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );

+    if ( !*p ) {

+        SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );

+        return;

+    }

+    ParseDeep(p, 0, &_parseCurLineNum );

+}

+

+XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :

+    _elementJustOpened( false ),

+    _stack(),

+    _firstElement( true ),

+    _fp( file ),

+    _depth( depth ),

+    _textDepth( -1 ),

+    _processEntities( true ),

+    _compactMode( compact ),

+    _buffer()

 {

     for( int i=0; i<ENTITY_RANGE; ++i ) {

-        entityFlag[i] = false;

-        restrictedEntityFlag[i] = false;

+        _entityFlag[i] = false;

+        _restrictedEntityFlag[i] = false;

     }

     for( int i=0; i<NUM_ENTITIES; ++i ) {

-        TIXMLASSERT( entities[i].value < ENTITY_RANGE );

-        if ( entities[i].value < ENTITY_RANGE ) {

-            entityFlag[ (int)entities[i].value ] = true;

-        }

+        const char entityValue = entities[i].value;

+        const unsigned char flagIndex = (unsigned char)entityValue;

+        TIXMLASSERT( flagIndex < ENTITY_RANGE );

+        _entityFlag[flagIndex] = true;

     }

-    restrictedEntityFlag[(int)'&'] = true;

-    restrictedEntityFlag[(int)'<'] = true;

-    restrictedEntityFlag[(int)'>'] = true;    // not required, but consistency is nice

-    buffer.Push( 0 );

+    _restrictedEntityFlag[(unsigned char)'&'] = true;

+    _restrictedEntityFlag[(unsigned char)'<'] = true;

+    _restrictedEntityFlag[(unsigned char)'>'] = true;	// not required, but consistency is nice

+    _buffer.Push( 0 );

 }

 

 

@@ -1687,41 +2395,53 @@
     va_list     va;

     va_start( va, format );

 

-    if ( fp ) {

-        vfprintf( fp, format, va );

+    if ( _fp ) {

+        vfprintf( _fp, format, va );

     }

     else {

-        // This seems brutally complex. Haven't figured out a better

-        // way on windows.

-        #ifdef _MSC_VER

-            int len = -1;

-            int expand = 1000;

-            while ( len < 0 ) {

-                len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );

-                if ( len < 0 ) {

-                    expand *= 3/2;

-                    accumulator.PushArr( expand );

-                }

-            }

-            char* p = buffer.PushArr( len ) - 1;

-            memcpy( p, accumulator.Mem(), len+1 );

-        #else

-            int len = vsnprintf( 0, 0, format, va );

-            // Close out and re-start the va-args

-            va_end( va );

-            va_start( va, format );

-            char* p = buffer.PushArr( len ) - 1;

-            vsnprintf( p, len+1, format, va );

-        #endif

+        const int len = TIXML_VSCPRINTF( format, va );

+        // Close out and re-start the va-args

+        va_end( va );

+        TIXMLASSERT( len >= 0 );

+        va_start( va, format );

+        TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );

+        char* p = _buffer.PushArr( len ) - 1;	// back up over the null terminator.

+		TIXML_VSNPRINTF( p, len+1, format, va );

     }

     va_end( va );

 }

 

 

+void XMLPrinter::Write( const char* data, size_t size )

+{

+    if ( _fp ) {

+        fwrite ( data , sizeof(char), size, _fp);

+    }

+    else {

+        char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.

+        memcpy( p, data, size );

+        p[size] = 0;

+    }

+}

+

+

+void XMLPrinter::Putc( char ch )

+{

+    if ( _fp ) {

+        fputc ( ch, _fp);

+    }

+    else {

+        char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.

+        p[0] = ch;

+        p[1] = 0;

+    }

+}

+

+

 void XMLPrinter::PrintSpace( int depth )

 {

     for( int i=0; i<depth; ++i ) {

-        Print( "    " );

+        Write( "    " );

     }

 }

 

@@ -1730,45 +2450,60 @@
 {

     // Look for runs of bytes between entities to print.

     const char* q = p;

-    const bool* flag = restricted ? restrictedEntityFlag : entityFlag;

 

-    if ( processEntities ) {

+    if ( _processEntities ) {

+        const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;

         while ( *q ) {

+            TIXMLASSERT( p <= q );

             // Remember, char is sometimes signed. (How many times has that bitten me?)

             if ( *q > 0 && *q < ENTITY_RANGE ) {

                 // Check for entities. If one is found, flush

                 // the stream up until the entity, write the

                 // entity, and keep looking.

-                if ( flag[(unsigned)(*q)] ) {

+                if ( flag[(unsigned char)(*q)] ) {

                     while ( p < q ) {

-                        Print( "%c", *p );

-                        ++p;

+                        const size_t delta = q - p;

+                        const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;

+                        Write( p, toPrint );

+                        p += toPrint;

                     }

+                    bool entityPatternPrinted = false;

                     for( int i=0; i<NUM_ENTITIES; ++i ) {

                         if ( entities[i].value == *q ) {

-                            Print( "&%s;", entities[i].pattern );

+                            Putc( '&' );

+                            Write( entities[i].pattern, entities[i].length );

+                            Putc( ';' );

+                            entityPatternPrinted = true;

                             break;

                         }

                     }

+                    if ( !entityPatternPrinted ) {

+                        // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release

+                        TIXMLASSERT( false );

+                    }

                     ++p;

                 }

             }

             ++q;

+            TIXMLASSERT( p <= q );

         }

     }

     // Flush the remaining string. This will be the entire

     // string if an entity wasn't found.

-    if ( !processEntities || (q-p > 0) ) {

-        Print( "%s", p );

+    TIXMLASSERT( p <= q );

+    if ( !_processEntities || ( p < q ) ) {

+        const size_t delta = q - p;

+        const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;

+        Write( p, toPrint );

     }

 }

 

 

 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )

 {

-    static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };

     if ( writeBOM ) {

-        Print( "%s", bom );

+        static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };

+        Write( reinterpret_cast< const char* >( bom ) );

     }

     if ( writeDec ) {

         PushDeclaration( "xml version=\"1.0\"" );

@@ -1776,31 +2511,35 @@
 }

 

 

-void XMLPrinter::OpenElement( const char* name )

+void XMLPrinter::OpenElement( const char* name, bool compactMode )

 {

-    if ( elementJustOpened ) {

-        SealElement();

-    }

-    stack.Push( name );

+    SealElementIfJustOpened();

+    _stack.Push( name );

 

-    if ( textDepth < 0 && !firstElement && !compactMode ) {

-        Print( "\n" );

-        PrintSpace( depth );

+    if ( _textDepth < 0 && !_firstElement && !compactMode ) {

+        Putc( '\n' );

+    }

+    if ( !compactMode ) {

+        PrintSpace( _depth );

     }

 

-    Print( "<%s", name );

-    elementJustOpened = true;

-    firstElement = false;

-    ++depth;

+    Write ( "<" );

+    Write ( name );

+

+    _elementJustOpened = true;

+    _firstElement = false;

+    ++_depth;

 }

 

 

 void XMLPrinter::PushAttribute( const char* name, const char* value )

 {

-    TIXMLASSERT( elementJustOpened );

-    Print( " %s=\"", name );

+    TIXMLASSERT( _elementJustOpened );

+    Putc ( ' ' );

+    Write( name );

+    Write( "=\"" );

     PrintString( value, false );

-    Print( "\"" );

+    Putc ( '\"' );

 }

 

 

@@ -1820,6 +2559,14 @@
 }

 

 

+void XMLPrinter::PushAttribute(const char* name, int64_t v)

+{

+	char buf[BUF_SIZE];

+	XMLUtil::ToStr(v, buf, BUF_SIZE);

+	PushAttribute(name, buf);

+}

+

+

 void XMLPrinter::PushAttribute( const char* name, bool v )

 {

     char buf[BUF_SIZE];

@@ -1836,54 +2583,66 @@
 }

 

 

-void XMLPrinter::CloseElement()

+void XMLPrinter::CloseElement( bool compactMode )

 {

-    --depth;

-    const char* name = stack.Pop();

+    --_depth;

+    const char* name = _stack.Pop();

 

-    if ( elementJustOpened ) {

-        Print( "/>" );

+    if ( _elementJustOpened ) {

+        Write( "/>" );

     }

     else {

-        if ( textDepth < 0 && !compactMode) {

-            Print( "\n" );

-            PrintSpace( depth );

+        if ( _textDepth < 0 && !compactMode) {

+            Putc( '\n' );

+            PrintSpace( _depth );

         }

-        Print( "</%s>", name );

+        Write ( "</" );

+        Write ( name );

+        Write ( ">" );

     }

 

-    if ( textDepth == depth )

-        textDepth = -1;

-    if ( depth == 0 && !compactMode)

-        Print( "\n" );

-    elementJustOpened = false;

+    if ( _textDepth == _depth ) {

+        _textDepth = -1;

+    }

+    if ( _depth == 0 && !compactMode) {

+        Putc( '\n' );

+    }

+    _elementJustOpened = false;

 }

 

 

-void XMLPrinter::SealElement()

+void XMLPrinter::SealElementIfJustOpened()

 {

-    elementJustOpened = false;

-    Print( ">" );

+    if ( !_elementJustOpened ) {

+        return;

+    }

+    _elementJustOpened = false;

+    Putc( '>' );

 }

 

 

 void XMLPrinter::PushText( const char* text, bool cdata )

 {

-    textDepth = depth-1;

+    _textDepth = _depth-1;

 

-    if ( elementJustOpened ) {

-        SealElement();

-    }

+    SealElementIfJustOpened();

     if ( cdata ) {

-        Print( "<![CDATA[" );

-        Print( "%s", text );

-        Print( "]]>" );

+        Write( "<![CDATA[" );

+        Write( text );

+        Write( "]]>" );

     }

     else {

         PrintString( text, true );

     }

 }

 

+void XMLPrinter::PushText( int64_t value )

+{

+    char buf[BUF_SIZE];

+    XMLUtil::ToStr( value, buf, BUF_SIZE );

+    PushText( buf, false );

+}

+

 void XMLPrinter::PushText( int value )

 {

     char buf[BUF_SIZE];

@@ -1926,49 +2685,52 @@
 

 void XMLPrinter::PushComment( const char* comment )

 {

-    if ( elementJustOpened ) {

-        SealElement();

+    SealElementIfJustOpened();

+    if ( _textDepth < 0 && !_firstElement && !_compactMode) {

+        Putc( '\n' );

+        PrintSpace( _depth );

     }

-    if ( textDepth < 0 && !firstElement && !compactMode) {

-        Print( "\n" );

-        PrintSpace( depth );

-    }

-    firstElement = false;

-    Print( "<!--%s-->", comment );

+    _firstElement = false;

+

+    Write( "<!--" );

+    Write( comment );

+    Write( "-->" );

 }

 

 

 void XMLPrinter::PushDeclaration( const char* value )

 {

-    if ( elementJustOpened ) {

-        SealElement();

+    SealElementIfJustOpened();

+    if ( _textDepth < 0 && !_firstElement && !_compactMode) {

+        Putc( '\n' );

+        PrintSpace( _depth );

     }

-    if ( textDepth < 0 && !firstElement && !compactMode) {

-        Print( "\n" );

-        PrintSpace( depth );

-    }

-    firstElement = false;

-    Print( "<?%s?>", value );

+    _firstElement = false;

+

+    Write( "<?" );

+    Write( value );

+    Write( "?>" );

 }

 

 

 void XMLPrinter::PushUnknown( const char* value )

 {

-    if ( elementJustOpened ) {

-        SealElement();

+    SealElementIfJustOpened();

+    if ( _textDepth < 0 && !_firstElement && !_compactMode) {

+        Putc( '\n' );

+        PrintSpace( _depth );

     }

-    if ( textDepth < 0 && !firstElement && !compactMode) {

-        Print( "\n" );

-        PrintSpace( depth );

-    }

-    firstElement = false;

-    Print( "<!%s>", value );

+    _firstElement = false;

+

+    Write( "<!" );

+    Write( value );

+    Putc( '>' );

 }

 

 

 bool XMLPrinter::VisitEnter( const XMLDocument& doc )

 {

-    processEntities = doc.ProcessEntities();

+    _processEntities = doc.ProcessEntities();

     if ( doc.HasBOM() ) {

         PushHeader( true, false );

     }

@@ -1978,7 +2740,12 @@
 

 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )

 {

-    OpenElement( element.Name() );

+    const XMLElement* parentElem = 0;

+    if ( element.Parent() ) {

+        parentElem = element.Parent()->ToElement();

+    }

+    const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;

+    OpenElement( element.Name(), compactMode );

     while ( attribute ) {

         PushAttribute( attribute->Name(), attribute->Value() );

         attribute = attribute->Next();

@@ -1987,9 +2754,9 @@
 }

 

 

-bool XMLPrinter::VisitExit( const XMLElement& )

+bool XMLPrinter::VisitExit( const XMLElement& element )

 {

-    CloseElement();

+    CloseElement( CompactMode(element) );

     return true;

 }

 

@@ -2019,3 +2786,6 @@
     PushUnknown( unknown.Value() );

     return true;

 }

+

+}   // namespace tinyxml2

+