tinyxml2.cpp
Go to the documentation of this file.
00001 /*
00002 Original code by Lee Thomason (www.grinninglizard.com)
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any
00006 damages arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any
00009 purpose, including commercial applications, and to alter it and
00010 redistribute it freely, subject to the following restrictions:
00011 
00012 1. The origin of this software must not be misrepresented; you must
00013 not claim that you wrote the original software. If you use this
00014 software in a product, an acknowledgment in the product documentation
00015 would be appreciated but is not required.
00016 
00017 2. Altered source versions must be plainly marked as such, and
00018 must not be misrepresented as being the original software.
00019 
00020 3. This notice may not be removed or altered from any source
00021 distribution.
00022 */
00023 
00024 #include "tinyxml2.h"
00025 
00026 #include <new>          // yes, this one new style header, is in the Android SDK.
00027 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
00028 #   include <stddef.h>
00029 #   include <stdarg.h>
00030 #else
00031 #   include <cstddef>
00032 #   include <cstdarg>
00033 #endif
00034 
00035 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
00036         // Microsoft Visual Studio, version 2005 and higher. Not WinCE.
00037         /*int _snprintf_s(
00038            char *buffer,
00039            size_t sizeOfBuffer,
00040            size_t count,
00041            const char *format [,
00042                   argument] ...
00043         );*/
00044         static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
00045         {
00046                 va_list va;
00047                 va_start( va, format );
00048                 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
00049                 va_end( va );
00050                 return result;
00051         }
00052 
00053         static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
00054         {
00055                 int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
00056                 return result;
00057         }
00058 
00059         #define TIXML_VSCPRINTF _vscprintf
00060         #define TIXML_SSCANF    sscanf_s
00061 #elif defined _MSC_VER
00062         // Microsoft Visual Studio 2003 and earlier or WinCE
00063         #define TIXML_SNPRINTF  _snprintf
00064         #define TIXML_VSNPRINTF _vsnprintf
00065         #define TIXML_SSCANF    sscanf
00066         #if (_MSC_VER < 1400 ) && (!defined WINCE)
00067                 // Microsoft Visual Studio 2003 and not WinCE.
00068                 #define TIXML_VSCPRINTF   _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
00069         #else
00070                 // Microsoft Visual Studio 2003 and earlier or WinCE.
00071                 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
00072                 {
00073                         int len = 512;
00074                         for (;;) {
00075                                 len = len*2;
00076                                 char* str = new char[len]();
00077                                 const int required = _vsnprintf(str, len, format, va);
00078                                 delete[] str;
00079                                 if ( required != -1 ) {
00080                                         TIXMLASSERT( required >= 0 );
00081                                         len = required;
00082                                         break;
00083                                 }
00084                         }
00085                         TIXMLASSERT( len >= 0 );
00086                         return len;
00087                 }
00088         #endif
00089 #else
00090         // GCC version 3 and higher
00091         //#warning( "Using sn* functions." )
00092         #define TIXML_SNPRINTF  snprintf
00093         #define TIXML_VSNPRINTF vsnprintf
00094         static inline int TIXML_VSCPRINTF( const char* format, va_list va )
00095         {
00096                 int len = vsnprintf( 0, 0, format, va );
00097                 TIXMLASSERT( len >= 0 );
00098                 return len;
00099         }
00100         #define TIXML_SSCANF   sscanf
00101 #endif
00102 
00103 
00104 static const char LINE_FEED                             = (char)0x0a;                   // all line endings are normalized to LF
00105 static const char LF = LINE_FEED;
00106 static const char CARRIAGE_RETURN               = (char)0x0d;                   // CR gets filtered out
00107 static const char CR = CARRIAGE_RETURN;
00108 static const char SINGLE_QUOTE                  = '\'';
00109 static const char DOUBLE_QUOTE                  = '\"';
00110 
00111 // Bunch of unicode info at:
00112 //              http://www.unicode.org/faq/utf_bom.html
00113 //      ef bb bf (Microsoft "lead bytes") - designates UTF-8
00114 
00115 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
00116 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
00117 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
00118 
00119 namespace BT_TinyXML2
00120 {
00121 
00122 struct Entity {
00123     const char* pattern;
00124     int length;
00125     char value;
00126 };
00127 
00128 static const int NUM_ENTITIES = 5;
00129 static const Entity entities[NUM_ENTITIES] = {
00130     { "quot", 4,        DOUBLE_QUOTE },
00131     { "amp", 3,         '&'  },
00132     { "apos", 4,        SINGLE_QUOTE },
00133     { "lt",     2,              '<'      },
00134     { "gt",     2,              '>'      }
00135 };
00136 
00137 
00138 StrPair::~StrPair()
00139 {
00140     Reset();
00141 }
00142 
00143 
00144 void StrPair::TransferTo( StrPair* other )
00145 {
00146     if ( this == other ) {
00147         return;
00148     }
00149     // This in effect implements the assignment operator by "moving"
00150     // ownership (as in auto_ptr).
00151 
00152     TIXMLASSERT( other != 0 );
00153     TIXMLASSERT( other->_flags == 0 );
00154     TIXMLASSERT( other->_start == 0 );
00155     TIXMLASSERT( other->_end == 0 );
00156 
00157     other->Reset();
00158 
00159     other->_flags = _flags;
00160     other->_start = _start;
00161     other->_end = _end;
00162 
00163     _flags = 0;
00164     _start = 0;
00165     _end = 0;
00166 }
00167 
00168 
00169 void StrPair::Reset()
00170 {
00171     if ( _flags & NEEDS_DELETE ) {
00172         delete [] _start;
00173     }
00174     _flags = 0;
00175     _start = 0;
00176     _end = 0;
00177 }
00178 
00179 
00180 void StrPair::SetStr( const char* str, int flags )
00181 {
00182     TIXMLASSERT( str );
00183     Reset();
00184     size_t len = strlen( str );
00185     TIXMLASSERT( _start == 0 );
00186     _start = new char[ len+1 ];
00187     memcpy( _start, str, len+1 );
00188     _end = _start + len;
00189     _flags = flags | NEEDS_DELETE;
00190 }
00191 
00192 
00193 char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
00194 {
00195     TIXMLASSERT( p );
00196     TIXMLASSERT( endTag && *endTag );
00197         TIXMLASSERT(curLineNumPtr);
00198 
00199     char* start = p;
00200     char  endChar = *endTag;
00201     size_t length = strlen( endTag );
00202 
00203     // Inner loop of text parsing.
00204     while ( *p ) {
00205         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
00206             Set( start, p, strFlags );
00207             return p + length;
00208         } else if (*p == '\n') {
00209             ++(*curLineNumPtr);
00210         }
00211         ++p;
00212         TIXMLASSERT( p );
00213     }
00214     return 0;
00215 }
00216 
00217 
00218 char* StrPair::ParseName( char* p )
00219 {
00220     if ( !p || !(*p) ) {
00221         return 0;
00222     }
00223     if ( !XMLUtil::IsNameStartChar( *p ) ) {
00224         return 0;
00225     }
00226 
00227     char* const start = p;
00228     ++p;
00229     while ( *p && XMLUtil::IsNameChar( *p ) ) {
00230         ++p;
00231     }
00232 
00233     Set( start, p, 0 );
00234     return p;
00235 }
00236 
00237 
00238 void StrPair::CollapseWhitespace()
00239 {
00240     // Adjusting _start would cause undefined behavior on delete[]
00241     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
00242     // Trim leading space.
00243     _start = XMLUtil::SkipWhiteSpace( _start, 0 );
00244 
00245     if ( *_start ) {
00246         const char* p = _start; // the read pointer
00247         char* q = _start;       // the write pointer
00248 
00249         while( *p ) {
00250             if ( XMLUtil::IsWhiteSpace( *p )) {
00251                 p = XMLUtil::SkipWhiteSpace( p, 0 );
00252                 if ( *p == 0 ) {
00253                     break;    // don't write to q; this trims the trailing space.
00254                 }
00255                 *q = ' ';
00256                 ++q;
00257             }
00258             *q = *p;
00259             ++q;
00260             ++p;
00261         }
00262         *q = 0;
00263     }
00264 }
00265 
00266 
00267 const char* StrPair::GetStr()
00268 {
00269     TIXMLASSERT( _start );
00270     TIXMLASSERT( _end );
00271     if ( _flags & NEEDS_FLUSH ) {
00272         *_end = 0;
00273         _flags ^= NEEDS_FLUSH;
00274 
00275         if ( _flags ) {
00276             const char* p = _start;     // the read pointer
00277             char* q = _start;   // the write pointer
00278 
00279             while( p < _end ) {
00280                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
00281                     // CR-LF pair becomes LF
00282                     // CR alone becomes LF
00283                     // LF-CR becomes LF
00284                     if ( *(p+1) == LF ) {
00285                         p += 2;
00286                     }
00287                     else {
00288                         ++p;
00289                     }
00290                     *q = LF;
00291                     ++q;
00292                 }
00293                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
00294                     if ( *(p+1) == CR ) {
00295                         p += 2;
00296                     }
00297                     else {
00298                         ++p;
00299                     }
00300                     *q = LF;
00301                     ++q;
00302                 }
00303                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
00304                     // Entities handled by tinyXML2:
00305                     // - special entities in the entity table [in/out]
00306                     // - numeric character reference [in]
00307                     //   &#20013; or &#x4e2d;
00308 
00309                     if ( *(p+1) == '#' ) {
00310                         const int buflen = 10;
00311                         char buf[buflen] = { 0 };
00312                         int len = 0;
00313                         char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
00314                         if ( adjusted == 0 ) {
00315                             *q = *p;
00316                             ++p;
00317                             ++q;
00318                         }
00319                         else {
00320                             TIXMLASSERT( 0 <= len && len <= buflen );
00321                             TIXMLASSERT( q + len <= adjusted );
00322                             p = adjusted;
00323                             memcpy( q, buf, len );
00324                             q += len;
00325                         }
00326                     }
00327                     else {
00328                         bool entityFound = false;
00329                         for( int i = 0; i < NUM_ENTITIES; ++i ) {
00330                             const Entity& entity = entities[i];
00331                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
00332                                     && *( p + entity.length + 1 ) == ';' ) {
00333                                 // Found an entity - convert.
00334                                 *q = entity.value;
00335                                 ++q;
00336                                 p += entity.length + 2;
00337                                 entityFound = true;
00338                                 break;
00339                             }
00340                         }
00341                         if ( !entityFound ) {
00342                             // fixme: treat as error?
00343                             ++p;
00344                             ++q;
00345                         }
00346                     }
00347                 }
00348                 else {
00349                     *q = *p;
00350                     ++p;
00351                     ++q;
00352                 }
00353             }
00354             *q = 0;
00355         }
00356         // The loop below has plenty going on, and this
00357         // is a less useful mode. Break it out.
00358         if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
00359             CollapseWhitespace();
00360         }
00361         _flags = (_flags & NEEDS_DELETE);
00362     }
00363     TIXMLASSERT( _start );
00364     return _start;
00365 }
00366 
00367 
00368 
00369 
00370 // --------- XMLUtil ----------- //
00371 
00372 const char* XMLUtil::writeBoolTrue  = "true";
00373 const char* XMLUtil::writeBoolFalse = "false";
00374 
00375 void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
00376 {
00377         static const char* defTrue  = "true";
00378         static const char* defFalse = "false";
00379 
00380         writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
00381         writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
00382 }
00383 
00384 
00385 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
00386 {
00387     TIXMLASSERT( p );
00388     TIXMLASSERT( bom );
00389     *bom = false;
00390     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
00391     // Check for BOM:
00392     if (    *(pu+0) == TIXML_UTF_LEAD_0
00393             && *(pu+1) == TIXML_UTF_LEAD_1
00394             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
00395         *bom = true;
00396         p += 3;
00397     }
00398     TIXMLASSERT( p );
00399     return p;
00400 }
00401 
00402 
00403 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
00404 {
00405     const unsigned long BYTE_MASK = 0xBF;
00406     const unsigned long BYTE_MARK = 0x80;
00407     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
00408 
00409     if (input < 0x80) {
00410         *length = 1;
00411     }
00412     else if ( input < 0x800 ) {
00413         *length = 2;
00414     }
00415     else if ( input < 0x10000 ) {
00416         *length = 3;
00417     }
00418     else if ( input < 0x200000 ) {
00419         *length = 4;
00420     }
00421     else {
00422         *length = 0;    // This code won't convert this correctly anyway.
00423         return;
00424     }
00425 
00426     output += *length;
00427 
00428     // Scary scary fall throughs are annotated with carefully designed comments
00429     // to suppress compiler warnings such as -Wimplicit-fallthrough in gcc
00430     switch (*length) {
00431         case 4:
00432             --output;
00433             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00434             input >>= 6;
00435             //fall through
00436         case 3:
00437             --output;
00438             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00439             input >>= 6;
00440             //fall through
00441         case 2:
00442             --output;
00443             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00444             input >>= 6;
00445             //fall through
00446         case 1:
00447             --output;
00448             *output = (char)(input | FIRST_BYTE_MARK[*length]);
00449             break;
00450         default:
00451             TIXMLASSERT( false );
00452     }
00453 }
00454 
00455 
00456 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
00457 {
00458     // Presume an entity, and pull it out.
00459     *length = 0;
00460 
00461     if ( *(p+1) == '#' && *(p+2) ) {
00462         unsigned long ucs = 0;
00463         TIXMLASSERT( sizeof( ucs ) >= 4 );
00464         ptrdiff_t delta = 0;
00465         unsigned mult = 1;
00466         static const char SEMICOLON = ';';
00467 
00468         if ( *(p+2) == 'x' ) {
00469             // Hexadecimal.
00470             const char* q = p+3;
00471             if ( !(*q) ) {
00472                 return 0;
00473             }
00474 
00475             q = strchr( q, SEMICOLON );
00476 
00477             if ( !q ) {
00478                 return 0;
00479             }
00480             TIXMLASSERT( *q == SEMICOLON );
00481 
00482             delta = q-p;
00483             --q;
00484 
00485             while ( *q != 'x' ) {
00486                 unsigned int digit = 0;
00487 
00488                 if ( *q >= '0' && *q <= '9' ) {
00489                     digit = *q - '0';
00490                 }
00491                 else if ( *q >= 'a' && *q <= 'f' ) {
00492                     digit = *q - 'a' + 10;
00493                 }
00494                 else if ( *q >= 'A' && *q <= 'F' ) {
00495                     digit = *q - 'A' + 10;
00496                 }
00497                 else {
00498                     return 0;
00499                 }
00500                 TIXMLASSERT( digit < 16 );
00501                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
00502                 const unsigned int digitScaled = mult * digit;
00503                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
00504                 ucs += digitScaled;
00505                 TIXMLASSERT( mult <= UINT_MAX / 16 );
00506                 mult *= 16;
00507                 --q;
00508             }
00509         }
00510         else {
00511             // Decimal.
00512             const char* q = p+2;
00513             if ( !(*q) ) {
00514                 return 0;
00515             }
00516 
00517             q = strchr( q, SEMICOLON );
00518 
00519             if ( !q ) {
00520                 return 0;
00521             }
00522             TIXMLASSERT( *q == SEMICOLON );
00523 
00524             delta = q-p;
00525             --q;
00526 
00527             while ( *q != '#' ) {
00528                 if ( *q >= '0' && *q <= '9' ) {
00529                     const unsigned int digit = *q - '0';
00530                     TIXMLASSERT( digit < 10 );
00531                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
00532                     const unsigned int digitScaled = mult * digit;
00533                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
00534                     ucs += digitScaled;
00535                 }
00536                 else {
00537                     return 0;
00538                 }
00539                 TIXMLASSERT( mult <= UINT_MAX / 10 );
00540                 mult *= 10;
00541                 --q;
00542             }
00543         }
00544         // convert the UCS to UTF-8
00545         ConvertUTF32ToUTF8( ucs, value, length );
00546         return p + delta + 1;
00547     }
00548     return p+1;
00549 }
00550 
00551 
00552 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
00553 {
00554     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
00555 }
00556 
00557 
00558 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
00559 {
00560     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
00561 }
00562 
00563 
00564 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
00565 {
00566     TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
00567 }
00568 
00569 /*
00570         ToStr() of a number is a very tricky topic.
00571         https://github.com/leethomason/tinyxml2/issues/106
00572 */
00573 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
00574 {
00575     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
00576 }
00577 
00578 
00579 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
00580 {
00581     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
00582 }
00583 
00584 
00585 void XMLUtil::ToStr(int64_t v, char* buffer, int bufferSize)
00586 {
00587         // horrible syntax trick to make the compiler happy about %lld
00588         TIXML_SNPRINTF(buffer, bufferSize, "%lld", (long long)v);
00589 }
00590 
00591 
00592 bool XMLUtil::ToInt( const char* str, int* value )
00593 {
00594     if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
00595         return true;
00596     }
00597     return false;
00598 }
00599 
00600 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
00601 {
00602     if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
00603         return true;
00604     }
00605     return false;
00606 }
00607 
00608 bool XMLUtil::ToBool( const char* str, bool* value )
00609 {
00610     int ival = 0;
00611     if ( ToInt( str, &ival )) {
00612         *value = (ival==0) ? false : true;
00613         return true;
00614     }
00615     if ( StringEqual( str, "true" ) ) {
00616         *value = true;
00617         return true;
00618     }
00619     else if ( StringEqual( str, "false" ) ) {
00620         *value = false;
00621         return true;
00622     }
00623     return false;
00624 }
00625 
00626 
00627 bool XMLUtil::ToFloat( const char* str, float* value )
00628 {
00629     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
00630         return true;
00631     }
00632     return false;
00633 }
00634 
00635 
00636 bool XMLUtil::ToDouble( const char* str, double* value )
00637 {
00638     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
00639         return true;
00640     }
00641     return false;
00642 }
00643 
00644 
00645 bool XMLUtil::ToInt64(const char* str, int64_t* value)
00646 {
00647         long long v = 0;        // horrible syntax trick to make the compiler happy about %lld
00648         if (TIXML_SSCANF(str, "%lld", &v) == 1) {
00649                 *value = (int64_t)v;
00650                 return true;
00651         }
00652         return false;
00653 }
00654 
00655 
00656 char* XMLDocument::Identify( char* p, XMLNode** node )
00657 {
00658     TIXMLASSERT( node );
00659     TIXMLASSERT( p );
00660     char* const start = p;
00661     int const startLine = _parseCurLineNum;
00662     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
00663     if( !*p ) {
00664         *node = 0;
00665         TIXMLASSERT( p );
00666         return p;
00667     }
00668 
00669     // These strings define the matching patterns:
00670     static const char* xmlHeader                = { "<?" };
00671     static const char* commentHeader    = { "<!--" };
00672     static const char* cdataHeader              = { "<![CDATA[" };
00673     static const char* dtdHeader                = { "<!" };
00674     static const char* elementHeader    = { "<" };      // and a header for everything else; check last.
00675 
00676     static const int xmlHeaderLen               = 2;
00677     static const int commentHeaderLen   = 4;
00678     static const int cdataHeaderLen             = 9;
00679     static const int dtdHeaderLen               = 2;
00680     static const int elementHeaderLen   = 1;
00681 
00682     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );                // use same memory pool
00683     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
00684     XMLNode* returnNode = 0;
00685     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
00686         returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
00687         returnNode->_parseLineNum = _parseCurLineNum;
00688         p += xmlHeaderLen;
00689     }
00690     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
00691         returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
00692         returnNode->_parseLineNum = _parseCurLineNum;
00693         p += commentHeaderLen;
00694     }
00695     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
00696         XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
00697         returnNode = text;
00698         returnNode->_parseLineNum = _parseCurLineNum;
00699         p += cdataHeaderLen;
00700         text->SetCData( true );
00701     }
00702     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
00703         returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
00704         returnNode->_parseLineNum = _parseCurLineNum;
00705         p += dtdHeaderLen;
00706     }
00707     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
00708         returnNode =  CreateUnlinkedNode<XMLElement>( _elementPool );
00709         returnNode->_parseLineNum = _parseCurLineNum;
00710         p += elementHeaderLen;
00711     }
00712     else {
00713         returnNode = CreateUnlinkedNode<XMLText>( _textPool );
00714         returnNode->_parseLineNum = _parseCurLineNum; // Report line of first non-whitespace character
00715         p = start;      // Back it up, all the text counts.
00716         _parseCurLineNum = startLine;
00717     }
00718 
00719     TIXMLASSERT( returnNode );
00720     TIXMLASSERT( p );
00721     *node = returnNode;
00722     return p;
00723 }
00724 
00725 
00726 bool XMLDocument::Accept( XMLVisitor* visitor ) const
00727 {
00728     TIXMLASSERT( visitor );
00729     if ( visitor->VisitEnter( *this ) ) {
00730         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
00731             if ( !node->Accept( visitor ) ) {
00732                 break;
00733             }
00734         }
00735     }
00736     return visitor->VisitExit( *this );
00737 }
00738 
00739 
00740 // --------- XMLNode ----------- //
00741 
00742 XMLNode::XMLNode( XMLDocument* doc ) :
00743     _document( doc ),
00744     _parent( 0 ),
00745     _value(),
00746     _parseLineNum( 0 ),
00747     _firstChild( 0 ), _lastChild( 0 ),
00748     _prev( 0 ), _next( 0 ),
00749         _userData( 0 ),
00750     _memPool( 0 )
00751 {
00752 }
00753 
00754 
00755 XMLNode::~XMLNode()
00756 {
00757     DeleteChildren();
00758     if ( _parent ) {
00759         _parent->Unlink( this );
00760     }
00761 }
00762 
00763 const char* XMLNode::Value() const
00764 {
00765     // Edge case: XMLDocuments don't have a Value. Return null.
00766     if ( this->ToDocument() )
00767         return 0;
00768     return _value.GetStr();
00769 }
00770 
00771 void XMLNode::SetValue( const char* str, bool staticMem )
00772 {
00773     if ( staticMem ) {
00774         _value.SetInternedStr( str );
00775     }
00776     else {
00777         _value.SetStr( str );
00778     }
00779 }
00780 
00781 XMLNode* XMLNode::DeepClone(XMLDocument* target) const
00782 {
00783         XMLNode* clone = this->ShallowClone(target);
00784         if (!clone) return 0;
00785 
00786         for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
00787                 XMLNode* childClone = child->DeepClone(target);
00788                 TIXMLASSERT(childClone);
00789                 clone->InsertEndChild(childClone);
00790         }
00791         return clone;
00792 }
00793 
00794 void XMLNode::DeleteChildren()
00795 {
00796     while( _firstChild ) {
00797         TIXMLASSERT( _lastChild );
00798         DeleteChild( _firstChild );
00799     }
00800     _firstChild = _lastChild = 0;
00801 }
00802 
00803 
00804 void XMLNode::Unlink( XMLNode* child )
00805 {
00806     TIXMLASSERT( child );
00807     TIXMLASSERT( child->_document == _document );
00808     TIXMLASSERT( child->_parent == this );
00809     if ( child == _firstChild ) {
00810         _firstChild = _firstChild->_next;
00811     }
00812     if ( child == _lastChild ) {
00813         _lastChild = _lastChild->_prev;
00814     }
00815 
00816     if ( child->_prev ) {
00817         child->_prev->_next = child->_next;
00818     }
00819     if ( child->_next ) {
00820         child->_next->_prev = child->_prev;
00821     }
00822         child->_next = 0;
00823         child->_prev = 0;
00824         child->_parent = 0;
00825 }
00826 
00827 
00828 void XMLNode::DeleteChild( XMLNode* node )
00829 {
00830     TIXMLASSERT( node );
00831     TIXMLASSERT( node->_document == _document );
00832     TIXMLASSERT( node->_parent == this );
00833     Unlink( node );
00834         TIXMLASSERT(node->_prev == 0);
00835         TIXMLASSERT(node->_next == 0);
00836         TIXMLASSERT(node->_parent == 0);
00837     DeleteNode( node );
00838 }
00839 
00840 
00841 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
00842 {
00843     TIXMLASSERT( addThis );
00844     if ( addThis->_document != _document ) {
00845         TIXMLASSERT( false );
00846         return 0;
00847     }
00848     InsertChildPreamble( addThis );
00849 
00850     if ( _lastChild ) {
00851         TIXMLASSERT( _firstChild );
00852         TIXMLASSERT( _lastChild->_next == 0 );
00853         _lastChild->_next = addThis;
00854         addThis->_prev = _lastChild;
00855         _lastChild = addThis;
00856 
00857         addThis->_next = 0;
00858     }
00859     else {
00860         TIXMLASSERT( _firstChild == 0 );
00861         _firstChild = _lastChild = addThis;
00862 
00863         addThis->_prev = 0;
00864         addThis->_next = 0;
00865     }
00866     addThis->_parent = this;
00867     return addThis;
00868 }
00869 
00870 
00871 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
00872 {
00873     TIXMLASSERT( addThis );
00874     if ( addThis->_document != _document ) {
00875         TIXMLASSERT( false );
00876         return 0;
00877     }
00878     InsertChildPreamble( addThis );
00879 
00880     if ( _firstChild ) {
00881         TIXMLASSERT( _lastChild );
00882         TIXMLASSERT( _firstChild->_prev == 0 );
00883 
00884         _firstChild->_prev = addThis;
00885         addThis->_next = _firstChild;
00886         _firstChild = addThis;
00887 
00888         addThis->_prev = 0;
00889     }
00890     else {
00891         TIXMLASSERT( _lastChild == 0 );
00892         _firstChild = _lastChild = addThis;
00893 
00894         addThis->_prev = 0;
00895         addThis->_next = 0;
00896     }
00897     addThis->_parent = this;
00898     return addThis;
00899 }
00900 
00901 
00902 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
00903 {
00904     TIXMLASSERT( addThis );
00905     if ( addThis->_document != _document ) {
00906         TIXMLASSERT( false );
00907         return 0;
00908     }
00909 
00910     TIXMLASSERT( afterThis );
00911 
00912     if ( afterThis->_parent != this ) {
00913         TIXMLASSERT( false );
00914         return 0;
00915     }
00916     if ( afterThis == addThis ) {
00917         // Current state: BeforeThis -> AddThis -> OneAfterAddThis
00918         // Now AddThis must disappear from it's location and then
00919         // reappear between BeforeThis and OneAfterAddThis.
00920         // So just leave it where it is.
00921         return addThis;
00922     }
00923 
00924     if ( afterThis->_next == 0 ) {
00925         // The last node or the only node.
00926         return InsertEndChild( addThis );
00927     }
00928     InsertChildPreamble( addThis );
00929     addThis->_prev = afterThis;
00930     addThis->_next = afterThis->_next;
00931     afterThis->_next->_prev = addThis;
00932     afterThis->_next = addThis;
00933     addThis->_parent = this;
00934     return addThis;
00935 }
00936 
00937 
00938 
00939 
00940 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
00941 {
00942     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
00943         const XMLElement* element = node->ToElementWithName( name );
00944         if ( element ) {
00945             return element;
00946         }
00947     }
00948     return 0;
00949 }
00950 
00951 
00952 const XMLElement* XMLNode::LastChildElement( const char* name ) const
00953 {
00954     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
00955         const XMLElement* element = node->ToElementWithName( name );
00956         if ( element ) {
00957             return element;
00958         }
00959     }
00960     return 0;
00961 }
00962 
00963 
00964 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
00965 {
00966     for( const XMLNode* node = _next; node; node = node->_next ) {
00967         const XMLElement* element = node->ToElementWithName( name );
00968         if ( element ) {
00969             return element;
00970         }
00971     }
00972     return 0;
00973 }
00974 
00975 
00976 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
00977 {
00978     for( const XMLNode* node = _prev; node; node = node->_prev ) {
00979         const XMLElement* element = node->ToElementWithName( name );
00980         if ( element ) {
00981             return element;
00982         }
00983     }
00984     return 0;
00985 }
00986 
00987 
00988 char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
00989 {
00990     // This is a recursive method, but thinking about it "at the current level"
00991     // it is a pretty simple flat list:
00992     //          <foo/>
00993     //          <!-- comment -->
00994     //
00995     // With a special case:
00996     //          <foo>
00997     //          </foo>
00998     //          <!-- comment -->
00999     //
01000     // Where the closing element (/foo) *must* be the next thing after the opening
01001     // element, and the names must match. BUT the tricky bit is that the closing
01002     // element will be read by the child.
01003     //
01004     // 'endTag' is the end tag for this node, it is returned by a call to a child.
01005     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
01006 
01007         XMLDocument::DepthTracker tracker(_document);
01008         if (_document->Error())
01009                 return 0;
01010 
01011         while( p && *p ) {
01012         XMLNode* node = 0;
01013 
01014         p = _document->Identify( p, &node );
01015         TIXMLASSERT( p );
01016         if ( node == 0 ) {
01017             break;
01018         }
01019 
01020         int initialLineNum = node->_parseLineNum;
01021 
01022         StrPair endTag;
01023         p = node->ParseDeep( p, &endTag, curLineNumPtr );
01024         if ( !p ) {
01025             DeleteNode( node );
01026             if ( !_document->Error() ) {
01027                 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
01028             }
01029             break;
01030         }
01031 
01032         XMLDeclaration* decl = node->ToDeclaration();
01033         if ( decl ) {
01034             // Declarations are only allowed at document level
01035             //
01036             // Multiple declarations are allowed but all declarations
01037             // must occur before anything else. 
01038             //
01039             // Optimized due to a security test case. If the first node is 
01040             // a declaration, and the last node is a declaration, then only 
01041             // declarations have so far been addded.
01042             bool wellLocated = false;
01043 
01044             if (ToDocument()) {
01045                 if (FirstChild()) {
01046                     wellLocated =
01047                         FirstChild() &&
01048                         FirstChild()->ToDeclaration() &&
01049                         LastChild() &&
01050                         LastChild()->ToDeclaration();
01051                 }
01052                 else {
01053                     wellLocated = true;
01054                 }
01055             }
01056             if ( !wellLocated ) {
01057                 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
01058                 DeleteNode( node );
01059                 break;
01060             }
01061         }
01062 
01063         XMLElement* ele = node->ToElement();
01064         if ( ele ) {
01065             // We read the end tag. Return it to the parent.
01066             if ( ele->ClosingType() == XMLElement::CLOSING ) {
01067                 if ( parentEndTag ) {
01068                     ele->_value.TransferTo( parentEndTag );
01069                 }
01070                 node->_memPool->SetTracked();   // created and then immediately deleted.
01071                 DeleteNode( node );
01072                 return p;
01073             }
01074 
01075             // Handle an end tag returned to this level.
01076             // And handle a bunch of annoying errors.
01077             bool mismatch = false;
01078             if ( endTag.Empty() ) {
01079                 if ( ele->ClosingType() == XMLElement::OPEN ) {
01080                     mismatch = true;
01081                 }
01082             }
01083             else {
01084                 if ( ele->ClosingType() != XMLElement::OPEN ) {
01085                     mismatch = true;
01086                 }
01087                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
01088                     mismatch = true;
01089                 }
01090             }
01091             if ( mismatch ) {
01092                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
01093                 DeleteNode( node );
01094                 break;
01095             }
01096         }
01097         InsertEndChild( node );
01098     }
01099     return 0;
01100 }
01101 
01102 /*static*/ void XMLNode::DeleteNode( XMLNode* node )
01103 {
01104     if ( node == 0 ) {
01105         return;
01106     }
01107         TIXMLASSERT(node->_document);
01108         if (!node->ToDocument()) {
01109                 node->_document->MarkInUse(node);
01110         }
01111 
01112     MemPool* pool = node->_memPool;
01113     node->~XMLNode();
01114     pool->Free( node );
01115 }
01116 
01117 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
01118 {
01119     TIXMLASSERT( insertThis );
01120     TIXMLASSERT( insertThis->_document == _document );
01121 
01122         if (insertThis->_parent) {
01123         insertThis->_parent->Unlink( insertThis );
01124         }
01125         else {
01126                 insertThis->_document->MarkInUse(insertThis);
01127         insertThis->_memPool->SetTracked();
01128         }
01129 }
01130 
01131 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
01132 {
01133     const XMLElement* element = this->ToElement();
01134     if ( element == 0 ) {
01135         return 0;
01136     }
01137     if ( name == 0 ) {
01138         return element;
01139     }
01140     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
01141        return element;
01142     }
01143     return 0;
01144 }
01145 
01146 // --------- XMLText ---------- //
01147 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01148 {
01149     if ( this->CData() ) {
01150         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
01151         if ( !p ) {
01152             _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
01153         }
01154         return p;
01155     }
01156     else {
01157         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
01158         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
01159             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
01160         }
01161 
01162         p = _value.ParseText( p, "<", flags, curLineNumPtr );
01163         if ( p && *p ) {
01164             return p-1;
01165         }
01166         if ( !p ) {
01167             _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
01168         }
01169     }
01170     return 0;
01171 }
01172 
01173 
01174 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
01175 {
01176     if ( !doc ) {
01177         doc = _document;
01178     }
01179     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
01180     text->SetCData( this->CData() );
01181     return text;
01182 }
01183 
01184 
01185 bool XMLText::ShallowEqual( const XMLNode* compare ) const
01186 {
01187     TIXMLASSERT( compare );
01188     const XMLText* text = compare->ToText();
01189     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
01190 }
01191 
01192 
01193 bool XMLText::Accept( XMLVisitor* visitor ) const
01194 {
01195     TIXMLASSERT( visitor );
01196     return visitor->Visit( *this );
01197 }
01198 
01199 
01200 // --------- XMLComment ---------- //
01201 
01202 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
01203 {
01204 }
01205 
01206 
01207 XMLComment::~XMLComment()
01208 {
01209 }
01210 
01211 
01212 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01213 {
01214     // Comment parses as text.
01215     p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
01216     if ( p == 0 ) {
01217         _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
01218     }
01219     return p;
01220 }
01221 
01222 
01223 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
01224 {
01225     if ( !doc ) {
01226         doc = _document;
01227     }
01228     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?
01229     return comment;
01230 }
01231 
01232 
01233 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
01234 {
01235     TIXMLASSERT( compare );
01236     const XMLComment* comment = compare->ToComment();
01237     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
01238 }
01239 
01240 
01241 bool XMLComment::Accept( XMLVisitor* visitor ) const
01242 {
01243     TIXMLASSERT( visitor );
01244     return visitor->Visit( *this );
01245 }
01246 
01247 
01248 // --------- XMLDeclaration ---------- //
01249 
01250 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
01251 {
01252 }
01253 
01254 
01255 XMLDeclaration::~XMLDeclaration()
01256 {
01257     //printf( "~XMLDeclaration\n" );
01258 }
01259 
01260 
01261 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01262 {
01263     // Declaration parses as text.
01264     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
01265     if ( p == 0 ) {
01266         _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
01267     }
01268     return p;
01269 }
01270 
01271 
01272 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
01273 {
01274     if ( !doc ) {
01275         doc = _document;
01276     }
01277     XMLDeclaration* dec = doc->NewDeclaration( Value() );       // fixme: this will always allocate memory. Intern?
01278     return dec;
01279 }
01280 
01281 
01282 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
01283 {
01284     TIXMLASSERT( compare );
01285     const XMLDeclaration* declaration = compare->ToDeclaration();
01286     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
01287 }
01288 
01289 
01290 
01291 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
01292 {
01293     TIXMLASSERT( visitor );
01294     return visitor->Visit( *this );
01295 }
01296 
01297 // --------- XMLUnknown ---------- //
01298 
01299 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
01300 {
01301 }
01302 
01303 
01304 XMLUnknown::~XMLUnknown()
01305 {
01306 }
01307 
01308 
01309 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01310 {
01311     // Unknown parses as text.
01312     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
01313     if ( !p ) {
01314         _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
01315     }
01316     return p;
01317 }
01318 
01319 
01320 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
01321 {
01322     if ( !doc ) {
01323         doc = _document;
01324     }
01325     XMLUnknown* text = doc->NewUnknown( Value() );      // fixme: this will always allocate memory. Intern?
01326     return text;
01327 }
01328 
01329 
01330 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
01331 {
01332     TIXMLASSERT( compare );
01333     const XMLUnknown* unknown = compare->ToUnknown();
01334     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
01335 }
01336 
01337 
01338 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
01339 {
01340     TIXMLASSERT( visitor );
01341     return visitor->Visit( *this );
01342 }
01343 
01344 // --------- XMLAttribute ---------- //
01345 
01346 const char* XMLAttribute::Name() const
01347 {
01348     return _name.GetStr();
01349 }
01350 
01351 const char* XMLAttribute::Value() const
01352 {
01353     return _value.GetStr();
01354 }
01355 
01356 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
01357 {
01358     // Parse using the name rules: bug fix, was using ParseText before
01359     p = _name.ParseName( p );
01360     if ( !p || !*p ) {
01361         return 0;
01362     }
01363 
01364     // Skip white space before =
01365     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01366     if ( *p != '=' ) {
01367         return 0;
01368     }
01369 
01370     ++p;        // move up to opening quote
01371     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01372     if ( *p != '\"' && *p != '\'' ) {
01373         return 0;
01374     }
01375 
01376     char endTag[2] = { *p, 0 };
01377     ++p;        // move past opening quote
01378 
01379     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
01380     return p;
01381 }
01382 
01383 
01384 void XMLAttribute::SetName( const char* n )
01385 {
01386     _name.SetStr( n );
01387 }
01388 
01389 
01390 XMLError XMLAttribute::QueryIntValue( int* value ) const
01391 {
01392     if ( XMLUtil::ToInt( Value(), value )) {
01393         return XML_SUCCESS;
01394     }
01395     return XML_WRONG_ATTRIBUTE_TYPE;
01396 }
01397 
01398 
01399 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
01400 {
01401     if ( XMLUtil::ToUnsigned( Value(), value )) {
01402         return XML_SUCCESS;
01403     }
01404     return XML_WRONG_ATTRIBUTE_TYPE;
01405 }
01406 
01407 
01408 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
01409 {
01410         if (XMLUtil::ToInt64(Value(), value)) {
01411                 return XML_SUCCESS;
01412         }
01413         return XML_WRONG_ATTRIBUTE_TYPE;
01414 }
01415 
01416 
01417 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
01418 {
01419     if ( XMLUtil::ToBool( Value(), value )) {
01420         return XML_SUCCESS;
01421     }
01422     return XML_WRONG_ATTRIBUTE_TYPE;
01423 }
01424 
01425 
01426 XMLError XMLAttribute::QueryFloatValue( float* value ) const
01427 {
01428     if ( XMLUtil::ToFloat( Value(), value )) {
01429         return XML_SUCCESS;
01430     }
01431     return XML_WRONG_ATTRIBUTE_TYPE;
01432 }
01433 
01434 
01435 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
01436 {
01437     if ( XMLUtil::ToDouble( Value(), value )) {
01438         return XML_SUCCESS;
01439     }
01440     return XML_WRONG_ATTRIBUTE_TYPE;
01441 }
01442 
01443 
01444 void XMLAttribute::SetAttribute( const char* v )
01445 {
01446     _value.SetStr( v );
01447 }
01448 
01449 
01450 void XMLAttribute::SetAttribute( int v )
01451 {
01452     char buf[BUF_SIZE];
01453     XMLUtil::ToStr( v, buf, BUF_SIZE );
01454     _value.SetStr( buf );
01455 }
01456 
01457 
01458 void XMLAttribute::SetAttribute( unsigned v )
01459 {
01460     char buf[BUF_SIZE];
01461     XMLUtil::ToStr( v, buf, BUF_SIZE );
01462     _value.SetStr( buf );
01463 }
01464 
01465 
01466 void XMLAttribute::SetAttribute(int64_t v)
01467 {
01468         char buf[BUF_SIZE];
01469         XMLUtil::ToStr(v, buf, BUF_SIZE);
01470         _value.SetStr(buf);
01471 }
01472 
01473 
01474 
01475 void XMLAttribute::SetAttribute( bool v )
01476 {
01477     char buf[BUF_SIZE];
01478     XMLUtil::ToStr( v, buf, BUF_SIZE );
01479     _value.SetStr( buf );
01480 }
01481 
01482 void XMLAttribute::SetAttribute( double v )
01483 {
01484     char buf[BUF_SIZE];
01485     XMLUtil::ToStr( v, buf, BUF_SIZE );
01486     _value.SetStr( buf );
01487 }
01488 
01489 void XMLAttribute::SetAttribute( float v )
01490 {
01491     char buf[BUF_SIZE];
01492     XMLUtil::ToStr( v, buf, BUF_SIZE );
01493     _value.SetStr( buf );
01494 }
01495 
01496 
01497 // --------- XMLElement ---------- //
01498 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
01499     _closingType( OPEN ),
01500     _rootAttribute( 0 )
01501 {
01502 }
01503 
01504 
01505 XMLElement::~XMLElement()
01506 {
01507     while( _rootAttribute ) {
01508         XMLAttribute* next = _rootAttribute->_next;
01509         DeleteAttribute( _rootAttribute );
01510         _rootAttribute = next;
01511     }
01512 }
01513 
01514 
01515 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
01516 {
01517     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
01518         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
01519             return a;
01520         }
01521     }
01522     return 0;
01523 }
01524 
01525 
01526 const char* XMLElement::Attribute( const char* name, const char* value ) const
01527 {
01528     const XMLAttribute* a = FindAttribute( name );
01529     if ( !a ) {
01530         return 0;
01531     }
01532     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
01533         return a->Value();
01534     }
01535     return 0;
01536 }
01537 
01538 int XMLElement::IntAttribute(const char* name, int defaultValue) const
01539 {
01540         int i = defaultValue;
01541         QueryIntAttribute(name, &i);
01542         return i;
01543 }
01544 
01545 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
01546 {
01547         unsigned i = defaultValue;
01548         QueryUnsignedAttribute(name, &i);
01549         return i;
01550 }
01551 
01552 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
01553 {
01554         int64_t i = defaultValue;
01555         QueryInt64Attribute(name, &i);
01556         return i;
01557 }
01558 
01559 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
01560 {
01561         bool b = defaultValue;
01562         QueryBoolAttribute(name, &b);
01563         return b;
01564 }
01565 
01566 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
01567 {
01568         double d = defaultValue;
01569         QueryDoubleAttribute(name, &d);
01570         return d;
01571 }
01572 
01573 float XMLElement::FloatAttribute(const char* name, float defaultValue) const
01574 {
01575         float f = defaultValue;
01576         QueryFloatAttribute(name, &f);
01577         return f;
01578 }
01579 
01580 const char* XMLElement::GetText() const
01581 {
01582     if ( FirstChild() && FirstChild()->ToText() ) {
01583         return FirstChild()->Value();
01584     }
01585     return 0;
01586 }
01587 
01588 
01589 void    XMLElement::SetText( const char* inText )
01590 {
01591         if ( FirstChild() && FirstChild()->ToText() )
01592                 FirstChild()->SetValue( inText );
01593         else {
01594                 XMLText*        theText = GetDocument()->NewText( inText );
01595                 InsertFirstChild( theText );
01596         }
01597 }
01598 
01599 
01600 void XMLElement::SetText( int v )
01601 {
01602     char buf[BUF_SIZE];
01603     XMLUtil::ToStr( v, buf, BUF_SIZE );
01604     SetText( buf );
01605 }
01606 
01607 
01608 void XMLElement::SetText( unsigned v )
01609 {
01610     char buf[BUF_SIZE];
01611     XMLUtil::ToStr( v, buf, BUF_SIZE );
01612     SetText( buf );
01613 }
01614 
01615 
01616 void XMLElement::SetText(int64_t v)
01617 {
01618         char buf[BUF_SIZE];
01619         XMLUtil::ToStr(v, buf, BUF_SIZE);
01620         SetText(buf);
01621 }
01622 
01623 
01624 void XMLElement::SetText( bool v )
01625 {
01626     char buf[BUF_SIZE];
01627     XMLUtil::ToStr( v, buf, BUF_SIZE );
01628     SetText( buf );
01629 }
01630 
01631 
01632 void XMLElement::SetText( float v )
01633 {
01634     char buf[BUF_SIZE];
01635     XMLUtil::ToStr( v, buf, BUF_SIZE );
01636     SetText( buf );
01637 }
01638 
01639 
01640 void XMLElement::SetText( double v )
01641 {
01642     char buf[BUF_SIZE];
01643     XMLUtil::ToStr( v, buf, BUF_SIZE );
01644     SetText( buf );
01645 }
01646 
01647 
01648 XMLError XMLElement::QueryIntText( int* ival ) const
01649 {
01650     if ( FirstChild() && FirstChild()->ToText() ) {
01651         const char* t = FirstChild()->Value();
01652         if ( XMLUtil::ToInt( t, ival ) ) {
01653             return XML_SUCCESS;
01654         }
01655         return XML_CAN_NOT_CONVERT_TEXT;
01656     }
01657     return XML_NO_TEXT_NODE;
01658 }
01659 
01660 
01661 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
01662 {
01663     if ( FirstChild() && FirstChild()->ToText() ) {
01664         const char* t = FirstChild()->Value();
01665         if ( XMLUtil::ToUnsigned( t, uval ) ) {
01666             return XML_SUCCESS;
01667         }
01668         return XML_CAN_NOT_CONVERT_TEXT;
01669     }
01670     return XML_NO_TEXT_NODE;
01671 }
01672 
01673 
01674 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
01675 {
01676         if (FirstChild() && FirstChild()->ToText()) {
01677                 const char* t = FirstChild()->Value();
01678                 if (XMLUtil::ToInt64(t, ival)) {
01679                         return XML_SUCCESS;
01680                 }
01681                 return XML_CAN_NOT_CONVERT_TEXT;
01682         }
01683         return XML_NO_TEXT_NODE;
01684 }
01685 
01686 
01687 XMLError XMLElement::QueryBoolText( bool* bval ) const
01688 {
01689     if ( FirstChild() && FirstChild()->ToText() ) {
01690         const char* t = FirstChild()->Value();
01691         if ( XMLUtil::ToBool( t, bval ) ) {
01692             return XML_SUCCESS;
01693         }
01694         return XML_CAN_NOT_CONVERT_TEXT;
01695     }
01696     return XML_NO_TEXT_NODE;
01697 }
01698 
01699 
01700 XMLError XMLElement::QueryDoubleText( double* dval ) const
01701 {
01702     if ( FirstChild() && FirstChild()->ToText() ) {
01703         const char* t = FirstChild()->Value();
01704         if ( XMLUtil::ToDouble( t, dval ) ) {
01705             return XML_SUCCESS;
01706         }
01707         return XML_CAN_NOT_CONVERT_TEXT;
01708     }
01709     return XML_NO_TEXT_NODE;
01710 }
01711 
01712 
01713 XMLError XMLElement::QueryFloatText( float* fval ) const
01714 {
01715     if ( FirstChild() && FirstChild()->ToText() ) {
01716         const char* t = FirstChild()->Value();
01717         if ( XMLUtil::ToFloat( t, fval ) ) {
01718             return XML_SUCCESS;
01719         }
01720         return XML_CAN_NOT_CONVERT_TEXT;
01721     }
01722     return XML_NO_TEXT_NODE;
01723 }
01724 
01725 int XMLElement::IntText(int defaultValue) const
01726 {
01727         int i = defaultValue;
01728         QueryIntText(&i);
01729         return i;
01730 }
01731 
01732 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
01733 {
01734         unsigned i = defaultValue;
01735         QueryUnsignedText(&i);
01736         return i;
01737 }
01738 
01739 int64_t XMLElement::Int64Text(int64_t defaultValue) const
01740 {
01741         int64_t i = defaultValue;
01742         QueryInt64Text(&i);
01743         return i;
01744 }
01745 
01746 bool XMLElement::BoolText(bool defaultValue) const
01747 {
01748         bool b = defaultValue;
01749         QueryBoolText(&b);
01750         return b;
01751 }
01752 
01753 double XMLElement::DoubleText(double defaultValue) const
01754 {
01755         double d = defaultValue;
01756         QueryDoubleText(&d);
01757         return d;
01758 }
01759 
01760 float XMLElement::FloatText(float defaultValue) const
01761 {
01762         float f = defaultValue;
01763         QueryFloatText(&f);
01764         return f;
01765 }
01766 
01767 
01768 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
01769 {
01770     XMLAttribute* last = 0;
01771     XMLAttribute* attrib = 0;
01772     for( attrib = _rootAttribute;
01773             attrib;
01774             last = attrib, attrib = attrib->_next ) {
01775         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
01776             break;
01777         }
01778     }
01779     if ( !attrib ) {
01780         attrib = CreateAttribute();
01781         TIXMLASSERT( attrib );
01782         if ( last ) {
01783             TIXMLASSERT( last->_next == 0 );
01784             last->_next = attrib;
01785         }
01786         else {
01787             TIXMLASSERT( _rootAttribute == 0 );
01788             _rootAttribute = attrib;
01789         }
01790         attrib->SetName( name );
01791     }
01792     return attrib;
01793 }
01794 
01795 
01796 void XMLElement::DeleteAttribute( const char* name )
01797 {
01798     XMLAttribute* prev = 0;
01799     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
01800         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
01801             if ( prev ) {
01802                 prev->_next = a->_next;
01803             }
01804             else {
01805                 _rootAttribute = a->_next;
01806             }
01807             DeleteAttribute( a );
01808             break;
01809         }
01810         prev = a;
01811     }
01812 }
01813 
01814 
01815 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
01816 {
01817     XMLAttribute* prevAttribute = 0;
01818 
01819     // Read the attributes.
01820     while( p ) {
01821         p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01822         if ( !(*p) ) {
01823             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
01824             return 0;
01825         }
01826 
01827         // attribute.
01828         if (XMLUtil::IsNameStartChar( *p ) ) {
01829             XMLAttribute* attrib = CreateAttribute();
01830             TIXMLASSERT( attrib );
01831             attrib->_parseLineNum = _document->_parseCurLineNum;
01832 
01833             int attrLineNum = attrib->_parseLineNum;
01834 
01835             p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
01836             if ( !p || Attribute( attrib->Name() ) ) {
01837                 DeleteAttribute( attrib );
01838                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
01839                 return 0;
01840             }
01841             // There is a minor bug here: if the attribute in the source xml
01842             // document is duplicated, it will not be detected and the
01843             // attribute will be doubly added. However, tracking the 'prevAttribute'
01844             // avoids re-scanning the attribute list. Preferring performance for
01845             // now, may reconsider in the future.
01846             if ( prevAttribute ) {
01847                 TIXMLASSERT( prevAttribute->_next == 0 );
01848                 prevAttribute->_next = attrib;
01849             }
01850             else {
01851                 TIXMLASSERT( _rootAttribute == 0 );
01852                 _rootAttribute = attrib;
01853             }
01854             prevAttribute = attrib;
01855         }
01856         // end of the tag
01857         else if ( *p == '>' ) {
01858             ++p;
01859             break;
01860         }
01861         // end of the tag
01862         else if ( *p == '/' && *(p+1) == '>' ) {
01863             _closingType = CLOSED;
01864             return p+2; // done; sealed element.
01865         }
01866         else {
01867             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
01868             return 0;
01869         }
01870     }
01871     return p;
01872 }
01873 
01874 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
01875 {
01876     if ( attribute == 0 ) {
01877         return;
01878     }
01879     MemPool* pool = attribute->_memPool;
01880     attribute->~XMLAttribute();
01881     pool->Free( attribute );
01882 }
01883 
01884 XMLAttribute* XMLElement::CreateAttribute()
01885 {
01886     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
01887     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
01888     TIXMLASSERT( attrib );
01889     attrib->_memPool = &_document->_attributePool;
01890     attrib->_memPool->SetTracked();
01891     return attrib;
01892 }
01893 
01894 //
01895 //      <ele></ele>
01896 //      <ele>foo<b>bar</b></ele>
01897 //
01898 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
01899 {
01900     // Read the element name.
01901     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01902 
01903     // The closing element is the </element> form. It is
01904     // parsed just like a regular element then deleted from
01905     // the DOM.
01906     if ( *p == '/' ) {
01907         _closingType = CLOSING;
01908         ++p;
01909     }
01910 
01911     p = _value.ParseName( p );
01912     if ( _value.Empty() ) {
01913         return 0;
01914     }
01915 
01916     p = ParseAttributes( p, curLineNumPtr );
01917     if ( !p || !*p || _closingType != OPEN ) {
01918         return p;
01919     }
01920 
01921     p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
01922     return p;
01923 }
01924 
01925 
01926 
01927 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
01928 {
01929     if ( !doc ) {
01930         doc = _document;
01931     }
01932     XMLElement* element = doc->NewElement( Value() );                                   // fixme: this will always allocate memory. Intern?
01933     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
01934         element->SetAttribute( a->Name(), a->Value() );                                 // fixme: this will always allocate memory. Intern?
01935     }
01936     return element;
01937 }
01938 
01939 
01940 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
01941 {
01942     TIXMLASSERT( compare );
01943     const XMLElement* other = compare->ToElement();
01944     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
01945 
01946         const XMLAttribute* a=FirstAttribute();
01947         const XMLAttribute* b=other->FirstAttribute();
01948 
01949         while ( a && b ) {
01950             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
01951                 return false;
01952             }
01953             a = a->Next();
01954             b = b->Next();
01955         }
01956         if ( a || b ) {
01957             // different count
01958             return false;
01959         }
01960         return true;
01961     }
01962     return false;
01963 }
01964 
01965 
01966 bool XMLElement::Accept( XMLVisitor* visitor ) const
01967 {
01968     TIXMLASSERT( visitor );
01969     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
01970         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
01971             if ( !node->Accept( visitor ) ) {
01972                 break;
01973             }
01974         }
01975     }
01976     return visitor->VisitExit( *this );
01977 }
01978 
01979 
01980 // --------- XMLDocument ----------- //
01981 
01982 // Warning: List must match 'enum XMLError'
01983 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
01984     "XML_SUCCESS",
01985     "XML_NO_ATTRIBUTE",
01986     "XML_WRONG_ATTRIBUTE_TYPE",
01987     "XML_ERROR_FILE_NOT_FOUND",
01988     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
01989     "XML_ERROR_FILE_READ_ERROR",
01990     "XML_ERROR_PARSING_ELEMENT",
01991     "XML_ERROR_PARSING_ATTRIBUTE",
01992     "XML_ERROR_PARSING_TEXT",
01993     "XML_ERROR_PARSING_CDATA",
01994     "XML_ERROR_PARSING_COMMENT",
01995     "XML_ERROR_PARSING_DECLARATION",
01996     "XML_ERROR_PARSING_UNKNOWN",
01997     "XML_ERROR_EMPTY_DOCUMENT",
01998     "XML_ERROR_MISMATCHED_ELEMENT",
01999     "XML_ERROR_PARSING",
02000     "XML_CAN_NOT_CONVERT_TEXT",
02001     "XML_NO_TEXT_NODE",
02002         "XML_ELEMENT_DEPTH_EXCEEDED"
02003 };
02004 
02005 
02006 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
02007     XMLNode( 0 ),
02008     _writeBOM( false ),
02009     _processEntities( processEntities ),
02010     _errorID(XML_SUCCESS),
02011     _whitespaceMode( whitespaceMode ),
02012     _errorStr(),
02013     _errorLineNum( 0 ),
02014     _charBuffer( 0 ),
02015     _parseCurLineNum( 0 ),
02016         _parsingDepth(0),
02017     _unlinked(),
02018     _elementPool(),
02019     _attributePool(),
02020     _textPool(),
02021     _commentPool()
02022 {
02023     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
02024     _document = this;
02025 }
02026 
02027 
02028 XMLDocument::~XMLDocument()
02029 {
02030     Clear();
02031 }
02032 
02033 
02034 void XMLDocument::MarkInUse(XMLNode* node)
02035 {
02036         TIXMLASSERT(node);
02037         TIXMLASSERT(node->_parent == 0);
02038 
02039         for (int i = 0; i < _unlinked.Size(); ++i) {
02040                 if (node == _unlinked[i]) {
02041                         _unlinked.SwapRemove(i);
02042                         break;
02043                 }
02044         }
02045 }
02046 
02047 void XMLDocument::Clear()
02048 {
02049     DeleteChildren();
02050         while( _unlinked.Size()) {
02051                 DeleteNode(_unlinked[0]);       // Will remove from _unlinked as part of delete.
02052         }
02053 
02054 #ifdef TINYXML2_DEBUG
02055     const bool hadError = Error();
02056 #endif
02057     ClearError();
02058 
02059     delete [] _charBuffer;
02060     _charBuffer = 0;
02061         _parsingDepth = 0;
02062 
02063 #if 0
02064     _textPool.Trace( "text" );
02065     _elementPool.Trace( "element" );
02066     _commentPool.Trace( "comment" );
02067     _attributePool.Trace( "attribute" );
02068 #endif
02069 
02070 #ifdef TINYXML2_DEBUG
02071     if ( !hadError ) {
02072         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
02073         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
02074         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
02075         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
02076     }
02077 #endif
02078 }
02079 
02080 
02081 void XMLDocument::DeepCopy(XMLDocument* target) const
02082 {
02083         TIXMLASSERT(target);
02084     if (target == this) {
02085         return; // technically success - a no-op.
02086     }
02087 
02088         target->Clear();
02089         for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
02090                 target->InsertEndChild(node->DeepClone(target));
02091         }
02092 }
02093 
02094 XMLElement* XMLDocument::NewElement( const char* name )
02095 {
02096     XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
02097     ele->SetName( name );
02098     return ele;
02099 }
02100 
02101 
02102 XMLComment* XMLDocument::NewComment( const char* str )
02103 {
02104     XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
02105     comment->SetValue( str );
02106     return comment;
02107 }
02108 
02109 
02110 XMLText* XMLDocument::NewText( const char* str )
02111 {
02112     XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
02113     text->SetValue( str );
02114     return text;
02115 }
02116 
02117 
02118 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
02119 {
02120     XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
02121     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
02122     return dec;
02123 }
02124 
02125 
02126 XMLUnknown* XMLDocument::NewUnknown( const char* str )
02127 {
02128     XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
02129     unk->SetValue( str );
02130     return unk;
02131 }
02132 
02133 static FILE* callfopen( const char* filepath, const char* mode )
02134 {
02135     TIXMLASSERT( filepath );
02136     TIXMLASSERT( mode );
02137 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
02138     FILE* fp = 0;
02139     errno_t err = fopen_s( &fp, filepath, mode );
02140     if ( err ) {
02141         return 0;
02142     }
02143 #else
02144     FILE* fp = fopen( filepath, mode );
02145 #endif
02146     return fp;
02147 }
02148 
02149 void XMLDocument::DeleteNode( XMLNode* node )   {
02150     TIXMLASSERT( node );
02151     TIXMLASSERT(node->_document == this );
02152     if (node->_parent) {
02153         node->_parent->DeleteChild( node );
02154     }
02155     else {
02156         // Isn't in the tree.
02157         // Use the parent delete.
02158         // Also, we need to mark it tracked: we 'know'
02159         // it was never used.
02160         node->_memPool->SetTracked();
02161         // Call the static XMLNode version:
02162         XMLNode::DeleteNode(node);
02163     }
02164 }
02165 
02166 
02167 XMLError XMLDocument::LoadFile( const char* filename )
02168 {
02169     if ( !filename ) {
02170         TIXMLASSERT( false );
02171         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
02172         return _errorID;
02173     }
02174 
02175     Clear();
02176     FILE* fp = callfopen( filename, "rb" );
02177     if ( !fp ) {
02178         SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
02179         return _errorID;
02180     }
02181     LoadFile( fp );
02182     fclose( fp );
02183     return _errorID;
02184 }
02185 
02186 // This is likely overengineered template art to have a check that unsigned long value incremented
02187 // by one still fits into size_t. If size_t type is larger than unsigned long type
02188 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
02189 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check
02190 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long
02191 // types sizes relate to each other.
02192 template
02193 <bool = (sizeof(unsigned long) >= sizeof(size_t))>
02194 struct LongFitsIntoSizeTMinusOne {
02195     static bool Fits( unsigned long value )
02196     {
02197         return value < (size_t)-1;
02198     }
02199 };
02200 
02201 template <>
02202 struct LongFitsIntoSizeTMinusOne<false> {
02203     static bool Fits( unsigned long )
02204     {
02205         return true;
02206     }
02207 };
02208 
02209 XMLError XMLDocument::LoadFile( FILE* fp )
02210 {
02211     Clear();
02212 
02213     fseek( fp, 0, SEEK_SET );
02214     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
02215         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02216         return _errorID;
02217     }
02218 
02219     fseek( fp, 0, SEEK_END );
02220     const long filelength = ftell( fp );
02221     fseek( fp, 0, SEEK_SET );
02222     if ( filelength == -1L ) {
02223         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02224         return _errorID;
02225     }
02226     TIXMLASSERT( filelength >= 0 );
02227 
02228     if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
02229         // Cannot handle files which won't fit in buffer together with null terminator
02230         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02231         return _errorID;
02232     }
02233 
02234     if ( filelength == 0 ) {
02235         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02236         return _errorID;
02237     }
02238 
02239     const size_t size = filelength;
02240     TIXMLASSERT( _charBuffer == 0 );
02241     _charBuffer = new char[size+1];
02242     size_t read = fread( _charBuffer, 1, size, fp );
02243     if ( read != size ) {
02244         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02245         return _errorID;
02246     }
02247 
02248     _charBuffer[size] = 0;
02249 
02250     Parse();
02251     return _errorID;
02252 }
02253 
02254 
02255 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
02256 {
02257     if ( !filename ) {
02258         TIXMLASSERT( false );
02259         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
02260         return _errorID;
02261     }
02262 
02263     FILE* fp = callfopen( filename, "w" );
02264     if ( !fp ) {
02265         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
02266         return _errorID;
02267     }
02268     SaveFile(fp, compact);
02269     fclose( fp );
02270     return _errorID;
02271 }
02272 
02273 
02274 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
02275 {
02276     // Clear any error from the last save, otherwise it will get reported
02277     // for *this* call.
02278     ClearError();
02279     XMLPrinter stream( fp, compact );
02280     Print( &stream );
02281     return _errorID;
02282 }
02283 
02284 
02285 XMLError XMLDocument::Parse( const char* p, size_t len )
02286 {
02287     Clear();
02288 
02289     if ( len == 0 || !p || !*p ) {
02290         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02291         return _errorID;
02292     }
02293     if ( len == (size_t)(-1) ) {
02294         len = strlen( p );
02295     }
02296     TIXMLASSERT( _charBuffer == 0 );
02297     _charBuffer = new char[ len+1 ];
02298     memcpy( _charBuffer, p, len );
02299     _charBuffer[len] = 0;
02300 
02301     Parse();
02302     if ( Error() ) {
02303         // clean up now essentially dangling memory.
02304         // and the parse fail can put objects in the
02305         // pools that are dead and inaccessible.
02306         DeleteChildren();
02307         _elementPool.Clear();
02308         _attributePool.Clear();
02309         _textPool.Clear();
02310         _commentPool.Clear();
02311     }
02312     return _errorID;
02313 }
02314 
02315 
02316 void XMLDocument::Print( XMLPrinter* streamer ) const
02317 {
02318     if ( streamer ) {
02319         Accept( streamer );
02320     }
02321     else {
02322         XMLPrinter stdoutStreamer( stdout );
02323         Accept( &stdoutStreamer );
02324     }
02325 }
02326 
02327 
02328 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
02329 {
02330     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
02331     _errorID = error;
02332     _errorLineNum = lineNum;
02333         _errorStr.Reset();
02334 
02335     size_t BUFFER_SIZE = 1000;
02336     char* buffer = new char[BUFFER_SIZE];
02337 
02338     TIXMLASSERT(sizeof(error) <= sizeof(int));
02339     TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
02340 
02341         if (format) {
02342                 size_t len = strlen(buffer);
02343                 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
02344                 len = strlen(buffer);
02345 
02346                 va_list va;
02347                 va_start(va, format);
02348                 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
02349                 va_end(va);
02350         }
02351         _errorStr.SetStr(buffer);
02352         delete[] buffer;
02353 }
02354 
02355 
02356 /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
02357 {
02358         TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
02359     const char* errorName = _errorNames[errorID];
02360     TIXMLASSERT( errorName && errorName[0] );
02361     return errorName;
02362 }
02363 
02364 const char* XMLDocument::ErrorStr() const
02365 {
02366         return _errorStr.Empty() ? "" : _errorStr.GetStr();
02367 }
02368 
02369 
02370 void XMLDocument::PrintError() const
02371 {
02372     printf("%s\n", ErrorStr());
02373 }
02374 
02375 const char* XMLDocument::ErrorName() const
02376 {
02377     return ErrorIDToName(_errorID);
02378 }
02379 
02380 void XMLDocument::Parse()
02381 {
02382     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
02383     TIXMLASSERT( _charBuffer );
02384     _parseCurLineNum = 1;
02385     _parseLineNum = 1;
02386     char* p = _charBuffer;
02387     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
02388     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
02389     if ( !*p ) {
02390         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02391         return;
02392     }
02393     ParseDeep(p, 0, &_parseCurLineNum );
02394 }
02395 
02396 void XMLDocument::PushDepth()
02397 {
02398         _parsingDepth++;
02399         if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
02400                 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
02401         }
02402 }
02403 
02404 void XMLDocument::PopDepth()
02405 {
02406         TIXMLASSERT(_parsingDepth > 0);
02407         --_parsingDepth;
02408 }
02409 
02410 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
02411     _elementJustOpened( false ),
02412     _stack(),
02413     _firstElement( true ),
02414     _fp( file ),
02415     _depth( depth ),
02416     _textDepth( -1 ),
02417     _processEntities( true ),
02418     _compactMode( compact ),
02419     _buffer()
02420 {
02421     for( int i=0; i<ENTITY_RANGE; ++i ) {
02422         _entityFlag[i] = false;
02423         _restrictedEntityFlag[i] = false;
02424     }
02425     for( int i=0; i<NUM_ENTITIES; ++i ) {
02426         const char entityValue = entities[i].value;
02427         const unsigned char flagIndex = (unsigned char)entityValue;
02428         TIXMLASSERT( flagIndex < ENTITY_RANGE );
02429         _entityFlag[flagIndex] = true;
02430     }
02431     _restrictedEntityFlag[(unsigned char)'&'] = true;
02432     _restrictedEntityFlag[(unsigned char)'<'] = true;
02433     _restrictedEntityFlag[(unsigned char)'>'] = true;   // not required, but consistency is nice
02434     _buffer.Push( 0 );
02435 }
02436 
02437 
02438 void XMLPrinter::Print( const char* format, ... )
02439 {
02440     va_list     va;
02441     va_start( va, format );
02442 
02443     if ( _fp ) {
02444         vfprintf( _fp, format, va );
02445     }
02446     else {
02447         const int len = TIXML_VSCPRINTF( format, va );
02448         // Close out and re-start the va-args
02449         va_end( va );
02450         TIXMLASSERT( len >= 0 );
02451         va_start( va, format );
02452         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
02453         char* p = _buffer.PushArr( len ) - 1;   // back up over the null terminator.
02454                 TIXML_VSNPRINTF( p, len+1, format, va );
02455     }
02456     va_end( va );
02457 }
02458 
02459 
02460 void XMLPrinter::Write( const char* data, size_t size )
02461 {
02462     if ( _fp ) {
02463         fwrite ( data , sizeof(char), size, _fp);
02464     }
02465     else {
02466         char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.
02467         memcpy( p, data, size );
02468         p[size] = 0;
02469     }
02470 }
02471 
02472 
02473 void XMLPrinter::Putc( char ch )
02474 {
02475     if ( _fp ) {
02476         fputc ( ch, _fp);
02477     }
02478     else {
02479         char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.
02480         p[0] = ch;
02481         p[1] = 0;
02482     }
02483 }
02484 
02485 
02486 void XMLPrinter::PrintSpace( int depth )
02487 {
02488     for( int i=0; i<depth; ++i ) {
02489         Write( "    " );
02490     }
02491 }
02492 
02493 
02494 void XMLPrinter::PrintString( const char* p, bool restricted )
02495 {
02496     // Look for runs of bytes between entities to print.
02497     const char* q = p;
02498 
02499     if ( _processEntities ) {
02500         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
02501         while ( *q ) {
02502             TIXMLASSERT( p <= q );
02503             // Remember, char is sometimes signed. (How many times has that bitten me?)
02504             if ( *q > 0 && *q < ENTITY_RANGE ) {
02505                 // Check for entities. If one is found, flush
02506                 // the stream up until the entity, write the
02507                 // entity, and keep looking.
02508                 if ( flag[(unsigned char)(*q)] ) {
02509                     while ( p < q ) {
02510                         const size_t delta = q - p;
02511                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
02512                         Write( p, toPrint );
02513                         p += toPrint;
02514                     }
02515                     bool entityPatternPrinted = false;
02516                     for( int i=0; i<NUM_ENTITIES; ++i ) {
02517                         if ( entities[i].value == *q ) {
02518                             Putc( '&' );
02519                             Write( entities[i].pattern, entities[i].length );
02520                             Putc( ';' );
02521                             entityPatternPrinted = true;
02522                             break;
02523                         }
02524                     }
02525                     if ( !entityPatternPrinted ) {
02526                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
02527                         TIXMLASSERT( false );
02528                     }
02529                     ++p;
02530                 }
02531             }
02532             ++q;
02533             TIXMLASSERT( p <= q );
02534         }
02535         // Flush the remaining string. This will be the entire
02536         // string if an entity wasn't found.
02537         if ( p < q ) {
02538             const size_t delta = q - p;
02539             const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
02540             Write( p, toPrint );
02541         }
02542     }
02543     else {
02544         Write( p );
02545     }
02546 }
02547 
02548 
02549 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
02550 {
02551     if ( writeBOM ) {
02552         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
02553         Write( reinterpret_cast< const char* >( bom ) );
02554     }
02555     if ( writeDec ) {
02556         PushDeclaration( "xml version=\"1.0\"" );
02557     }
02558 }
02559 
02560 
02561 void XMLPrinter::OpenElement( const char* name, bool compactMode )
02562 {
02563     SealElementIfJustOpened();
02564     _stack.Push( name );
02565 
02566     if ( _textDepth < 0 && !_firstElement && !compactMode ) {
02567         Putc( '\n' );
02568     }
02569     if ( !compactMode ) {
02570         PrintSpace( _depth );
02571     }
02572 
02573     Write ( "<" );
02574     Write ( name );
02575 
02576     _elementJustOpened = true;
02577     _firstElement = false;
02578     ++_depth;
02579 }
02580 
02581 
02582 void XMLPrinter::PushAttribute( const char* name, const char* value )
02583 {
02584     TIXMLASSERT( _elementJustOpened );
02585     Putc ( ' ' );
02586     Write( name );
02587     Write( "=\"" );
02588     PrintString( value, false );
02589     Putc ( '\"' );
02590 }
02591 
02592 
02593 void XMLPrinter::PushAttribute( const char* name, int v )
02594 {
02595     char buf[BUF_SIZE];
02596     XMLUtil::ToStr( v, buf, BUF_SIZE );
02597     PushAttribute( name, buf );
02598 }
02599 
02600 
02601 void XMLPrinter::PushAttribute( const char* name, unsigned v )
02602 {
02603     char buf[BUF_SIZE];
02604     XMLUtil::ToStr( v, buf, BUF_SIZE );
02605     PushAttribute( name, buf );
02606 }
02607 
02608 
02609 void XMLPrinter::PushAttribute(const char* name, int64_t v)
02610 {
02611         char buf[BUF_SIZE];
02612         XMLUtil::ToStr(v, buf, BUF_SIZE);
02613         PushAttribute(name, buf);
02614 }
02615 
02616 
02617 void XMLPrinter::PushAttribute( const char* name, bool v )
02618 {
02619     char buf[BUF_SIZE];
02620     XMLUtil::ToStr( v, buf, BUF_SIZE );
02621     PushAttribute( name, buf );
02622 }
02623 
02624 
02625 void XMLPrinter::PushAttribute( const char* name, double v )
02626 {
02627     char buf[BUF_SIZE];
02628     XMLUtil::ToStr( v, buf, BUF_SIZE );
02629     PushAttribute( name, buf );
02630 }
02631 
02632 
02633 void XMLPrinter::CloseElement( bool compactMode )
02634 {
02635     --_depth;
02636     const char* name = _stack.Pop();
02637 
02638     if ( _elementJustOpened ) {
02639         Write( "/>" );
02640     }
02641     else {
02642         if ( _textDepth < 0 && !compactMode) {
02643             Putc( '\n' );
02644             PrintSpace( _depth );
02645         }
02646         Write ( "</" );
02647         Write ( name );
02648         Write ( ">" );
02649     }
02650 
02651     if ( _textDepth == _depth ) {
02652         _textDepth = -1;
02653     }
02654     if ( _depth == 0 && !compactMode) {
02655         Putc( '\n' );
02656     }
02657     _elementJustOpened = false;
02658 }
02659 
02660 
02661 void XMLPrinter::SealElementIfJustOpened()
02662 {
02663     if ( !_elementJustOpened ) {
02664         return;
02665     }
02666     _elementJustOpened = false;
02667     Putc( '>' );
02668 }
02669 
02670 
02671 void XMLPrinter::PushText( const char* text, bool cdata )
02672 {
02673     _textDepth = _depth-1;
02674 
02675     SealElementIfJustOpened();
02676     if ( cdata ) {
02677         Write( "<![CDATA[" );
02678         Write( text );
02679         Write( "]]>" );
02680     }
02681     else {
02682         PrintString( text, true );
02683     }
02684 }
02685 
02686 void XMLPrinter::PushText( int64_t value )
02687 {
02688     char buf[BUF_SIZE];
02689     XMLUtil::ToStr( value, buf, BUF_SIZE );
02690     PushText( buf, false );
02691 }
02692 
02693 void XMLPrinter::PushText( int value )
02694 {
02695     char buf[BUF_SIZE];
02696     XMLUtil::ToStr( value, buf, BUF_SIZE );
02697     PushText( buf, false );
02698 }
02699 
02700 
02701 void XMLPrinter::PushText( unsigned value )
02702 {
02703     char buf[BUF_SIZE];
02704     XMLUtil::ToStr( value, buf, BUF_SIZE );
02705     PushText( buf, false );
02706 }
02707 
02708 
02709 void XMLPrinter::PushText( bool value )
02710 {
02711     char buf[BUF_SIZE];
02712     XMLUtil::ToStr( value, buf, BUF_SIZE );
02713     PushText( buf, false );
02714 }
02715 
02716 
02717 void XMLPrinter::PushText( float value )
02718 {
02719     char buf[BUF_SIZE];
02720     XMLUtil::ToStr( value, buf, BUF_SIZE );
02721     PushText( buf, false );
02722 }
02723 
02724 
02725 void XMLPrinter::PushText( double value )
02726 {
02727     char buf[BUF_SIZE];
02728     XMLUtil::ToStr( value, buf, BUF_SIZE );
02729     PushText( buf, false );
02730 }
02731 
02732 
02733 void XMLPrinter::PushComment( const char* comment )
02734 {
02735     SealElementIfJustOpened();
02736     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02737         Putc( '\n' );
02738         PrintSpace( _depth );
02739     }
02740     _firstElement = false;
02741 
02742     Write( "<!--" );
02743     Write( comment );
02744     Write( "-->" );
02745 }
02746 
02747 
02748 void XMLPrinter::PushDeclaration( const char* value )
02749 {
02750     SealElementIfJustOpened();
02751     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02752         Putc( '\n' );
02753         PrintSpace( _depth );
02754     }
02755     _firstElement = false;
02756 
02757     Write( "<?" );
02758     Write( value );
02759     Write( "?>" );
02760 }
02761 
02762 
02763 void XMLPrinter::PushUnknown( const char* value )
02764 {
02765     SealElementIfJustOpened();
02766     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02767         Putc( '\n' );
02768         PrintSpace( _depth );
02769     }
02770     _firstElement = false;
02771 
02772     Write( "<!" );
02773     Write( value );
02774     Putc( '>' );
02775 }
02776 
02777 
02778 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
02779 {
02780     _processEntities = doc.ProcessEntities();
02781     if ( doc.HasBOM() ) {
02782         PushHeader( true, false );
02783     }
02784     return true;
02785 }
02786 
02787 
02788 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
02789 {
02790     const XMLElement* parentElem = 0;
02791     if ( element.Parent() ) {
02792         parentElem = element.Parent()->ToElement();
02793     }
02794     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
02795     OpenElement( element.Name(), compactMode );
02796     while ( attribute ) {
02797         PushAttribute( attribute->Name(), attribute->Value() );
02798         attribute = attribute->Next();
02799     }
02800     return true;
02801 }
02802 
02803 
02804 bool XMLPrinter::VisitExit( const XMLElement& element )
02805 {
02806     CloseElement( CompactMode(element) );
02807     return true;
02808 }
02809 
02810 
02811 bool XMLPrinter::Visit( const XMLText& text )
02812 {
02813     PushText( text.Value(), text.CData() );
02814     return true;
02815 }
02816 
02817 
02818 bool XMLPrinter::Visit( const XMLComment& comment )
02819 {
02820     PushComment( comment.Value() );
02821     return true;
02822 }
02823 
02824 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
02825 {
02826     PushDeclaration( declaration.Value() );
02827     return true;
02828 }
02829 
02830 
02831 bool XMLPrinter::Visit( const XMLUnknown& unknown )
02832 {
02833     PushUnknown( unknown.Value() );
02834     return true;
02835 }
02836 
02837 }   // namespace tinyxml2


behaviortree_cpp
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Sat Jun 8 2019 20:17:15