Back to home page

EIC code displayed by LXR

 
 

    


Warning, file /pfRICH/Visualization/tinyxml2.cpp was not indexed or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).

0001 /*

0002 Original code by Lee Thomason (www.grinninglizard.com)

0003 

0004 This software is provided 'as-is', without any express or implied

0005 warranty. In no event will the authors be held liable for any

0006 damages arising from the use of this software.

0007 

0008 Permission is granted to anyone to use this software for any

0009 purpose, including commercial applications, and to alter it and

0010 redistribute it freely, subject to the following restrictions:

0011 

0012 1. The origin of this software must not be misrepresented; you must

0013 not claim that you wrote the original software. If you use this

0014 software in a product, an acknowledgment in the product documentation

0015 would be appreciated but is not required.

0016 

0017 2. Altered source versions must be plainly marked as such, and

0018 must not be misrepresented as being the original software.

0019 

0020 3. This notice may not be removed or altered from any source

0021 distribution.

0022 */
0023 
0024 #include "tinyxml2.h"
0025 
0026 #include <new>      // yes, this one new style header, is in the Android SDK.
0027 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
0028 #   include <stddef.h>
0029 #   include <stdarg.h>
0030 #else
0031 #   include <cstddef>
0032 #   include <cstdarg>
0033 #endif
0034 
0035 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
0036     // Microsoft Visual Studio, version 2005 and higher. Not WinCE.

0037     /*int _snprintf_s(

0038        char *buffer,

0039        size_t sizeOfBuffer,

0040        size_t count,

0041        const char *format [,

0042           argument] ...

0043     );*/
0044     static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
0045     {
0046         va_list va;
0047         va_start( va, format );
0048         const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
0049         va_end( va );
0050         return result;
0051     }
0052 
0053     static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
0054     {
0055         const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
0056         return result;
0057     }
0058 
0059     #define TIXML_VSCPRINTF _vscprintf
0060     #define TIXML_SSCANF    sscanf_s
0061 #elif defined _MSC_VER
0062     // Microsoft Visual Studio 2003 and earlier or WinCE

0063     #define TIXML_SNPRINTF  _snprintf
0064     #define TIXML_VSNPRINTF _vsnprintf
0065     #define TIXML_SSCANF    sscanf
0066     #if (_MSC_VER < 1400 ) && (!defined WINCE)
0067         // Microsoft Visual Studio 2003 and not WinCE.

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

0069     #else
0070         // Microsoft Visual Studio 2003 and earlier or WinCE.

0071         static inline int TIXML_VSCPRINTF( const char* format, va_list va )
0072         {
0073             int len = 512;
0074             for (;;) {
0075                 len = len*2;
0076                 char* str = new char[len]();
0077                 const int required = _vsnprintf(str, len, format, va);
0078                 delete[] str;
0079                 if ( required != -1 ) {
0080                     TIXMLASSERT( required >= 0 );
0081                     len = required;
0082                     break;
0083                 }
0084             }
0085             TIXMLASSERT( len >= 0 );
0086             return len;
0087         }
0088     #endif
0089 #else
0090     // GCC version 3 and higher

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

0092     #define TIXML_SNPRINTF  snprintf
0093     #define TIXML_VSNPRINTF vsnprintf
0094     static inline int TIXML_VSCPRINTF( const char* format, va_list va )
0095     {
0096         int len = vsnprintf( 0, 0, format, va );
0097         TIXMLASSERT( len >= 0 );
0098         return len;
0099     }
0100     #define TIXML_SSCANF   sscanf
0101 #endif
0102 
0103 #if defined(_WIN64)
0104     #define TIXML_FSEEK _fseeki64
0105     #define TIXML_FTELL _ftelli64
0106 #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || (__CYGWIN__)
0107     #define TIXML_FSEEK fseeko
0108     #define TIXML_FTELL ftello
0109 #elif defined(__ANDROID__) 
0110     #if __ANDROID_API__ > 24
0111         #define TIXML_FSEEK fseeko64
0112         #define TIXML_FTELL ftello64
0113     #else
0114         #define TIXML_FSEEK fseeko
0115         #define TIXML_FTELL ftello
0116     #endif
0117 #elif defined(__unix__) && defined(__x86_64__)
0118     #define TIXML_FSEEK fseeko64
0119     #define TIXML_FTELL ftello64
0120 #else
0121     #define TIXML_FSEEK fseek
0122     #define TIXML_FTELL ftell
0123 #endif
0124 
0125 
0126 static const char LINE_FEED             = static_cast<char>(0x0a);          // all line endings are normalized to LF

0127 static const char LF = LINE_FEED;
0128 static const char CARRIAGE_RETURN       = static_cast<char>(0x0d);          // CR gets filtered out

0129 static const char CR = CARRIAGE_RETURN;
0130 static const char SINGLE_QUOTE          = '\'';
0131 static const char DOUBLE_QUOTE          = '\"';
0132 
0133 // Bunch of unicode info at:

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

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

0136 
0137 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
0138 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
0139 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
0140 
0141 namespace tinyxml2
0142 {
0143 
0144 struct Entity {
0145     const char* pattern;
0146     int length;
0147     char value;
0148 };
0149 
0150 static const int NUM_ENTITIES = 5;
0151 static const Entity entities[NUM_ENTITIES] = {
0152     { "quot", 4,    DOUBLE_QUOTE },
0153     { "amp", 3,     '&'  },
0154     { "apos", 4,    SINGLE_QUOTE },
0155     { "lt", 2,      '<'  },
0156     { "gt", 2,      '>'  }
0157 };
0158 
0159 
0160 StrPair::~StrPair()
0161 {
0162     Reset();
0163 }
0164 
0165 
0166 void StrPair::TransferTo( StrPair* other )
0167 {
0168     if ( this == other ) {
0169         return;
0170     }
0171     // This in effect implements the assignment operator by "moving"

0172     // ownership (as in auto_ptr).

0173 
0174     TIXMLASSERT( other != 0 );
0175     TIXMLASSERT( other->_flags == 0 );
0176     TIXMLASSERT( other->_start == 0 );
0177     TIXMLASSERT( other->_end == 0 );
0178 
0179     other->Reset();
0180 
0181     other->_flags = _flags;
0182     other->_start = _start;
0183     other->_end = _end;
0184 
0185     _flags = 0;
0186     _start = 0;
0187     _end = 0;
0188 }
0189 
0190 
0191 void StrPair::Reset()
0192 {
0193     if ( _flags & NEEDS_DELETE ) {
0194         delete [] _start;
0195     }
0196     _flags = 0;
0197     _start = 0;
0198     _end = 0;
0199 }
0200 
0201 
0202 void StrPair::SetStr( const char* str, int flags )
0203 {
0204     TIXMLASSERT( str );
0205     Reset();
0206     size_t len = strlen( str );
0207     TIXMLASSERT( _start == 0 );
0208     _start = new char[ len+1 ];
0209     memcpy( _start, str, len+1 );
0210     _end = _start + len;
0211     _flags = flags | NEEDS_DELETE;
0212 }
0213 
0214 
0215 char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
0216 {
0217     TIXMLASSERT( p );
0218     TIXMLASSERT( endTag && *endTag );
0219     TIXMLASSERT(curLineNumPtr);
0220 
0221     char* start = p;
0222     const char  endChar = *endTag;
0223     size_t length = strlen( endTag );
0224 
0225     // Inner loop of text parsing.

0226     while ( *p ) {
0227         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
0228             Set( start, p, strFlags );
0229             return p + length;
0230         } else if (*p == '\n') {
0231             ++(*curLineNumPtr);
0232         }
0233         ++p;
0234         TIXMLASSERT( p );
0235     }
0236     return 0;
0237 }
0238 
0239 
0240 char* StrPair::ParseName( char* p )
0241 {
0242     if ( !p || !(*p) ) {
0243         return 0;
0244     }
0245     if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
0246         return 0;
0247     }
0248 
0249     char* const start = p;
0250     ++p;
0251     while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {
0252         ++p;
0253     }
0254 
0255     Set( start, p, 0 );
0256     return p;
0257 }
0258 
0259 
0260 void StrPair::CollapseWhitespace()
0261 {
0262     // Adjusting _start would cause undefined behavior on delete[]

0263     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
0264     // Trim leading space.

0265     _start = XMLUtil::SkipWhiteSpace( _start, 0 );
0266 
0267     if ( *_start ) {
0268         const char* p = _start; // the read pointer

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

0270 
0271         while( *p ) {
0272             if ( XMLUtil::IsWhiteSpace( *p )) {
0273                 p = XMLUtil::SkipWhiteSpace( p, 0 );
0274                 if ( *p == 0 ) {
0275                     break;    // don't write to q; this trims the trailing space.

0276                 }
0277                 *q = ' ';
0278                 ++q;
0279             }
0280             *q = *p;
0281             ++q;
0282             ++p;
0283         }
0284         *q = 0;
0285     }
0286 }
0287 
0288 
0289 const char* StrPair::GetStr()
0290 {
0291     TIXMLASSERT( _start );
0292     TIXMLASSERT( _end );
0293     if ( _flags & NEEDS_FLUSH ) {
0294         *_end = 0;
0295         _flags ^= NEEDS_FLUSH;
0296 
0297         if ( _flags ) {
0298             const char* p = _start; // the read pointer

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

0300 
0301             while( p < _end ) {
0302                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
0303                     // CR-LF pair becomes LF

0304                     // CR alone becomes LF

0305                     // LF-CR becomes LF

0306                     if ( *(p+1) == LF ) {
0307                         p += 2;
0308                     }
0309                     else {
0310                         ++p;
0311                     }
0312                     *q = LF;
0313                     ++q;
0314                 }
0315                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
0316                     if ( *(p+1) == CR ) {
0317                         p += 2;
0318                     }
0319                     else {
0320                         ++p;
0321                     }
0322                     *q = LF;
0323                     ++q;
0324                 }
0325                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
0326                     // Entities handled by tinyXML2:

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

0328                     // - numeric character reference [in]

0329                     //   &#20013; or &#x4e2d;

0330 
0331                     if ( *(p+1) == '#' ) {
0332                         const int buflen = 10;
0333                         char buf[buflen] = { 0 };
0334                         int len = 0;
0335                         const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
0336                         if ( adjusted == 0 ) {
0337                             *q = *p;
0338                             ++p;
0339                             ++q;
0340                         }
0341                         else {
0342                             TIXMLASSERT( 0 <= len && len <= buflen );
0343                             TIXMLASSERT( q + len <= adjusted );
0344                             p = adjusted;
0345                             memcpy( q, buf, len );
0346                             q += len;
0347                         }
0348                     }
0349                     else {
0350                         bool entityFound = false;
0351                         for( int i = 0; i < NUM_ENTITIES; ++i ) {
0352                             const Entity& entity = entities[i];
0353                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
0354                                     && *( p + entity.length + 1 ) == ';' ) {
0355                                 // Found an entity - convert.

0356                                 *q = entity.value;
0357                                 ++q;
0358                                 p += entity.length + 2;
0359                                 entityFound = true;
0360                                 break;
0361                             }
0362                         }
0363                         if ( !entityFound ) {
0364                             // fixme: treat as error?

0365                             ++p;
0366                             ++q;
0367                         }
0368                     }
0369                 }
0370                 else {
0371                     *q = *p;
0372                     ++p;
0373                     ++q;
0374                 }
0375             }
0376             *q = 0;
0377         }
0378         // The loop below has plenty going on, and this

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

0380         if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
0381             CollapseWhitespace();
0382         }
0383         _flags = (_flags & NEEDS_DELETE);
0384     }
0385     TIXMLASSERT( _start );
0386     return _start;
0387 }
0388 
0389 
0390 
0391 
0392 // --------- XMLUtil ----------- //

0393 
0394 const char* XMLUtil::writeBoolTrue  = "true";
0395 const char* XMLUtil::writeBoolFalse = "false";
0396 
0397 void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
0398 {
0399     static const char* defTrue  = "true";
0400     static const char* defFalse = "false";
0401 
0402     writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
0403     writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
0404 }
0405 
0406 
0407 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
0408 {
0409     TIXMLASSERT( p );
0410     TIXMLASSERT( bom );
0411     *bom = false;
0412     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
0413     // Check for BOM:

0414     if (    *(pu+0) == TIXML_UTF_LEAD_0
0415             && *(pu+1) == TIXML_UTF_LEAD_1
0416             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
0417         *bom = true;
0418         p += 3;
0419     }
0420     TIXMLASSERT( p );
0421     return p;
0422 }
0423 
0424 
0425 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
0426 {
0427     const unsigned long BYTE_MASK = 0xBF;
0428     const unsigned long BYTE_MARK = 0x80;
0429     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
0430 
0431     if (input < 0x80) {
0432         *length = 1;
0433     }
0434     else if ( input < 0x800 ) {
0435         *length = 2;
0436     }
0437     else if ( input < 0x10000 ) {
0438         *length = 3;
0439     }
0440     else if ( input < 0x200000 ) {
0441         *length = 4;
0442     }
0443     else {
0444         *length = 0;    // This code won't convert this correctly anyway.

0445         return;
0446     }
0447 
0448     output += *length;
0449 
0450     // Scary scary fall throughs are annotated with carefully designed comments

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

0452     switch (*length) {
0453         case 4:
0454             --output;
0455             *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
0456             input >>= 6;
0457             //fall through

0458         case 3:
0459             --output;
0460             *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
0461             input >>= 6;
0462             //fall through

0463         case 2:
0464             --output;
0465             *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
0466             input >>= 6;
0467             //fall through

0468         case 1:
0469             --output;
0470             *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
0471             break;
0472         default:
0473             TIXMLASSERT( false );
0474     }
0475 }
0476 
0477 
0478 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
0479 {
0480     // Presume an entity, and pull it out.

0481     *length = 0;
0482 
0483     if ( *(p+1) == '#' && *(p+2) ) {
0484         unsigned long ucs = 0;
0485         TIXMLASSERT( sizeof( ucs ) >= 4 );
0486         ptrdiff_t delta = 0;
0487         unsigned mult = 1;
0488         static const char SEMICOLON = ';';
0489 
0490         if ( *(p+2) == 'x' ) {
0491             // Hexadecimal.

0492             const char* q = p+3;
0493             if ( !(*q) ) {
0494                 return 0;
0495             }
0496 
0497             q = strchr( q, SEMICOLON );
0498 
0499             if ( !q ) {
0500                 return 0;
0501             }
0502             TIXMLASSERT( *q == SEMICOLON );
0503 
0504             delta = q-p;
0505             --q;
0506 
0507             while ( *q != 'x' ) {
0508                 unsigned int digit = 0;
0509 
0510                 if ( *q >= '0' && *q <= '9' ) {
0511                     digit = *q - '0';
0512                 }
0513                 else if ( *q >= 'a' && *q <= 'f' ) {
0514                     digit = *q - 'a' + 10;
0515                 }
0516                 else if ( *q >= 'A' && *q <= 'F' ) {
0517                     digit = *q - 'A' + 10;
0518                 }
0519                 else {
0520                     return 0;
0521                 }
0522                 TIXMLASSERT( digit < 16 );
0523                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
0524                 const unsigned int digitScaled = mult * digit;
0525                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
0526                 ucs += digitScaled;
0527                 TIXMLASSERT( mult <= UINT_MAX / 16 );
0528                 mult *= 16;
0529                 --q;
0530             }
0531         }
0532         else {
0533             // Decimal.

0534             const char* q = p+2;
0535             if ( !(*q) ) {
0536                 return 0;
0537             }
0538 
0539             q = strchr( q, SEMICOLON );
0540 
0541             if ( !q ) {
0542                 return 0;
0543             }
0544             TIXMLASSERT( *q == SEMICOLON );
0545 
0546             delta = q-p;
0547             --q;
0548 
0549             while ( *q != '#' ) {
0550                 if ( *q >= '0' && *q <= '9' ) {
0551                     const unsigned int digit = *q - '0';
0552                     TIXMLASSERT( digit < 10 );
0553                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
0554                     const unsigned int digitScaled = mult * digit;
0555                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
0556                     ucs += digitScaled;
0557                 }
0558                 else {
0559                     return 0;
0560                 }
0561                 TIXMLASSERT( mult <= UINT_MAX / 10 );
0562                 mult *= 10;
0563                 --q;
0564             }
0565         }
0566         // convert the UCS to UTF-8

0567         ConvertUTF32ToUTF8( ucs, value, length );
0568         return p + delta + 1;
0569     }
0570     return p+1;
0571 }
0572 
0573 
0574 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
0575 {
0576     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
0577 }
0578 
0579 
0580 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
0581 {
0582     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
0583 }
0584 
0585 
0586 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
0587 {
0588     TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
0589 }
0590 
0591 /*

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

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

0594 */
0595 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
0596 {
0597     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
0598 }
0599 
0600 
0601 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
0602 {
0603     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
0604 }
0605 
0606 
0607 void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
0608 {
0609     // horrible syntax trick to make the compiler happy about %lld

0610     TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v));
0611 }
0612 
0613 void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
0614 {
0615     // horrible syntax trick to make the compiler happy about %llu

0616     TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v);
0617 }
0618 
0619 bool XMLUtil::ToInt(const char* str, int* value)
0620 {
0621     if (IsPrefixHex(str)) {
0622         unsigned v;
0623         if (TIXML_SSCANF(str, "%x", &v) == 1) {
0624             *value = static_cast<int>(v);
0625             return true;
0626         }
0627     }
0628     else {
0629         if (TIXML_SSCANF(str, "%d", value) == 1) {
0630             return true;
0631         }
0632     }
0633     return false;
0634 }
0635 
0636 bool XMLUtil::ToUnsigned(const char* str, unsigned* value)
0637 {
0638     if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) {
0639         return true;
0640     }
0641     return false;
0642 }
0643 
0644 bool XMLUtil::ToBool( const char* str, bool* value )
0645 {
0646     int ival = 0;
0647     if ( ToInt( str, &ival )) {
0648         *value = (ival==0) ? false : true;
0649         return true;
0650     }
0651     static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 };
0652     static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 };
0653 
0654     for (int i = 0; TRUE_VALS[i]; ++i) {
0655         if (StringEqual(str, TRUE_VALS[i])) {
0656             *value = true;
0657             return true;
0658         }
0659     }
0660     for (int i = 0; FALSE_VALS[i]; ++i) {
0661         if (StringEqual(str, FALSE_VALS[i])) {
0662             *value = false;
0663             return true;
0664         }
0665     }
0666     return false;
0667 }
0668 
0669 
0670 bool XMLUtil::ToFloat( const char* str, float* value )
0671 {
0672     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
0673         return true;
0674     }
0675     return false;
0676 }
0677 
0678 
0679 bool XMLUtil::ToDouble( const char* str, double* value )
0680 {
0681     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
0682         return true;
0683     }
0684     return false;
0685 }
0686 
0687 
0688 bool XMLUtil::ToInt64(const char* str, int64_t* value)
0689 {
0690     if (IsPrefixHex(str)) {
0691         unsigned long long v = 0;   // horrible syntax trick to make the compiler happy about %llx

0692         if (TIXML_SSCANF(str, "%llx", &v) == 1) {
0693             *value = static_cast<int64_t>(v);
0694             return true;
0695         }
0696     }
0697     else {
0698         long long v = 0;    // horrible syntax trick to make the compiler happy about %lld

0699         if (TIXML_SSCANF(str, "%lld", &v) == 1) {
0700             *value = static_cast<int64_t>(v);
0701             return true;
0702         }
0703     }
0704     return false;
0705 }
0706 
0707 
0708 bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
0709     unsigned long long v = 0;   // horrible syntax trick to make the compiler happy about %llu

0710     if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
0711         *value = (uint64_t)v;
0712         return true;
0713     }
0714     return false;
0715 }
0716 
0717 
0718 char* XMLDocument::Identify( char* p, XMLNode** node )
0719 {
0720     TIXMLASSERT( node );
0721     TIXMLASSERT( p );
0722     char* const start = p;
0723     int const startLine = _parseCurLineNum;
0724     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
0725     if( !*p ) {
0726         *node = 0;
0727         TIXMLASSERT( p );
0728         return p;
0729     }
0730 
0731     // These strings define the matching patterns:

0732     static const char* xmlHeader        = { "<?" };
0733     static const char* commentHeader    = { "<!--" };
0734     static const char* cdataHeader      = { "<![CDATA[" };
0735     static const char* dtdHeader        = { "<!" };
0736     static const char* elementHeader    = { "<" };  // and a header for everything else; check last.

0737 
0738     static const int xmlHeaderLen       = 2;
0739     static const int commentHeaderLen   = 4;
0740     static const int cdataHeaderLen     = 9;
0741     static const int dtdHeaderLen       = 2;
0742     static const int elementHeaderLen   = 1;
0743 
0744     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );        // use same memory pool

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

0746     XMLNode* returnNode = 0;
0747     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
0748         returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
0749         returnNode->_parseLineNum = _parseCurLineNum;
0750         p += xmlHeaderLen;
0751     }
0752     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
0753         returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
0754         returnNode->_parseLineNum = _parseCurLineNum;
0755         p += commentHeaderLen;
0756     }
0757     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
0758         XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
0759         returnNode = text;
0760         returnNode->_parseLineNum = _parseCurLineNum;
0761         p += cdataHeaderLen;
0762         text->SetCData( true );
0763     }
0764     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
0765         returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
0766         returnNode->_parseLineNum = _parseCurLineNum;
0767         p += dtdHeaderLen;
0768     }
0769     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
0770         returnNode =  CreateUnlinkedNode<XMLElement>( _elementPool );
0771         returnNode->_parseLineNum = _parseCurLineNum;
0772         p += elementHeaderLen;
0773     }
0774     else {
0775         returnNode = CreateUnlinkedNode<XMLText>( _textPool );
0776         returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character

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

0778         _parseCurLineNum = startLine;
0779     }
0780 
0781     TIXMLASSERT( returnNode );
0782     TIXMLASSERT( p );
0783     *node = returnNode;
0784     return p;
0785 }
0786 
0787 
0788 bool XMLDocument::Accept( XMLVisitor* visitor ) const
0789 {
0790     TIXMLASSERT( visitor );
0791     if ( visitor->VisitEnter( *this ) ) {
0792         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
0793             if ( !node->Accept( visitor ) ) {
0794                 break;
0795             }
0796         }
0797     }
0798     return visitor->VisitExit( *this );
0799 }
0800 
0801 
0802 // --------- XMLNode ----------- //

0803 
0804 XMLNode::XMLNode( XMLDocument* doc ) :
0805     _document( doc ),
0806     _parent( 0 ),
0807     _value(),
0808     _parseLineNum( 0 ),
0809     _firstChild( 0 ), _lastChild( 0 ),
0810     _prev( 0 ), _next( 0 ),
0811     _userData( 0 ),
0812     _memPool( 0 )
0813 {
0814 }
0815 
0816 
0817 XMLNode::~XMLNode()
0818 {
0819     DeleteChildren();
0820     if ( _parent ) {
0821         _parent->Unlink( this );
0822     }
0823 }
0824 
0825 const char* XMLNode::Value() const
0826 {
0827     // Edge case: XMLDocuments don't have a Value. Return null.

0828     if ( this->ToDocument() )
0829         return 0;
0830     return _value.GetStr();
0831 }
0832 
0833 void XMLNode::SetValue( const char* str, bool staticMem )
0834 {
0835     if ( staticMem ) {
0836         _value.SetInternedStr( str );
0837     }
0838     else {
0839         _value.SetStr( str );
0840     }
0841 }
0842 
0843 XMLNode* XMLNode::DeepClone(XMLDocument* target) const
0844 {
0845     XMLNode* clone = this->ShallowClone(target);
0846     if (!clone) return 0;
0847 
0848     for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
0849         XMLNode* childClone = child->DeepClone(target);
0850         TIXMLASSERT(childClone);
0851         clone->InsertEndChild(childClone);
0852     }
0853     return clone;
0854 }
0855 
0856 void XMLNode::DeleteChildren()
0857 {
0858     while( _firstChild ) {
0859         TIXMLASSERT( _lastChild );
0860         DeleteChild( _firstChild );
0861     }
0862     _firstChild = _lastChild = 0;
0863 }
0864 
0865 
0866 void XMLNode::Unlink( XMLNode* child )
0867 {
0868     TIXMLASSERT( child );
0869     TIXMLASSERT( child->_document == _document );
0870     TIXMLASSERT( child->_parent == this );
0871     if ( child == _firstChild ) {
0872         _firstChild = _firstChild->_next;
0873     }
0874     if ( child == _lastChild ) {
0875         _lastChild = _lastChild->_prev;
0876     }
0877 
0878     if ( child->_prev ) {
0879         child->_prev->_next = child->_next;
0880     }
0881     if ( child->_next ) {
0882         child->_next->_prev = child->_prev;
0883     }
0884     child->_next = 0;
0885     child->_prev = 0;
0886     child->_parent = 0;
0887 }
0888 
0889 
0890 void XMLNode::DeleteChild( XMLNode* node )
0891 {
0892     TIXMLASSERT( node );
0893     TIXMLASSERT( node->_document == _document );
0894     TIXMLASSERT( node->_parent == this );
0895     Unlink( node );
0896     TIXMLASSERT(node->_prev == 0);
0897     TIXMLASSERT(node->_next == 0);
0898     TIXMLASSERT(node->_parent == 0);
0899     DeleteNode( node );
0900 }
0901 
0902 
0903 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
0904 {
0905     TIXMLASSERT( addThis );
0906     if ( addThis->_document != _document ) {
0907         TIXMLASSERT( false );
0908         return 0;
0909     }
0910     InsertChildPreamble( addThis );
0911 
0912     if ( _lastChild ) {
0913         TIXMLASSERT( _firstChild );
0914         TIXMLASSERT( _lastChild->_next == 0 );
0915         _lastChild->_next = addThis;
0916         addThis->_prev = _lastChild;
0917         _lastChild = addThis;
0918 
0919         addThis->_next = 0;
0920     }
0921     else {
0922         TIXMLASSERT( _firstChild == 0 );
0923         _firstChild = _lastChild = addThis;
0924 
0925         addThis->_prev = 0;
0926         addThis->_next = 0;
0927     }
0928     addThis->_parent = this;
0929     return addThis;
0930 }
0931 
0932 
0933 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
0934 {
0935     TIXMLASSERT( addThis );
0936     if ( addThis->_document != _document ) {
0937         TIXMLASSERT( false );
0938         return 0;
0939     }
0940     InsertChildPreamble( addThis );
0941 
0942     if ( _firstChild ) {
0943         TIXMLASSERT( _lastChild );
0944         TIXMLASSERT( _firstChild->_prev == 0 );
0945 
0946         _firstChild->_prev = addThis;
0947         addThis->_next = _firstChild;
0948         _firstChild = addThis;
0949 
0950         addThis->_prev = 0;
0951     }
0952     else {
0953         TIXMLASSERT( _lastChild == 0 );
0954         _firstChild = _lastChild = addThis;
0955 
0956         addThis->_prev = 0;
0957         addThis->_next = 0;
0958     }
0959     addThis->_parent = this;
0960     return addThis;
0961 }
0962 
0963 
0964 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
0965 {
0966     TIXMLASSERT( addThis );
0967     if ( addThis->_document != _document ) {
0968         TIXMLASSERT( false );
0969         return 0;
0970     }
0971 
0972     TIXMLASSERT( afterThis );
0973 
0974     if ( afterThis->_parent != this ) {
0975         TIXMLASSERT( false );
0976         return 0;
0977     }
0978     if ( afterThis == addThis ) {
0979         // Current state: BeforeThis -> AddThis -> OneAfterAddThis

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

0981         // reappear between BeforeThis and OneAfterAddThis.

0982         // So just leave it where it is.

0983         return addThis;
0984     }
0985 
0986     if ( afterThis->_next == 0 ) {
0987         // The last node or the only node.

0988         return InsertEndChild( addThis );
0989     }
0990     InsertChildPreamble( addThis );
0991     addThis->_prev = afterThis;
0992     addThis->_next = afterThis->_next;
0993     afterThis->_next->_prev = addThis;
0994     afterThis->_next = addThis;
0995     addThis->_parent = this;
0996     return addThis;
0997 }
0998 
0999 
1000 
1001 
1002 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
1003 {
1004     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
1005         const XMLElement* element = node->ToElementWithName( name );
1006         if ( element ) {
1007             return element;
1008         }
1009     }
1010     return 0;
1011 }
1012 
1013 
1014 const XMLElement* XMLNode::LastChildElement( const char* name ) const
1015 {
1016     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
1017         const XMLElement* element = node->ToElementWithName( name );
1018         if ( element ) {
1019             return element;
1020         }
1021     }
1022     return 0;
1023 }
1024 
1025 
1026 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
1027 {
1028     for( const XMLNode* node = _next; node; node = node->_next ) {
1029         const XMLElement* element = node->ToElementWithName( name );
1030         if ( element ) {
1031             return element;
1032         }
1033     }
1034     return 0;
1035 }
1036 
1037 
1038 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
1039 {
1040     for( const XMLNode* node = _prev; node; node = node->_prev ) {
1041         const XMLElement* element = node->ToElementWithName( name );
1042         if ( element ) {
1043             return element;
1044         }
1045     }
1046     return 0;
1047 }
1048 
1049 
1050 char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
1051 {
1052     // This is a recursive method, but thinking about it "at the current level"

1053     // it is a pretty simple flat list:

1054     //      <foo/>

1055     //      <!-- comment -->

1056     //

1057     // With a special case:

1058     //      <foo>

1059     //      </foo>

1060     //      <!-- comment -->

1061     //

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

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

1064     // element will be read by the child.

1065     //

1066     // 'endTag' is the end tag for this node, it is returned by a call to a child.

1067     // 'parentEnd' is the end tag for the parent, which is filled in and returned.

1068 
1069     XMLDocument::DepthTracker tracker(_document);
1070     if (_document->Error())
1071         return 0;
1072 
1073     while( p && *p ) {
1074         XMLNode* node = 0;
1075 
1076         p = _document->Identify( p, &node );
1077         TIXMLASSERT( p );
1078         if ( node == 0 ) {
1079             break;
1080         }
1081 
1082        const int initialLineNum = node->_parseLineNum;
1083 
1084         StrPair endTag;
1085         p = node->ParseDeep( p, &endTag, curLineNumPtr );
1086         if ( !p ) {
1087             _document->DeleteNode( node );
1088             if ( !_document->Error() ) {
1089                 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1090             }
1091             break;
1092         }
1093 
1094         const XMLDeclaration* const decl = node->ToDeclaration();
1095         if ( decl ) {
1096             // Declarations are only allowed at document level

1097             //

1098             // Multiple declarations are allowed but all declarations

1099             // must occur before anything else. 

1100             //

1101             // Optimized due to a security test case. If the first node is 

1102             // a declaration, and the last node is a declaration, then only 

1103             // declarations have so far been added.

1104             bool wellLocated = false;
1105 
1106             if (ToDocument()) {
1107                 if (FirstChild()) {
1108                     wellLocated =
1109                         FirstChild() &&
1110                         FirstChild()->ToDeclaration() &&
1111                         LastChild() &&
1112                         LastChild()->ToDeclaration();
1113                 }
1114                 else {
1115                     wellLocated = true;
1116                 }
1117             }
1118             if ( !wellLocated ) {
1119                 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1120                 _document->DeleteNode( node );
1121                 break;
1122             }
1123         }
1124 
1125         XMLElement* ele = node->ToElement();
1126         if ( ele ) {
1127             // We read the end tag. Return it to the parent.

1128             if ( ele->ClosingType() == XMLElement::CLOSING ) {
1129                 if ( parentEndTag ) {
1130                     ele->_value.TransferTo( parentEndTag );
1131                 }
1132                 node->_memPool->SetTracked();   // created and then immediately deleted.

1133                 DeleteNode( node );
1134                 return p;
1135             }
1136 
1137             // Handle an end tag returned to this level.

1138             // And handle a bunch of annoying errors.

1139             bool mismatch = false;
1140             if ( endTag.Empty() ) {
1141                 if ( ele->ClosingType() == XMLElement::OPEN ) {
1142                     mismatch = true;
1143                 }
1144             }
1145             else {
1146                 if ( ele->ClosingType() != XMLElement::OPEN ) {
1147                     mismatch = true;
1148                 }
1149                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1150                     mismatch = true;
1151                 }
1152             }
1153             if ( mismatch ) {
1154                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1155                 _document->DeleteNode( node );
1156                 break;
1157             }
1158         }
1159         InsertEndChild( node );
1160     }
1161     return 0;
1162 }
1163 
1164 /*static*/ void XMLNode::DeleteNode( XMLNode* node )
1165 {
1166     if ( node == 0 ) {
1167         return;
1168     }
1169     TIXMLASSERT(node->_document);
1170     if (!node->ToDocument()) {
1171         node->_document->MarkInUse(node);
1172     }
1173 
1174     MemPool* pool = node->_memPool;
1175     node->~XMLNode();
1176     pool->Free( node );
1177 }
1178 
1179 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1180 {
1181     TIXMLASSERT( insertThis );
1182     TIXMLASSERT( insertThis->_document == _document );
1183 
1184     if (insertThis->_parent) {
1185         insertThis->_parent->Unlink( insertThis );
1186     }
1187     else {
1188         insertThis->_document->MarkInUse(insertThis);
1189         insertThis->_memPool->SetTracked();
1190     }
1191 }
1192 
1193 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1194 {
1195     const XMLElement* element = this->ToElement();
1196     if ( element == 0 ) {
1197         return 0;
1198     }
1199     if ( name == 0 ) {
1200         return element;
1201     }
1202     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1203        return element;
1204     }
1205     return 0;
1206 }
1207 
1208 // --------- XMLText ---------- //

1209 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1210 {
1211     if ( this->CData() ) {
1212         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1213         if ( !p ) {
1214             _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1215         }
1216         return p;
1217     }
1218     else {
1219         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1220         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1221             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1222         }
1223 
1224         p = _value.ParseText( p, "<", flags, curLineNumPtr );
1225         if ( p && *p ) {
1226             return p-1;
1227         }
1228         if ( !p ) {
1229             _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1230         }
1231     }
1232     return 0;
1233 }
1234 
1235 
1236 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1237 {
1238     if ( !doc ) {
1239         doc = _document;
1240     }
1241     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?

1242     text->SetCData( this->CData() );
1243     return text;
1244 }
1245 
1246 
1247 bool XMLText::ShallowEqual( const XMLNode* compare ) const
1248 {
1249     TIXMLASSERT( compare );
1250     const XMLText* text = compare->ToText();
1251     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1252 }
1253 
1254 
1255 bool XMLText::Accept( XMLVisitor* visitor ) const
1256 {
1257     TIXMLASSERT( visitor );
1258     return visitor->Visit( *this );
1259 }
1260 
1261 
1262 // --------- XMLComment ---------- //

1263 
1264 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1265 {
1266 }
1267 
1268 
1269 XMLComment::~XMLComment()
1270 {
1271 }
1272 
1273 
1274 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1275 {
1276     // Comment parses as text.

1277     p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1278     if ( p == 0 ) {
1279         _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1280     }
1281     return p;
1282 }
1283 
1284 
1285 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1286 {
1287     if ( !doc ) {
1288         doc = _document;
1289     }
1290     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?

1291     return comment;
1292 }
1293 
1294 
1295 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1296 {
1297     TIXMLASSERT( compare );
1298     const XMLComment* comment = compare->ToComment();
1299     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1300 }
1301 
1302 
1303 bool XMLComment::Accept( XMLVisitor* visitor ) const
1304 {
1305     TIXMLASSERT( visitor );
1306     return visitor->Visit( *this );
1307 }
1308 
1309 
1310 // --------- XMLDeclaration ---------- //

1311 
1312 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1313 {
1314 }
1315 
1316 
1317 XMLDeclaration::~XMLDeclaration()
1318 {
1319     //printf( "~XMLDeclaration\n" );

1320 }
1321 
1322 
1323 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1324 {
1325     // Declaration parses as text.

1326     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1327     if ( p == 0 ) {
1328         _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1329     }
1330     return p;
1331 }
1332 
1333 
1334 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1335 {
1336     if ( !doc ) {
1337         doc = _document;
1338     }
1339     XMLDeclaration* dec = doc->NewDeclaration( Value() );   // fixme: this will always allocate memory. Intern?

1340     return dec;
1341 }
1342 
1343 
1344 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1345 {
1346     TIXMLASSERT( compare );
1347     const XMLDeclaration* declaration = compare->ToDeclaration();
1348     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1349 }
1350 
1351 
1352 
1353 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1354 {
1355     TIXMLASSERT( visitor );
1356     return visitor->Visit( *this );
1357 }
1358 
1359 // --------- XMLUnknown ---------- //

1360 
1361 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1362 {
1363 }
1364 
1365 
1366 XMLUnknown::~XMLUnknown()
1367 {
1368 }
1369 
1370 
1371 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1372 {
1373     // Unknown parses as text.

1374     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1375     if ( !p ) {
1376         _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1377     }
1378     return p;
1379 }
1380 
1381 
1382 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1383 {
1384     if ( !doc ) {
1385         doc = _document;
1386     }
1387     XMLUnknown* text = doc->NewUnknown( Value() );  // fixme: this will always allocate memory. Intern?

1388     return text;
1389 }
1390 
1391 
1392 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1393 {
1394     TIXMLASSERT( compare );
1395     const XMLUnknown* unknown = compare->ToUnknown();
1396     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1397 }
1398 
1399 
1400 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1401 {
1402     TIXMLASSERT( visitor );
1403     return visitor->Visit( *this );
1404 }
1405 
1406 // --------- XMLAttribute ---------- //

1407 
1408 const char* XMLAttribute::Name() const
1409 {
1410     return _name.GetStr();
1411 }
1412 
1413 const char* XMLAttribute::Value() const
1414 {
1415     return _value.GetStr();
1416 }
1417 
1418 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1419 {
1420     // Parse using the name rules: bug fix, was using ParseText before

1421     p = _name.ParseName( p );
1422     if ( !p || !*p ) {
1423         return 0;
1424     }
1425 
1426     // Skip white space before =

1427     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1428     if ( *p != '=' ) {
1429         return 0;
1430     }
1431 
1432     ++p;    // move up to opening quote

1433     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1434     if ( *p != '\"' && *p != '\'' ) {
1435         return 0;
1436     }
1437 
1438     const char endTag[2] = { *p, 0 };
1439     ++p;    // move past opening quote

1440 
1441     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1442     return p;
1443 }
1444 
1445 
1446 void XMLAttribute::SetName( const char* n )
1447 {
1448     _name.SetStr( n );
1449 }
1450 
1451 
1452 XMLError XMLAttribute::QueryIntValue( int* value ) const
1453 {
1454     if ( XMLUtil::ToInt( Value(), value )) {
1455         return XML_SUCCESS;
1456     }
1457     return XML_WRONG_ATTRIBUTE_TYPE;
1458 }
1459 
1460 
1461 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1462 {
1463     if ( XMLUtil::ToUnsigned( Value(), value )) {
1464         return XML_SUCCESS;
1465     }
1466     return XML_WRONG_ATTRIBUTE_TYPE;
1467 }
1468 
1469 
1470 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1471 {
1472     if (XMLUtil::ToInt64(Value(), value)) {
1473         return XML_SUCCESS;
1474     }
1475     return XML_WRONG_ATTRIBUTE_TYPE;
1476 }
1477 
1478 
1479 XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1480 {
1481     if(XMLUtil::ToUnsigned64(Value(), value)) {
1482         return XML_SUCCESS;
1483     }
1484     return XML_WRONG_ATTRIBUTE_TYPE;
1485 }
1486 
1487 
1488 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1489 {
1490     if ( XMLUtil::ToBool( Value(), value )) {
1491         return XML_SUCCESS;
1492     }
1493     return XML_WRONG_ATTRIBUTE_TYPE;
1494 }
1495 
1496 
1497 XMLError XMLAttribute::QueryFloatValue( float* value ) const
1498 {
1499     if ( XMLUtil::ToFloat( Value(), value )) {
1500         return XML_SUCCESS;
1501     }
1502     return XML_WRONG_ATTRIBUTE_TYPE;
1503 }
1504 
1505 
1506 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1507 {
1508     if ( XMLUtil::ToDouble( Value(), value )) {
1509         return XML_SUCCESS;
1510     }
1511     return XML_WRONG_ATTRIBUTE_TYPE;
1512 }
1513 
1514 
1515 void XMLAttribute::SetAttribute( const char* v )
1516 {
1517     _value.SetStr( v );
1518 }
1519 
1520 
1521 void XMLAttribute::SetAttribute( int v )
1522 {
1523     char buf[BUF_SIZE];
1524     XMLUtil::ToStr( v, buf, BUF_SIZE );
1525     _value.SetStr( buf );
1526 }
1527 
1528 
1529 void XMLAttribute::SetAttribute( unsigned v )
1530 {
1531     char buf[BUF_SIZE];
1532     XMLUtil::ToStr( v, buf, BUF_SIZE );
1533     _value.SetStr( buf );
1534 }
1535 
1536 
1537 void XMLAttribute::SetAttribute(int64_t v)
1538 {
1539     char buf[BUF_SIZE];
1540     XMLUtil::ToStr(v, buf, BUF_SIZE);
1541     _value.SetStr(buf);
1542 }
1543 
1544 void XMLAttribute::SetAttribute(uint64_t v)
1545 {
1546     char buf[BUF_SIZE];
1547     XMLUtil::ToStr(v, buf, BUF_SIZE);
1548     _value.SetStr(buf);
1549 }
1550 
1551 
1552 void XMLAttribute::SetAttribute( bool v )
1553 {
1554     char buf[BUF_SIZE];
1555     XMLUtil::ToStr( v, buf, BUF_SIZE );
1556     _value.SetStr( buf );
1557 }
1558 
1559 void XMLAttribute::SetAttribute( double v )
1560 {
1561     char buf[BUF_SIZE];
1562     XMLUtil::ToStr( v, buf, BUF_SIZE );
1563     _value.SetStr( buf );
1564 }
1565 
1566 void XMLAttribute::SetAttribute( float v )
1567 {
1568     char buf[BUF_SIZE];
1569     XMLUtil::ToStr( v, buf, BUF_SIZE );
1570     _value.SetStr( buf );
1571 }
1572 
1573 
1574 // --------- XMLElement ---------- //

1575 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1576     _closingType( OPEN ),
1577     _rootAttribute( 0 )
1578 {
1579 }
1580 
1581 
1582 XMLElement::~XMLElement()
1583 {
1584     while( _rootAttribute ) {
1585         XMLAttribute* next = _rootAttribute->_next;
1586         DeleteAttribute( _rootAttribute );
1587         _rootAttribute = next;
1588     }
1589 }
1590 
1591 
1592 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1593 {
1594     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1595         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1596             return a;
1597         }
1598     }
1599     return 0;
1600 }
1601 
1602 
1603 const char* XMLElement::Attribute( const char* name, const char* value ) const
1604 {
1605     const XMLAttribute* a = FindAttribute( name );
1606     if ( !a ) {
1607         return 0;
1608     }
1609     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1610         return a->Value();
1611     }
1612     return 0;
1613 }
1614 
1615 int XMLElement::IntAttribute(const char* name, int defaultValue) const
1616 {
1617     int i = defaultValue;
1618     QueryIntAttribute(name, &i);
1619     return i;
1620 }
1621 
1622 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1623 {
1624     unsigned i = defaultValue;
1625     QueryUnsignedAttribute(name, &i);
1626     return i;
1627 }
1628 
1629 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1630 {
1631     int64_t i = defaultValue;
1632     QueryInt64Attribute(name, &i);
1633     return i;
1634 }
1635 
1636 uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1637 {
1638     uint64_t i = defaultValue;
1639     QueryUnsigned64Attribute(name, &i);
1640     return i;
1641 }
1642 
1643 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1644 {
1645     bool b = defaultValue;
1646     QueryBoolAttribute(name, &b);
1647     return b;
1648 }
1649 
1650 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1651 {
1652     double d = defaultValue;
1653     QueryDoubleAttribute(name, &d);
1654     return d;
1655 }
1656 
1657 float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1658 {
1659     float f = defaultValue;
1660     QueryFloatAttribute(name, &f);
1661     return f;
1662 }
1663 
1664 const char* XMLElement::GetText() const
1665 {
1666     /* skip comment node */
1667     const XMLNode* node = FirstChild();
1668     while (node) {
1669         if (node->ToComment()) {
1670             node = node->NextSibling();
1671             continue;
1672         }
1673         break;
1674     }
1675 
1676     if ( node && node->ToText() ) {
1677         return node->Value();
1678     }
1679     return 0;
1680 }
1681 
1682 
1683 void    XMLElement::SetText( const char* inText )
1684 {
1685     if ( FirstChild() && FirstChild()->ToText() )
1686         FirstChild()->SetValue( inText );
1687     else {
1688         XMLText*    theText = GetDocument()->NewText( inText );
1689         InsertFirstChild( theText );
1690     }
1691 }
1692 
1693 
1694 void XMLElement::SetText( int v )
1695 {
1696     char buf[BUF_SIZE];
1697     XMLUtil::ToStr( v, buf, BUF_SIZE );
1698     SetText( buf );
1699 }
1700 
1701 
1702 void XMLElement::SetText( unsigned v )
1703 {
1704     char buf[BUF_SIZE];
1705     XMLUtil::ToStr( v, buf, BUF_SIZE );
1706     SetText( buf );
1707 }
1708 
1709 
1710 void XMLElement::SetText(int64_t v)
1711 {
1712     char buf[BUF_SIZE];
1713     XMLUtil::ToStr(v, buf, BUF_SIZE);
1714     SetText(buf);
1715 }
1716 
1717 void XMLElement::SetText(uint64_t v) {
1718     char buf[BUF_SIZE];
1719     XMLUtil::ToStr(v, buf, BUF_SIZE);
1720     SetText(buf);
1721 }
1722 
1723 
1724 void XMLElement::SetText( bool v )
1725 {
1726     char buf[BUF_SIZE];
1727     XMLUtil::ToStr( v, buf, BUF_SIZE );
1728     SetText( buf );
1729 }
1730 
1731 
1732 void XMLElement::SetText( float v )
1733 {
1734     char buf[BUF_SIZE];
1735     XMLUtil::ToStr( v, buf, BUF_SIZE );
1736     SetText( buf );
1737 }
1738 
1739 
1740 void XMLElement::SetText( double v )
1741 {
1742     char buf[BUF_SIZE];
1743     XMLUtil::ToStr( v, buf, BUF_SIZE );
1744     SetText( buf );
1745 }
1746 
1747 
1748 XMLError XMLElement::QueryIntText( int* ival ) const
1749 {
1750     if ( FirstChild() && FirstChild()->ToText() ) {
1751         const char* t = FirstChild()->Value();
1752         if ( XMLUtil::ToInt( t, ival ) ) {
1753             return XML_SUCCESS;
1754         }
1755         return XML_CAN_NOT_CONVERT_TEXT;
1756     }
1757     return XML_NO_TEXT_NODE;
1758 }
1759 
1760 
1761 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1762 {
1763     if ( FirstChild() && FirstChild()->ToText() ) {
1764         const char* t = FirstChild()->Value();
1765         if ( XMLUtil::ToUnsigned( t, uval ) ) {
1766             return XML_SUCCESS;
1767         }
1768         return XML_CAN_NOT_CONVERT_TEXT;
1769     }
1770     return XML_NO_TEXT_NODE;
1771 }
1772 
1773 
1774 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1775 {
1776     if (FirstChild() && FirstChild()->ToText()) {
1777         const char* t = FirstChild()->Value();
1778         if (XMLUtil::ToInt64(t, ival)) {
1779             return XML_SUCCESS;
1780         }
1781         return XML_CAN_NOT_CONVERT_TEXT;
1782     }
1783     return XML_NO_TEXT_NODE;
1784 }
1785 
1786 
1787 XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const
1788 {
1789     if(FirstChild() && FirstChild()->ToText()) {
1790         const char* t = FirstChild()->Value();
1791         if(XMLUtil::ToUnsigned64(t, uval)) {
1792             return XML_SUCCESS;
1793         }
1794         return XML_CAN_NOT_CONVERT_TEXT;
1795     }
1796     return XML_NO_TEXT_NODE;
1797 }
1798 
1799 
1800 XMLError XMLElement::QueryBoolText( bool* bval ) const
1801 {
1802     if ( FirstChild() && FirstChild()->ToText() ) {
1803         const char* t = FirstChild()->Value();
1804         if ( XMLUtil::ToBool( t, bval ) ) {
1805             return XML_SUCCESS;
1806         }
1807         return XML_CAN_NOT_CONVERT_TEXT;
1808     }
1809     return XML_NO_TEXT_NODE;
1810 }
1811 
1812 
1813 XMLError XMLElement::QueryDoubleText( double* dval ) const
1814 {
1815     if ( FirstChild() && FirstChild()->ToText() ) {
1816         const char* t = FirstChild()->Value();
1817         if ( XMLUtil::ToDouble( t, dval ) ) {
1818             return XML_SUCCESS;
1819         }
1820         return XML_CAN_NOT_CONVERT_TEXT;
1821     }
1822     return XML_NO_TEXT_NODE;
1823 }
1824 
1825 
1826 XMLError XMLElement::QueryFloatText( float* fval ) const
1827 {
1828     if ( FirstChild() && FirstChild()->ToText() ) {
1829         const char* t = FirstChild()->Value();
1830         if ( XMLUtil::ToFloat( t, fval ) ) {
1831             return XML_SUCCESS;
1832         }
1833         return XML_CAN_NOT_CONVERT_TEXT;
1834     }
1835     return XML_NO_TEXT_NODE;
1836 }
1837 
1838 int XMLElement::IntText(int defaultValue) const
1839 {
1840     int i = defaultValue;
1841     QueryIntText(&i);
1842     return i;
1843 }
1844 
1845 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1846 {
1847     unsigned i = defaultValue;
1848     QueryUnsignedText(&i);
1849     return i;
1850 }
1851 
1852 int64_t XMLElement::Int64Text(int64_t defaultValue) const
1853 {
1854     int64_t i = defaultValue;
1855     QueryInt64Text(&i);
1856     return i;
1857 }
1858 
1859 uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1860 {
1861     uint64_t i = defaultValue;
1862     QueryUnsigned64Text(&i);
1863     return i;
1864 }
1865 
1866 bool XMLElement::BoolText(bool defaultValue) const
1867 {
1868     bool b = defaultValue;
1869     QueryBoolText(&b);
1870     return b;
1871 }
1872 
1873 double XMLElement::DoubleText(double defaultValue) const
1874 {
1875     double d = defaultValue;
1876     QueryDoubleText(&d);
1877     return d;
1878 }
1879 
1880 float XMLElement::FloatText(float defaultValue) const
1881 {
1882     float f = defaultValue;
1883     QueryFloatText(&f);
1884     return f;
1885 }
1886 
1887 
1888 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1889 {
1890     XMLAttribute* last = 0;
1891     XMLAttribute* attrib = 0;
1892     for( attrib = _rootAttribute;
1893             attrib;
1894             last = attrib, attrib = attrib->_next ) {
1895         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1896             break;
1897         }
1898     }
1899     if ( !attrib ) {
1900         attrib = CreateAttribute();
1901         TIXMLASSERT( attrib );
1902         if ( last ) {
1903             TIXMLASSERT( last->_next == 0 );
1904             last->_next = attrib;
1905         }
1906         else {
1907             TIXMLASSERT( _rootAttribute == 0 );
1908             _rootAttribute = attrib;
1909         }
1910         attrib->SetName( name );
1911     }
1912     return attrib;
1913 }
1914 
1915 
1916 void XMLElement::DeleteAttribute( const char* name )
1917 {
1918     XMLAttribute* prev = 0;
1919     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1920         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1921             if ( prev ) {
1922                 prev->_next = a->_next;
1923             }
1924             else {
1925                 _rootAttribute = a->_next;
1926             }
1927             DeleteAttribute( a );
1928             break;
1929         }
1930         prev = a;
1931     }
1932 }
1933 
1934 
1935 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
1936 {
1937     XMLAttribute* prevAttribute = 0;
1938 
1939     // Read the attributes.

1940     while( p ) {
1941         p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1942         if ( !(*p) ) {
1943             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1944             return 0;
1945         }
1946 
1947         // attribute.

1948         if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
1949             XMLAttribute* attrib = CreateAttribute();
1950             TIXMLASSERT( attrib );
1951             attrib->_parseLineNum = _document->_parseCurLineNum;
1952 
1953             const int attrLineNum = attrib->_parseLineNum;
1954 
1955             p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
1956             if ( !p || Attribute( attrib->Name() ) ) {
1957                 DeleteAttribute( attrib );
1958                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
1959                 return 0;
1960             }
1961             // There is a minor bug here: if the attribute in the source xml

1962             // document is duplicated, it will not be detected and the

1963             // attribute will be doubly added. However, tracking the 'prevAttribute'

1964             // avoids re-scanning the attribute list. Preferring performance for

1965             // now, may reconsider in the future.

1966             if ( prevAttribute ) {
1967                 TIXMLASSERT( prevAttribute->_next == 0 );
1968                 prevAttribute->_next = attrib;
1969             }
1970             else {
1971                 TIXMLASSERT( _rootAttribute == 0 );
1972                 _rootAttribute = attrib;
1973             }
1974             prevAttribute = attrib;
1975         }
1976         // end of the tag

1977         else if ( *p == '>' ) {
1978             ++p;
1979             break;
1980         }
1981         // end of the tag

1982         else if ( *p == '/' && *(p+1) == '>' ) {
1983             _closingType = CLOSED;
1984             return p+2; // done; sealed element.

1985         }
1986         else {
1987             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
1988             return 0;
1989         }
1990     }
1991     return p;
1992 }
1993 
1994 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1995 {
1996     if ( attribute == 0 ) {
1997         return;
1998     }
1999     MemPool* pool = attribute->_memPool;
2000     attribute->~XMLAttribute();
2001     pool->Free( attribute );
2002 }
2003 
2004 XMLAttribute* XMLElement::CreateAttribute()
2005 {
2006     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
2007     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
2008     TIXMLASSERT( attrib );
2009     attrib->_memPool = &_document->_attributePool;
2010     attrib->_memPool->SetTracked();
2011     return attrib;
2012 }
2013 
2014 
2015 XMLElement* XMLElement::InsertNewChildElement(const char* name)
2016 {
2017     XMLElement* node = _document->NewElement(name);
2018     return InsertEndChild(node) ? node : 0;
2019 }
2020 
2021 XMLComment* XMLElement::InsertNewComment(const char* comment)
2022 {
2023     XMLComment* node = _document->NewComment(comment);
2024     return InsertEndChild(node) ? node : 0;
2025 }
2026 
2027 XMLText* XMLElement::InsertNewText(const char* text)
2028 {
2029     XMLText* node = _document->NewText(text);
2030     return InsertEndChild(node) ? node : 0;
2031 }
2032 
2033 XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)
2034 {
2035     XMLDeclaration* node = _document->NewDeclaration(text);
2036     return InsertEndChild(node) ? node : 0;
2037 }
2038 
2039 XMLUnknown* XMLElement::InsertNewUnknown(const char* text)
2040 {
2041     XMLUnknown* node = _document->NewUnknown(text);
2042     return InsertEndChild(node) ? node : 0;
2043 }
2044 
2045 
2046 
2047 //

2048 //  <ele></ele>

2049 //  <ele>foo<b>bar</b></ele>

2050 //

2051 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
2052 {
2053     // Read the element name.

2054     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
2055 
2056     // The closing element is the </element> form. It is

2057     // parsed just like a regular element then deleted from

2058     // the DOM.

2059     if ( *p == '/' ) {
2060         _closingType = CLOSING;
2061         ++p;
2062     }
2063 
2064     p = _value.ParseName( p );
2065     if ( _value.Empty() ) {
2066         return 0;
2067     }
2068 
2069     p = ParseAttributes( p, curLineNumPtr );
2070     if ( !p || !*p || _closingType != OPEN ) {
2071         return p;
2072     }
2073 
2074     p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2075     return p;
2076 }
2077 
2078 
2079 
2080 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2081 {
2082     if ( !doc ) {
2083         doc = _document;
2084     }
2085     XMLElement* element = doc->NewElement( Value() );                   // fixme: this will always allocate memory. Intern?

2086     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2087         element->SetAttribute( a->Name(), a->Value() );                 // fixme: this will always allocate memory. Intern?

2088     }
2089     return element;
2090 }
2091 
2092 
2093 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2094 {
2095     TIXMLASSERT( compare );
2096     const XMLElement* other = compare->ToElement();
2097     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
2098 
2099         const XMLAttribute* a=FirstAttribute();
2100         const XMLAttribute* b=other->FirstAttribute();
2101 
2102         while ( a && b ) {
2103             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2104                 return false;
2105             }
2106             a = a->Next();
2107             b = b->Next();
2108         }
2109         if ( a || b ) {
2110             // different count

2111             return false;
2112         }
2113         return true;
2114     }
2115     return false;
2116 }
2117 
2118 
2119 bool XMLElement::Accept( XMLVisitor* visitor ) const
2120 {
2121     TIXMLASSERT( visitor );
2122     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
2123         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2124             if ( !node->Accept( visitor ) ) {
2125                 break;
2126             }
2127         }
2128     }
2129     return visitor->VisitExit( *this );
2130 }
2131 
2132 
2133 // --------- XMLDocument ----------- //

2134 
2135 // Warning: List must match 'enum XMLError'

2136 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2137     "XML_SUCCESS",
2138     "XML_NO_ATTRIBUTE",
2139     "XML_WRONG_ATTRIBUTE_TYPE",
2140     "XML_ERROR_FILE_NOT_FOUND",
2141     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2142     "XML_ERROR_FILE_READ_ERROR",
2143     "XML_ERROR_PARSING_ELEMENT",
2144     "XML_ERROR_PARSING_ATTRIBUTE",
2145     "XML_ERROR_PARSING_TEXT",
2146     "XML_ERROR_PARSING_CDATA",
2147     "XML_ERROR_PARSING_COMMENT",
2148     "XML_ERROR_PARSING_DECLARATION",
2149     "XML_ERROR_PARSING_UNKNOWN",
2150     "XML_ERROR_EMPTY_DOCUMENT",
2151     "XML_ERROR_MISMATCHED_ELEMENT",
2152     "XML_ERROR_PARSING",
2153     "XML_CAN_NOT_CONVERT_TEXT",
2154     "XML_NO_TEXT_NODE",
2155     "XML_ELEMENT_DEPTH_EXCEEDED"
2156 };
2157 
2158 
2159 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
2160     XMLNode( 0 ),
2161     _writeBOM( false ),
2162     _processEntities( processEntities ),
2163     _errorID(XML_SUCCESS),
2164     _whitespaceMode( whitespaceMode ),
2165     _errorStr(),
2166     _errorLineNum( 0 ),
2167     _charBuffer( 0 ),
2168     _parseCurLineNum( 0 ),
2169     _parsingDepth(0),
2170     _unlinked(),
2171     _elementPool(),
2172     _attributePool(),
2173     _textPool(),
2174     _commentPool()
2175 {
2176     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)

2177     _document = this;
2178 }
2179 
2180 
2181 XMLDocument::~XMLDocument()
2182 {
2183     Clear();
2184 }
2185 
2186 
2187 void XMLDocument::MarkInUse(const XMLNode* const node)
2188 {
2189     TIXMLASSERT(node);
2190     TIXMLASSERT(node->_parent == 0);
2191 
2192     for (int i = 0; i < _unlinked.Size(); ++i) {
2193         if (node == _unlinked[i]) {
2194             _unlinked.SwapRemove(i);
2195             break;
2196         }
2197     }
2198 }
2199 
2200 void XMLDocument::Clear()
2201 {
2202     DeleteChildren();
2203     while( _unlinked.Size()) {
2204         DeleteNode(_unlinked[0]);   // Will remove from _unlinked as part of delete.

2205     }
2206 
2207 #ifdef TINYXML2_DEBUG
2208     const bool hadError = Error();
2209 #endif
2210     ClearError();
2211 
2212     delete [] _charBuffer;
2213     _charBuffer = 0;
2214     _parsingDepth = 0;
2215 
2216 #if 0
2217     _textPool.Trace( "text" );
2218     _elementPool.Trace( "element" );
2219     _commentPool.Trace( "comment" );
2220     _attributePool.Trace( "attribute" );
2221 #endif
2222 
2223 #ifdef TINYXML2_DEBUG
2224     if ( !hadError ) {
2225         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
2226         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2227         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
2228         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
2229     }
2230 #endif
2231 }
2232 
2233 
2234 void XMLDocument::DeepCopy(XMLDocument* target) const
2235 {
2236     TIXMLASSERT(target);
2237     if (target == this) {
2238         return; // technically success - a no-op.

2239     }
2240 
2241     target->Clear();
2242     for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2243         target->InsertEndChild(node->DeepClone(target));
2244     }
2245 }
2246 
2247 XMLElement* XMLDocument::NewElement( const char* name )
2248 {
2249     XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
2250     ele->SetName( name );
2251     return ele;
2252 }
2253 
2254 
2255 XMLComment* XMLDocument::NewComment( const char* str )
2256 {
2257     XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
2258     comment->SetValue( str );
2259     return comment;
2260 }
2261 
2262 
2263 XMLText* XMLDocument::NewText( const char* str )
2264 {
2265     XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
2266     text->SetValue( str );
2267     return text;
2268 }
2269 
2270 
2271 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2272 {
2273     XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
2274     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2275     return dec;
2276 }
2277 
2278 
2279 XMLUnknown* XMLDocument::NewUnknown( const char* str )
2280 {
2281     XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
2282     unk->SetValue( str );
2283     return unk;
2284 }
2285 
2286 static FILE* callfopen( const char* filepath, const char* mode )
2287 {
2288     TIXMLASSERT( filepath );
2289     TIXMLASSERT( mode );
2290 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2291     FILE* fp = 0;
2292     const errno_t err = fopen_s( &fp, filepath, mode );
2293     if ( err ) {
2294         return 0;
2295     }
2296 #else
2297     FILE* fp = fopen( filepath, mode );
2298 #endif
2299     return fp;
2300 }
2301 
2302 void XMLDocument::DeleteNode( XMLNode* node )   {
2303     TIXMLASSERT( node );
2304     TIXMLASSERT(node->_document == this );
2305     if (node->_parent) {
2306         node->_parent->DeleteChild( node );
2307     }
2308     else {
2309         // Isn't in the tree.

2310         // Use the parent delete.

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

2312         // it was never used.

2313         node->_memPool->SetTracked();
2314         // Call the static XMLNode version:

2315         XMLNode::DeleteNode(node);
2316     }
2317 }
2318 
2319 
2320 XMLError XMLDocument::LoadFile( const char* filename )
2321 {
2322     if ( !filename ) {
2323         TIXMLASSERT( false );
2324         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2325         return _errorID;
2326     }
2327 
2328     Clear();
2329     FILE* fp = callfopen( filename, "rb" );
2330     if ( !fp ) {
2331         SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
2332         return _errorID;
2333     }
2334     LoadFile( fp );
2335     fclose( fp );
2336     return _errorID;
2337 }
2338 
2339 XMLError XMLDocument::LoadFile( FILE* fp )
2340 {
2341     Clear();
2342 
2343     TIXML_FSEEK( fp, 0, SEEK_SET );
2344     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
2345         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2346         return _errorID;
2347     }
2348 
2349     TIXML_FSEEK( fp, 0, SEEK_END );
2350 
2351     unsigned long long filelength;
2352     {
2353         const long long fileLengthSigned = TIXML_FTELL( fp );
2354         TIXML_FSEEK( fp, 0, SEEK_SET );
2355         if ( fileLengthSigned == -1L ) {
2356             SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2357             return _errorID;
2358         }
2359         TIXMLASSERT( fileLengthSigned >= 0 );
2360         filelength = static_cast<unsigned long long>(fileLengthSigned);
2361     }
2362 
2363     const size_t maxSizeT = static_cast<size_t>(-1);
2364     // We'll do the comparison as an unsigned long long, because that's guaranteed to be at

2365     // least 8 bytes, even on a 32-bit platform.

2366     if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {
2367         // Cannot handle files which won't fit in buffer together with null terminator

2368         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2369         return _errorID;
2370     }
2371 
2372     if ( filelength == 0 ) {
2373         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2374         return _errorID;
2375     }
2376 
2377     const size_t size = static_cast<size_t>(filelength);
2378     TIXMLASSERT( _charBuffer == 0 );
2379     _charBuffer = new char[size+1];
2380     const size_t read = fread( _charBuffer, 1, size, fp );
2381     if ( read != size ) {
2382         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2383         return _errorID;
2384     }
2385 
2386     _charBuffer[size] = 0;
2387 
2388     Parse();
2389     return _errorID;
2390 }
2391 
2392 
2393 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
2394 {
2395     if ( !filename ) {
2396         TIXMLASSERT( false );
2397         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2398         return _errorID;
2399     }
2400 
2401     FILE* fp = callfopen( filename, "w" );
2402     if ( !fp ) {
2403         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
2404         return _errorID;
2405     }
2406     SaveFile(fp, compact);
2407     fclose( fp );
2408     return _errorID;
2409 }
2410 
2411 
2412 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2413 {
2414     // Clear any error from the last save, otherwise it will get reported

2415     // for *this* call.

2416     ClearError();
2417     XMLPrinter stream( fp, compact );
2418     Print( &stream );
2419     return _errorID;
2420 }
2421 
2422 
2423 XMLError XMLDocument::Parse( const char* xml, size_t nBytes )
2424 {
2425     Clear();
2426 
2427     if ( nBytes == 0 || !xml || !*xml ) {
2428         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2429         return _errorID;
2430     }
2431     if ( nBytes == static_cast<size_t>(-1) ) {
2432         nBytes = strlen( xml );
2433     }
2434     TIXMLASSERT( _charBuffer == 0 );
2435     _charBuffer = new char[ nBytes+1 ];
2436     memcpy( _charBuffer, xml, nBytes );
2437     _charBuffer[nBytes] = 0;
2438 
2439     Parse();
2440     if ( Error() ) {
2441         // clean up now essentially dangling memory.

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

2443         // pools that are dead and inaccessible.

2444         DeleteChildren();
2445         _elementPool.Clear();
2446         _attributePool.Clear();
2447         _textPool.Clear();
2448         _commentPool.Clear();
2449     }
2450     return _errorID;
2451 }
2452 
2453 
2454 void XMLDocument::Print( XMLPrinter* streamer ) const
2455 {
2456     if ( streamer ) {
2457         Accept( streamer );
2458     }
2459     else {
2460         XMLPrinter stdoutStreamer( stdout );
2461         Accept( &stdoutStreamer );
2462     }
2463 }
2464 
2465 
2466 void XMLDocument::ClearError() {
2467     _errorID = XML_SUCCESS;
2468     _errorLineNum = 0;
2469     _errorStr.Reset();
2470 }
2471 
2472 
2473 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2474 {
2475     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2476     _errorID = error;
2477     _errorLineNum = lineNum;
2478     _errorStr.Reset();
2479 
2480     const size_t BUFFER_SIZE = 1000;
2481     char* buffer = new char[BUFFER_SIZE];
2482 
2483     TIXMLASSERT(sizeof(error) <= sizeof(int));
2484     TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
2485 
2486     if (format) {
2487         size_t len = strlen(buffer);
2488         TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2489         len = strlen(buffer);
2490 
2491         va_list va;
2492         va_start(va, format);
2493         TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2494         va_end(va);
2495     }
2496     _errorStr.SetStr(buffer);
2497     delete[] buffer;
2498 }
2499 
2500 
2501 /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
2502 {
2503     TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2504     const char* errorName = _errorNames[errorID];
2505     TIXMLASSERT( errorName && errorName[0] );
2506     return errorName;
2507 }
2508 
2509 const char* XMLDocument::ErrorStr() const
2510 {
2511     return _errorStr.Empty() ? "" : _errorStr.GetStr();
2512 }
2513 
2514 
2515 void XMLDocument::PrintError() const
2516 {
2517     printf("%s\n", ErrorStr());
2518 }
2519 
2520 const char* XMLDocument::ErrorName() const
2521 {
2522     return ErrorIDToName(_errorID);
2523 }
2524 
2525 void XMLDocument::Parse()
2526 {
2527     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously

2528     TIXMLASSERT( _charBuffer );
2529     _parseCurLineNum = 1;
2530     _parseLineNum = 1;
2531     char* p = _charBuffer;
2532     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2533     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2534     if ( !*p ) {
2535         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2536         return;
2537     }
2538     ParseDeep(p, 0, &_parseCurLineNum );
2539 }
2540 
2541 void XMLDocument::PushDepth()
2542 {
2543     _parsingDepth++;
2544     if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2545         SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2546     }
2547 }
2548 
2549 void XMLDocument::PopDepth()
2550 {
2551     TIXMLASSERT(_parsingDepth > 0);
2552     --_parsingDepth;
2553 }
2554 
2555 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2556     _elementJustOpened( false ),
2557     _stack(),
2558     _firstElement( true ),
2559     _fp( file ),
2560     _depth( depth ),
2561     _textDepth( -1 ),
2562     _processEntities( true ),
2563     _compactMode( compact ),
2564     _buffer()
2565 {
2566     for( int i=0; i<ENTITY_RANGE; ++i ) {
2567         _entityFlag[i] = false;
2568         _restrictedEntityFlag[i] = false;
2569     }
2570     for( int i=0; i<NUM_ENTITIES; ++i ) {
2571         const char entityValue = entities[i].value;
2572         const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
2573         TIXMLASSERT( flagIndex < ENTITY_RANGE );
2574         _entityFlag[flagIndex] = true;
2575     }
2576     _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2577     _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2578     _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;  // not required, but consistency is nice

2579     _buffer.Push( 0 );
2580 }
2581 
2582 
2583 void XMLPrinter::Print( const char* format, ... )
2584 {
2585     va_list     va;
2586     va_start( va, format );
2587 
2588     if ( _fp ) {
2589         vfprintf( _fp, format, va );
2590     }
2591     else {
2592         const int len = TIXML_VSCPRINTF( format, va );
2593         // Close out and re-start the va-args

2594         va_end( va );
2595         TIXMLASSERT( len >= 0 );
2596         va_start( va, format );
2597         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2598         char* p = _buffer.PushArr( len ) - 1;   // back up over the null terminator.

2599         TIXML_VSNPRINTF( p, len+1, format, va );
2600     }
2601     va_end( va );
2602 }
2603 
2604 
2605 void XMLPrinter::Write( const char* data, size_t size )
2606 {
2607     if ( _fp ) {
2608         fwrite ( data , sizeof(char), size, _fp);
2609     }
2610     else {
2611         char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.

2612         memcpy( p, data, size );
2613         p[size] = 0;
2614     }
2615 }
2616 
2617 
2618 void XMLPrinter::Putc( char ch )
2619 {
2620     if ( _fp ) {
2621         fputc ( ch, _fp);
2622     }
2623     else {
2624         char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.

2625         p[0] = ch;
2626         p[1] = 0;
2627     }
2628 }
2629 
2630 
2631 void XMLPrinter::PrintSpace( int depth )
2632 {
2633     for( int i=0; i<depth; ++i ) {
2634         Write( "    " );
2635     }
2636 }
2637 
2638 
2639 void XMLPrinter::PrintString( const char* p, bool restricted )
2640 {
2641     // Look for runs of bytes between entities to print.

2642     const char* q = p;
2643 
2644     if ( _processEntities ) {
2645         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2646         while ( *q ) {
2647             TIXMLASSERT( p <= q );
2648             // Remember, char is sometimes signed. (How many times has that bitten me?)

2649             if ( *q > 0 && *q < ENTITY_RANGE ) {
2650                 // Check for entities. If one is found, flush

2651                 // the stream up until the entity, write the

2652                 // entity, and keep looking.

2653                 if ( flag[static_cast<unsigned char>(*q)] ) {
2654                     while ( p < q ) {
2655                         const size_t delta = q - p;
2656                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2657                         Write( p, toPrint );
2658                         p += toPrint;
2659                     }
2660                     bool entityPatternPrinted = false;
2661                     for( int i=0; i<NUM_ENTITIES; ++i ) {
2662                         if ( entities[i].value == *q ) {
2663                             Putc( '&' );
2664                             Write( entities[i].pattern, entities[i].length );
2665                             Putc( ';' );
2666                             entityPatternPrinted = true;
2667                             break;
2668                         }
2669                     }
2670                     if ( !entityPatternPrinted ) {
2671                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release

2672                         TIXMLASSERT( false );
2673                     }
2674                     ++p;
2675                 }
2676             }
2677             ++q;
2678             TIXMLASSERT( p <= q );
2679         }
2680         // Flush the remaining string. This will be the entire

2681         // string if an entity wasn't found.

2682         if ( p < q ) {
2683             const size_t delta = q - p;
2684             const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2685             Write( p, toPrint );
2686         }
2687     }
2688     else {
2689         Write( p );
2690     }
2691 }
2692 
2693 
2694 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2695 {
2696     if ( writeBOM ) {
2697         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2698         Write( reinterpret_cast< const char* >( bom ) );
2699     }
2700     if ( writeDec ) {
2701         PushDeclaration( "xml version=\"1.0\"" );
2702     }
2703 }
2704 
2705 void XMLPrinter::PrepareForNewNode( bool compactMode )
2706 {
2707     SealElementIfJustOpened();
2708 
2709     if ( compactMode ) {
2710         return;
2711     }
2712 
2713     if ( _firstElement ) {
2714         PrintSpace (_depth);
2715     } else if ( _textDepth < 0) {
2716         Putc( '\n' );
2717         PrintSpace( _depth );
2718     }
2719 
2720     _firstElement = false;
2721 }
2722 
2723 void XMLPrinter::OpenElement( const char* name, bool compactMode )
2724 {
2725     PrepareForNewNode( compactMode );
2726     _stack.Push( name );
2727 
2728     Write ( "<" );
2729     Write ( name );
2730 
2731     _elementJustOpened = true;
2732     ++_depth;
2733 }
2734 
2735 
2736 void XMLPrinter::PushAttribute( const char* name, const char* value )
2737 {
2738     TIXMLASSERT( _elementJustOpened );
2739     Putc ( ' ' );
2740     Write( name );
2741     Write( "=\"" );
2742     PrintString( value, false );
2743     Putc ( '\"' );
2744 }
2745 
2746 
2747 void XMLPrinter::PushAttribute( const char* name, int v )
2748 {
2749     char buf[BUF_SIZE];
2750     XMLUtil::ToStr( v, buf, BUF_SIZE );
2751     PushAttribute( name, buf );
2752 }
2753 
2754 
2755 void XMLPrinter::PushAttribute( const char* name, unsigned v )
2756 {
2757     char buf[BUF_SIZE];
2758     XMLUtil::ToStr( v, buf, BUF_SIZE );
2759     PushAttribute( name, buf );
2760 }
2761 
2762 
2763 void XMLPrinter::PushAttribute(const char* name, int64_t v)
2764 {
2765     char buf[BUF_SIZE];
2766     XMLUtil::ToStr(v, buf, BUF_SIZE);
2767     PushAttribute(name, buf);
2768 }
2769 
2770 
2771 void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2772 {
2773     char buf[BUF_SIZE];
2774     XMLUtil::ToStr(v, buf, BUF_SIZE);
2775     PushAttribute(name, buf);
2776 }
2777 
2778 
2779 void XMLPrinter::PushAttribute( const char* name, bool v )
2780 {
2781     char buf[BUF_SIZE];
2782     XMLUtil::ToStr( v, buf, BUF_SIZE );
2783     PushAttribute( name, buf );
2784 }
2785 
2786 
2787 void XMLPrinter::PushAttribute( const char* name, double v )
2788 {
2789     char buf[BUF_SIZE];
2790     XMLUtil::ToStr( v, buf, BUF_SIZE );
2791     PushAttribute( name, buf );
2792 }
2793 
2794 
2795 void XMLPrinter::CloseElement( bool compactMode )
2796 {
2797     --_depth;
2798     const char* name = _stack.Pop();
2799 
2800     if ( _elementJustOpened ) {
2801         Write( "/>" );
2802     }
2803     else {
2804         if ( _textDepth < 0 && !compactMode) {
2805             Putc( '\n' );
2806             PrintSpace( _depth );
2807         }
2808         Write ( "</" );
2809         Write ( name );
2810         Write ( ">" );
2811     }
2812 
2813     if ( _textDepth == _depth ) {
2814         _textDepth = -1;
2815     }
2816     if ( _depth == 0 && !compactMode) {
2817         Putc( '\n' );
2818     }
2819     _elementJustOpened = false;
2820 }
2821 
2822 
2823 void XMLPrinter::SealElementIfJustOpened()
2824 {
2825     if ( !_elementJustOpened ) {
2826         return;
2827     }
2828     _elementJustOpened = false;
2829     Putc( '>' );
2830 }
2831 
2832 
2833 void XMLPrinter::PushText( const char* text, bool cdata )
2834 {
2835     _textDepth = _depth-1;
2836 
2837     SealElementIfJustOpened();
2838     if ( cdata ) {
2839         Write( "<![CDATA[" );
2840         Write( text );
2841         Write( "]]>" );
2842     }
2843     else {
2844         PrintString( text, true );
2845     }
2846 }
2847 
2848 
2849 void XMLPrinter::PushText( int64_t value )
2850 {
2851     char buf[BUF_SIZE];
2852     XMLUtil::ToStr( value, buf, BUF_SIZE );
2853     PushText( buf, false );
2854 }
2855 
2856 
2857 void XMLPrinter::PushText( uint64_t value )
2858 {
2859     char buf[BUF_SIZE];
2860     XMLUtil::ToStr(value, buf, BUF_SIZE);
2861     PushText(buf, false);
2862 }
2863 
2864 
2865 void XMLPrinter::PushText( int value )
2866 {
2867     char buf[BUF_SIZE];
2868     XMLUtil::ToStr( value, buf, BUF_SIZE );
2869     PushText( buf, false );
2870 }
2871 
2872 
2873 void XMLPrinter::PushText( unsigned value )
2874 {
2875     char buf[BUF_SIZE];
2876     XMLUtil::ToStr( value, buf, BUF_SIZE );
2877     PushText( buf, false );
2878 }
2879 
2880 
2881 void XMLPrinter::PushText( bool value )
2882 {
2883     char buf[BUF_SIZE];
2884     XMLUtil::ToStr( value, buf, BUF_SIZE );
2885     PushText( buf, false );
2886 }
2887 
2888 
2889 void XMLPrinter::PushText( float value )
2890 {
2891     char buf[BUF_SIZE];
2892     XMLUtil::ToStr( value, buf, BUF_SIZE );
2893     PushText( buf, false );
2894 }
2895 
2896 
2897 void XMLPrinter::PushText( double value )
2898 {
2899     char buf[BUF_SIZE];
2900     XMLUtil::ToStr( value, buf, BUF_SIZE );
2901     PushText( buf, false );
2902 }
2903 
2904 
2905 void XMLPrinter::PushComment( const char* comment )
2906 {
2907     PrepareForNewNode( _compactMode );
2908 
2909     Write( "<!--" );
2910     Write( comment );
2911     Write( "-->" );
2912 }
2913 
2914 
2915 void XMLPrinter::PushDeclaration( const char* value )
2916 {
2917     PrepareForNewNode( _compactMode );
2918 
2919     Write( "<?" );
2920     Write( value );
2921     Write( "?>" );
2922 }
2923 
2924 
2925 void XMLPrinter::PushUnknown( const char* value )
2926 {
2927     PrepareForNewNode( _compactMode );
2928 
2929     Write( "<!" );
2930     Write( value );
2931     Putc( '>' );
2932 }
2933 
2934 
2935 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2936 {
2937     _processEntities = doc.ProcessEntities();
2938     if ( doc.HasBOM() ) {
2939         PushHeader( true, false );
2940     }
2941     return true;
2942 }
2943 
2944 
2945 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2946 {
2947     const XMLElement* parentElem = 0;
2948     if ( element.Parent() ) {
2949         parentElem = element.Parent()->ToElement();
2950     }
2951     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2952     OpenElement( element.Name(), compactMode );
2953     while ( attribute ) {
2954         PushAttribute( attribute->Name(), attribute->Value() );
2955         attribute = attribute->Next();
2956     }
2957     return true;
2958 }
2959 
2960 
2961 bool XMLPrinter::VisitExit( const XMLElement& element )
2962 {
2963     CloseElement( CompactMode(element) );
2964     return true;
2965 }
2966 
2967 
2968 bool XMLPrinter::Visit( const XMLText& text )
2969 {
2970     PushText( text.Value(), text.CData() );
2971     return true;
2972 }
2973 
2974 
2975 bool XMLPrinter::Visit( const XMLComment& comment )
2976 {
2977     PushComment( comment.Value() );
2978     return true;
2979 }
2980 
2981 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2982 {
2983     PushDeclaration( declaration.Value() );
2984     return true;
2985 }
2986 
2987 
2988 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2989 {
2990     PushUnknown( unknown.Value() );
2991     return true;
2992 }
2993 
2994 }   // namespace tinyxml2