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 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             bool wellLocated = ( ToDocument() != 0 );
01036             if ( wellLocated ) {
01037                 // Multiple declarations are allowed but all declarations
01038                 // must occur before anything else
01039                 for ( const XMLNode* existingNode = _document->FirstChild(); existingNode; existingNode = existingNode->NextSibling() ) {
01040                     if ( !existingNode->ToDeclaration() ) {
01041                         wellLocated = false;
01042                         break;
01043                     }
01044                 }
01045             }
01046             if ( !wellLocated ) {
01047                 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
01048                 DeleteNode( node );
01049                 break;
01050             }
01051         }
01052 
01053         XMLElement* ele = node->ToElement();
01054         if ( ele ) {
01055             // We read the end tag. Return it to the parent.
01056             if ( ele->ClosingType() == XMLElement::CLOSING ) {
01057                 if ( parentEndTag ) {
01058                     ele->_value.TransferTo( parentEndTag );
01059                 }
01060                 node->_memPool->SetTracked();   // created and then immediately deleted.
01061                 DeleteNode( node );
01062                 return p;
01063             }
01064 
01065             // Handle an end tag returned to this level.
01066             // And handle a bunch of annoying errors.
01067             bool mismatch = false;
01068             if ( endTag.Empty() ) {
01069                 if ( ele->ClosingType() == XMLElement::OPEN ) {
01070                     mismatch = true;
01071                 }
01072             }
01073             else {
01074                 if ( ele->ClosingType() != XMLElement::OPEN ) {
01075                     mismatch = true;
01076                 }
01077                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
01078                     mismatch = true;
01079                 }
01080             }
01081             if ( mismatch ) {
01082                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
01083                 DeleteNode( node );
01084                 break;
01085             }
01086         }
01087         InsertEndChild( node );
01088     }
01089     return 0;
01090 }
01091 
01092 /*static*/ void XMLNode::DeleteNode( XMLNode* node )
01093 {
01094     if ( node == 0 ) {
01095         return;
01096     }
01097         TIXMLASSERT(node->_document);
01098         if (!node->ToDocument()) {
01099                 node->_document->MarkInUse(node);
01100         }
01101 
01102     MemPool* pool = node->_memPool;
01103     node->~XMLNode();
01104     pool->Free( node );
01105 }
01106 
01107 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
01108 {
01109     TIXMLASSERT( insertThis );
01110     TIXMLASSERT( insertThis->_document == _document );
01111 
01112         if (insertThis->_parent) {
01113         insertThis->_parent->Unlink( insertThis );
01114         }
01115         else {
01116                 insertThis->_document->MarkInUse(insertThis);
01117         insertThis->_memPool->SetTracked();
01118         }
01119 }
01120 
01121 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
01122 {
01123     const XMLElement* element = this->ToElement();
01124     if ( element == 0 ) {
01125         return 0;
01126     }
01127     if ( name == 0 ) {
01128         return element;
01129     }
01130     if ( XMLUtil::StringEqual( element->Name(), name ) ) {
01131        return element;
01132     }
01133     return 0;
01134 }
01135 
01136 // --------- XMLText ---------- //
01137 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01138 {
01139     if ( this->CData() ) {
01140         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
01141         if ( !p ) {
01142             _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
01143         }
01144         return p;
01145     }
01146     else {
01147         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
01148         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
01149             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
01150         }
01151 
01152         p = _value.ParseText( p, "<", flags, curLineNumPtr );
01153         if ( p && *p ) {
01154             return p-1;
01155         }
01156         if ( !p ) {
01157             _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
01158         }
01159     }
01160     return 0;
01161 }
01162 
01163 
01164 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
01165 {
01166     if ( !doc ) {
01167         doc = _document;
01168     }
01169     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
01170     text->SetCData( this->CData() );
01171     return text;
01172 }
01173 
01174 
01175 bool XMLText::ShallowEqual( const XMLNode* compare ) const
01176 {
01177     TIXMLASSERT( compare );
01178     const XMLText* text = compare->ToText();
01179     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
01180 }
01181 
01182 
01183 bool XMLText::Accept( XMLVisitor* visitor ) const
01184 {
01185     TIXMLASSERT( visitor );
01186     return visitor->Visit( *this );
01187 }
01188 
01189 
01190 // --------- XMLComment ---------- //
01191 
01192 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
01193 {
01194 }
01195 
01196 
01197 XMLComment::~XMLComment()
01198 {
01199 }
01200 
01201 
01202 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01203 {
01204     // Comment parses as text.
01205     p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
01206     if ( p == 0 ) {
01207         _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
01208     }
01209     return p;
01210 }
01211 
01212 
01213 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
01214 {
01215     if ( !doc ) {
01216         doc = _document;
01217     }
01218     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?
01219     return comment;
01220 }
01221 
01222 
01223 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
01224 {
01225     TIXMLASSERT( compare );
01226     const XMLComment* comment = compare->ToComment();
01227     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
01228 }
01229 
01230 
01231 bool XMLComment::Accept( XMLVisitor* visitor ) const
01232 {
01233     TIXMLASSERT( visitor );
01234     return visitor->Visit( *this );
01235 }
01236 
01237 
01238 // --------- XMLDeclaration ---------- //
01239 
01240 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
01241 {
01242 }
01243 
01244 
01245 XMLDeclaration::~XMLDeclaration()
01246 {
01247     //printf( "~XMLDeclaration\n" );
01248 }
01249 
01250 
01251 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01252 {
01253     // Declaration parses as text.
01254     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
01255     if ( p == 0 ) {
01256         _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
01257     }
01258     return p;
01259 }
01260 
01261 
01262 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
01263 {
01264     if ( !doc ) {
01265         doc = _document;
01266     }
01267     XMLDeclaration* dec = doc->NewDeclaration( Value() );       // fixme: this will always allocate memory. Intern?
01268     return dec;
01269 }
01270 
01271 
01272 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
01273 {
01274     TIXMLASSERT( compare );
01275     const XMLDeclaration* declaration = compare->ToDeclaration();
01276     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
01277 }
01278 
01279 
01280 
01281 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
01282 {
01283     TIXMLASSERT( visitor );
01284     return visitor->Visit( *this );
01285 }
01286 
01287 // --------- XMLUnknown ---------- //
01288 
01289 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
01290 {
01291 }
01292 
01293 
01294 XMLUnknown::~XMLUnknown()
01295 {
01296 }
01297 
01298 
01299 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01300 {
01301     // Unknown parses as text.
01302     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
01303     if ( !p ) {
01304         _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
01305     }
01306     return p;
01307 }
01308 
01309 
01310 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
01311 {
01312     if ( !doc ) {
01313         doc = _document;
01314     }
01315     XMLUnknown* text = doc->NewUnknown( Value() );      // fixme: this will always allocate memory. Intern?
01316     return text;
01317 }
01318 
01319 
01320 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
01321 {
01322     TIXMLASSERT( compare );
01323     const XMLUnknown* unknown = compare->ToUnknown();
01324     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
01325 }
01326 
01327 
01328 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
01329 {
01330     TIXMLASSERT( visitor );
01331     return visitor->Visit( *this );
01332 }
01333 
01334 // --------- XMLAttribute ---------- //
01335 
01336 const char* XMLAttribute::Name() const
01337 {
01338     return _name.GetStr();
01339 }
01340 
01341 const char* XMLAttribute::Value() const
01342 {
01343     return _value.GetStr();
01344 }
01345 
01346 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
01347 {
01348     // Parse using the name rules: bug fix, was using ParseText before
01349     p = _name.ParseName( p );
01350     if ( !p || !*p ) {
01351         return 0;
01352     }
01353 
01354     // Skip white space before =
01355     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01356     if ( *p != '=' ) {
01357         return 0;
01358     }
01359 
01360     ++p;        // move up to opening quote
01361     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01362     if ( *p != '\"' && *p != '\'' ) {
01363         return 0;
01364     }
01365 
01366     char endTag[2] = { *p, 0 };
01367     ++p;        // move past opening quote
01368 
01369     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
01370     return p;
01371 }
01372 
01373 
01374 void XMLAttribute::SetName( const char* n )
01375 {
01376     _name.SetStr( n );
01377 }
01378 
01379 
01380 XMLError XMLAttribute::QueryIntValue( int* value ) const
01381 {
01382     if ( XMLUtil::ToInt( Value(), value )) {
01383         return XML_SUCCESS;
01384     }
01385     return XML_WRONG_ATTRIBUTE_TYPE;
01386 }
01387 
01388 
01389 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
01390 {
01391     if ( XMLUtil::ToUnsigned( Value(), value )) {
01392         return XML_SUCCESS;
01393     }
01394     return XML_WRONG_ATTRIBUTE_TYPE;
01395 }
01396 
01397 
01398 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
01399 {
01400         if (XMLUtil::ToInt64(Value(), value)) {
01401                 return XML_SUCCESS;
01402         }
01403         return XML_WRONG_ATTRIBUTE_TYPE;
01404 }
01405 
01406 
01407 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
01408 {
01409     if ( XMLUtil::ToBool( Value(), value )) {
01410         return XML_SUCCESS;
01411     }
01412     return XML_WRONG_ATTRIBUTE_TYPE;
01413 }
01414 
01415 
01416 XMLError XMLAttribute::QueryFloatValue( float* value ) const
01417 {
01418     if ( XMLUtil::ToFloat( Value(), value )) {
01419         return XML_SUCCESS;
01420     }
01421     return XML_WRONG_ATTRIBUTE_TYPE;
01422 }
01423 
01424 
01425 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
01426 {
01427     if ( XMLUtil::ToDouble( Value(), value )) {
01428         return XML_SUCCESS;
01429     }
01430     return XML_WRONG_ATTRIBUTE_TYPE;
01431 }
01432 
01433 
01434 void XMLAttribute::SetAttribute( const char* v )
01435 {
01436     _value.SetStr( v );
01437 }
01438 
01439 
01440 void XMLAttribute::SetAttribute( int v )
01441 {
01442     char buf[BUF_SIZE];
01443     XMLUtil::ToStr( v, buf, BUF_SIZE );
01444     _value.SetStr( buf );
01445 }
01446 
01447 
01448 void XMLAttribute::SetAttribute( unsigned v )
01449 {
01450     char buf[BUF_SIZE];
01451     XMLUtil::ToStr( v, buf, BUF_SIZE );
01452     _value.SetStr( buf );
01453 }
01454 
01455 
01456 void XMLAttribute::SetAttribute(int64_t v)
01457 {
01458         char buf[BUF_SIZE];
01459         XMLUtil::ToStr(v, buf, BUF_SIZE);
01460         _value.SetStr(buf);
01461 }
01462 
01463 
01464 
01465 void XMLAttribute::SetAttribute( bool v )
01466 {
01467     char buf[BUF_SIZE];
01468     XMLUtil::ToStr( v, buf, BUF_SIZE );
01469     _value.SetStr( buf );
01470 }
01471 
01472 void XMLAttribute::SetAttribute( double v )
01473 {
01474     char buf[BUF_SIZE];
01475     XMLUtil::ToStr( v, buf, BUF_SIZE );
01476     _value.SetStr( buf );
01477 }
01478 
01479 void XMLAttribute::SetAttribute( float v )
01480 {
01481     char buf[BUF_SIZE];
01482     XMLUtil::ToStr( v, buf, BUF_SIZE );
01483     _value.SetStr( buf );
01484 }
01485 
01486 
01487 // --------- XMLElement ---------- //
01488 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
01489     _closingType( OPEN ),
01490     _rootAttribute( 0 )
01491 {
01492 }
01493 
01494 
01495 XMLElement::~XMLElement()
01496 {
01497     while( _rootAttribute ) {
01498         XMLAttribute* next = _rootAttribute->_next;
01499         DeleteAttribute( _rootAttribute );
01500         _rootAttribute = next;
01501     }
01502 }
01503 
01504 
01505 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
01506 {
01507     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
01508         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
01509             return a;
01510         }
01511     }
01512     return 0;
01513 }
01514 
01515 
01516 const char* XMLElement::Attribute( const char* name, const char* value ) const
01517 {
01518     const XMLAttribute* a = FindAttribute( name );
01519     if ( !a ) {
01520         return 0;
01521     }
01522     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
01523         return a->Value();
01524     }
01525     return 0;
01526 }
01527 
01528 int XMLElement::IntAttribute(const char* name, int defaultValue) const
01529 {
01530         int i = defaultValue;
01531         QueryIntAttribute(name, &i);
01532         return i;
01533 }
01534 
01535 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
01536 {
01537         unsigned i = defaultValue;
01538         QueryUnsignedAttribute(name, &i);
01539         return i;
01540 }
01541 
01542 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
01543 {
01544         int64_t i = defaultValue;
01545         QueryInt64Attribute(name, &i);
01546         return i;
01547 }
01548 
01549 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
01550 {
01551         bool b = defaultValue;
01552         QueryBoolAttribute(name, &b);
01553         return b;
01554 }
01555 
01556 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
01557 {
01558         double d = defaultValue;
01559         QueryDoubleAttribute(name, &d);
01560         return d;
01561 }
01562 
01563 float XMLElement::FloatAttribute(const char* name, float defaultValue) const
01564 {
01565         float f = defaultValue;
01566         QueryFloatAttribute(name, &f);
01567         return f;
01568 }
01569 
01570 const char* XMLElement::GetText() const
01571 {
01572     if ( FirstChild() && FirstChild()->ToText() ) {
01573         return FirstChild()->Value();
01574     }
01575     return 0;
01576 }
01577 
01578 
01579 void    XMLElement::SetText( const char* inText )
01580 {
01581         if ( FirstChild() && FirstChild()->ToText() )
01582                 FirstChild()->SetValue( inText );
01583         else {
01584                 XMLText*        theText = GetDocument()->NewText( inText );
01585                 InsertFirstChild( theText );
01586         }
01587 }
01588 
01589 
01590 void XMLElement::SetText( int v )
01591 {
01592     char buf[BUF_SIZE];
01593     XMLUtil::ToStr( v, buf, BUF_SIZE );
01594     SetText( buf );
01595 }
01596 
01597 
01598 void XMLElement::SetText( unsigned v )
01599 {
01600     char buf[BUF_SIZE];
01601     XMLUtil::ToStr( v, buf, BUF_SIZE );
01602     SetText( buf );
01603 }
01604 
01605 
01606 void XMLElement::SetText(int64_t v)
01607 {
01608         char buf[BUF_SIZE];
01609         XMLUtil::ToStr(v, buf, BUF_SIZE);
01610         SetText(buf);
01611 }
01612 
01613 
01614 void XMLElement::SetText( bool v )
01615 {
01616     char buf[BUF_SIZE];
01617     XMLUtil::ToStr( v, buf, BUF_SIZE );
01618     SetText( buf );
01619 }
01620 
01621 
01622 void XMLElement::SetText( float v )
01623 {
01624     char buf[BUF_SIZE];
01625     XMLUtil::ToStr( v, buf, BUF_SIZE );
01626     SetText( buf );
01627 }
01628 
01629 
01630 void XMLElement::SetText( double v )
01631 {
01632     char buf[BUF_SIZE];
01633     XMLUtil::ToStr( v, buf, BUF_SIZE );
01634     SetText( buf );
01635 }
01636 
01637 
01638 XMLError XMLElement::QueryIntText( int* ival ) const
01639 {
01640     if ( FirstChild() && FirstChild()->ToText() ) {
01641         const char* t = FirstChild()->Value();
01642         if ( XMLUtil::ToInt( t, ival ) ) {
01643             return XML_SUCCESS;
01644         }
01645         return XML_CAN_NOT_CONVERT_TEXT;
01646     }
01647     return XML_NO_TEXT_NODE;
01648 }
01649 
01650 
01651 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
01652 {
01653     if ( FirstChild() && FirstChild()->ToText() ) {
01654         const char* t = FirstChild()->Value();
01655         if ( XMLUtil::ToUnsigned( t, uval ) ) {
01656             return XML_SUCCESS;
01657         }
01658         return XML_CAN_NOT_CONVERT_TEXT;
01659     }
01660     return XML_NO_TEXT_NODE;
01661 }
01662 
01663 
01664 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
01665 {
01666         if (FirstChild() && FirstChild()->ToText()) {
01667                 const char* t = FirstChild()->Value();
01668                 if (XMLUtil::ToInt64(t, ival)) {
01669                         return XML_SUCCESS;
01670                 }
01671                 return XML_CAN_NOT_CONVERT_TEXT;
01672         }
01673         return XML_NO_TEXT_NODE;
01674 }
01675 
01676 
01677 XMLError XMLElement::QueryBoolText( bool* bval ) const
01678 {
01679     if ( FirstChild() && FirstChild()->ToText() ) {
01680         const char* t = FirstChild()->Value();
01681         if ( XMLUtil::ToBool( t, bval ) ) {
01682             return XML_SUCCESS;
01683         }
01684         return XML_CAN_NOT_CONVERT_TEXT;
01685     }
01686     return XML_NO_TEXT_NODE;
01687 }
01688 
01689 
01690 XMLError XMLElement::QueryDoubleText( double* dval ) const
01691 {
01692     if ( FirstChild() && FirstChild()->ToText() ) {
01693         const char* t = FirstChild()->Value();
01694         if ( XMLUtil::ToDouble( t, dval ) ) {
01695             return XML_SUCCESS;
01696         }
01697         return XML_CAN_NOT_CONVERT_TEXT;
01698     }
01699     return XML_NO_TEXT_NODE;
01700 }
01701 
01702 
01703 XMLError XMLElement::QueryFloatText( float* fval ) const
01704 {
01705     if ( FirstChild() && FirstChild()->ToText() ) {
01706         const char* t = FirstChild()->Value();
01707         if ( XMLUtil::ToFloat( t, fval ) ) {
01708             return XML_SUCCESS;
01709         }
01710         return XML_CAN_NOT_CONVERT_TEXT;
01711     }
01712     return XML_NO_TEXT_NODE;
01713 }
01714 
01715 int XMLElement::IntText(int defaultValue) const
01716 {
01717         int i = defaultValue;
01718         QueryIntText(&i);
01719         return i;
01720 }
01721 
01722 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
01723 {
01724         unsigned i = defaultValue;
01725         QueryUnsignedText(&i);
01726         return i;
01727 }
01728 
01729 int64_t XMLElement::Int64Text(int64_t defaultValue) const
01730 {
01731         int64_t i = defaultValue;
01732         QueryInt64Text(&i);
01733         return i;
01734 }
01735 
01736 bool XMLElement::BoolText(bool defaultValue) const
01737 {
01738         bool b = defaultValue;
01739         QueryBoolText(&b);
01740         return b;
01741 }
01742 
01743 double XMLElement::DoubleText(double defaultValue) const
01744 {
01745         double d = defaultValue;
01746         QueryDoubleText(&d);
01747         return d;
01748 }
01749 
01750 float XMLElement::FloatText(float defaultValue) const
01751 {
01752         float f = defaultValue;
01753         QueryFloatText(&f);
01754         return f;
01755 }
01756 
01757 
01758 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
01759 {
01760     XMLAttribute* last = 0;
01761     XMLAttribute* attrib = 0;
01762     for( attrib = _rootAttribute;
01763             attrib;
01764             last = attrib, attrib = attrib->_next ) {
01765         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
01766             break;
01767         }
01768     }
01769     if ( !attrib ) {
01770         attrib = CreateAttribute();
01771         TIXMLASSERT( attrib );
01772         if ( last ) {
01773             TIXMLASSERT( last->_next == 0 );
01774             last->_next = attrib;
01775         }
01776         else {
01777             TIXMLASSERT( _rootAttribute == 0 );
01778             _rootAttribute = attrib;
01779         }
01780         attrib->SetName( name );
01781     }
01782     return attrib;
01783 }
01784 
01785 
01786 void XMLElement::DeleteAttribute( const char* name )
01787 {
01788     XMLAttribute* prev = 0;
01789     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
01790         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
01791             if ( prev ) {
01792                 prev->_next = a->_next;
01793             }
01794             else {
01795                 _rootAttribute = a->_next;
01796             }
01797             DeleteAttribute( a );
01798             break;
01799         }
01800         prev = a;
01801     }
01802 }
01803 
01804 
01805 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
01806 {
01807     XMLAttribute* prevAttribute = 0;
01808 
01809     // Read the attributes.
01810     while( p ) {
01811         p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01812         if ( !(*p) ) {
01813             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
01814             return 0;
01815         }
01816 
01817         // attribute.
01818         if (XMLUtil::IsNameStartChar( *p ) ) {
01819             XMLAttribute* attrib = CreateAttribute();
01820             TIXMLASSERT( attrib );
01821             attrib->_parseLineNum = _document->_parseCurLineNum;
01822 
01823             int attrLineNum = attrib->_parseLineNum;
01824 
01825             p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
01826             if ( !p || Attribute( attrib->Name() ) ) {
01827                 DeleteAttribute( attrib );
01828                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
01829                 return 0;
01830             }
01831             // There is a minor bug here: if the attribute in the source xml
01832             // document is duplicated, it will not be detected and the
01833             // attribute will be doubly added. However, tracking the 'prevAttribute'
01834             // avoids re-scanning the attribute list. Preferring performance for
01835             // now, may reconsider in the future.
01836             if ( prevAttribute ) {
01837                 TIXMLASSERT( prevAttribute->_next == 0 );
01838                 prevAttribute->_next = attrib;
01839             }
01840             else {
01841                 TIXMLASSERT( _rootAttribute == 0 );
01842                 _rootAttribute = attrib;
01843             }
01844             prevAttribute = attrib;
01845         }
01846         // end of the tag
01847         else if ( *p == '>' ) {
01848             ++p;
01849             break;
01850         }
01851         // end of the tag
01852         else if ( *p == '/' && *(p+1) == '>' ) {
01853             _closingType = CLOSED;
01854             return p+2; // done; sealed element.
01855         }
01856         else {
01857             _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
01858             return 0;
01859         }
01860     }
01861     return p;
01862 }
01863 
01864 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
01865 {
01866     if ( attribute == 0 ) {
01867         return;
01868     }
01869     MemPool* pool = attribute->_memPool;
01870     attribute->~XMLAttribute();
01871     pool->Free( attribute );
01872 }
01873 
01874 XMLAttribute* XMLElement::CreateAttribute()
01875 {
01876     TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
01877     XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
01878     TIXMLASSERT( attrib );
01879     attrib->_memPool = &_document->_attributePool;
01880     attrib->_memPool->SetTracked();
01881     return attrib;
01882 }
01883 
01884 //
01885 //      <ele></ele>
01886 //      <ele>foo<b>bar</b></ele>
01887 //
01888 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
01889 {
01890     // Read the element name.
01891     p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01892 
01893     // The closing element is the </element> form. It is
01894     // parsed just like a regular element then deleted from
01895     // the DOM.
01896     if ( *p == '/' ) {
01897         _closingType = CLOSING;
01898         ++p;
01899     }
01900 
01901     p = _value.ParseName( p );
01902     if ( _value.Empty() ) {
01903         return 0;
01904     }
01905 
01906     p = ParseAttributes( p, curLineNumPtr );
01907     if ( !p || !*p || _closingType != OPEN ) {
01908         return p;
01909     }
01910 
01911     p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
01912     return p;
01913 }
01914 
01915 
01916 
01917 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
01918 {
01919     if ( !doc ) {
01920         doc = _document;
01921     }
01922     XMLElement* element = doc->NewElement( Value() );                                   // fixme: this will always allocate memory. Intern?
01923     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
01924         element->SetAttribute( a->Name(), a->Value() );                                 // fixme: this will always allocate memory. Intern?
01925     }
01926     return element;
01927 }
01928 
01929 
01930 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
01931 {
01932     TIXMLASSERT( compare );
01933     const XMLElement* other = compare->ToElement();
01934     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
01935 
01936         const XMLAttribute* a=FirstAttribute();
01937         const XMLAttribute* b=other->FirstAttribute();
01938 
01939         while ( a && b ) {
01940             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
01941                 return false;
01942             }
01943             a = a->Next();
01944             b = b->Next();
01945         }
01946         if ( a || b ) {
01947             // different count
01948             return false;
01949         }
01950         return true;
01951     }
01952     return false;
01953 }
01954 
01955 
01956 bool XMLElement::Accept( XMLVisitor* visitor ) const
01957 {
01958     TIXMLASSERT( visitor );
01959     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
01960         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
01961             if ( !node->Accept( visitor ) ) {
01962                 break;
01963             }
01964         }
01965     }
01966     return visitor->VisitExit( *this );
01967 }
01968 
01969 
01970 // --------- XMLDocument ----------- //
01971 
01972 // Warning: List must match 'enum XMLError'
01973 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
01974     "XML_SUCCESS",
01975     "XML_NO_ATTRIBUTE",
01976     "XML_WRONG_ATTRIBUTE_TYPE",
01977     "XML_ERROR_FILE_NOT_FOUND",
01978     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
01979     "XML_ERROR_FILE_READ_ERROR",
01980     "UNUSED_XML_ERROR_ELEMENT_MISMATCH",
01981     "XML_ERROR_PARSING_ELEMENT",
01982     "XML_ERROR_PARSING_ATTRIBUTE",
01983     "UNUSED_XML_ERROR_IDENTIFYING_TAG",
01984     "XML_ERROR_PARSING_TEXT",
01985     "XML_ERROR_PARSING_CDATA",
01986     "XML_ERROR_PARSING_COMMENT",
01987     "XML_ERROR_PARSING_DECLARATION",
01988     "XML_ERROR_PARSING_UNKNOWN",
01989     "XML_ERROR_EMPTY_DOCUMENT",
01990     "XML_ERROR_MISMATCHED_ELEMENT",
01991     "XML_ERROR_PARSING",
01992     "XML_CAN_NOT_CONVERT_TEXT",
01993     "XML_NO_TEXT_NODE",
01994         "XML_ELEMENT_DEPTH_EXCEEDED"
01995 };
01996 
01997 
01998 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
01999     XMLNode( 0 ),
02000     _writeBOM( false ),
02001     _processEntities( processEntities ),
02002     _errorID(XML_SUCCESS),
02003     _whitespaceMode( whitespaceMode ),
02004     _errorStr(),
02005     _errorLineNum( 0 ),
02006     _charBuffer( 0 ),
02007     _parseCurLineNum( 0 ),
02008         _parsingDepth(0),
02009     _unlinked(),
02010     _elementPool(),
02011     _attributePool(),
02012     _textPool(),
02013     _commentPool()
02014 {
02015     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
02016     _document = this;
02017 }
02018 
02019 
02020 XMLDocument::~XMLDocument()
02021 {
02022     Clear();
02023 }
02024 
02025 
02026 void XMLDocument::MarkInUse(XMLNode* node)
02027 {
02028         TIXMLASSERT(node);
02029         TIXMLASSERT(node->_parent == 0);
02030 
02031         for (int i = 0; i < _unlinked.Size(); ++i) {
02032                 if (node == _unlinked[i]) {
02033                         _unlinked.SwapRemove(i);
02034                         break;
02035                 }
02036         }
02037 }
02038 
02039 void XMLDocument::Clear()
02040 {
02041     DeleteChildren();
02042         while( _unlinked.Size()) {
02043                 DeleteNode(_unlinked[0]);       // Will remove from _unlinked as part of delete.
02044         }
02045 
02046 #ifdef TINYXML2_DEBUG
02047     const bool hadError = Error();
02048 #endif
02049     ClearError();
02050 
02051     delete [] _charBuffer;
02052     _charBuffer = 0;
02053         _parsingDepth = 0;
02054 
02055 #if 0
02056     _textPool.Trace( "text" );
02057     _elementPool.Trace( "element" );
02058     _commentPool.Trace( "comment" );
02059     _attributePool.Trace( "attribute" );
02060 #endif
02061 
02062 #ifdef TINYXML2_DEBUG
02063     if ( !hadError ) {
02064         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
02065         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
02066         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
02067         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
02068     }
02069 #endif
02070 }
02071 
02072 
02073 void XMLDocument::DeepCopy(XMLDocument* target) const
02074 {
02075         TIXMLASSERT(target);
02076     if (target == this) {
02077         return; // technically success - a no-op.
02078     }
02079 
02080         target->Clear();
02081         for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
02082                 target->InsertEndChild(node->DeepClone(target));
02083         }
02084 }
02085 
02086 XMLElement* XMLDocument::NewElement( const char* name )
02087 {
02088     XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
02089     ele->SetName( name );
02090     return ele;
02091 }
02092 
02093 
02094 XMLComment* XMLDocument::NewComment( const char* str )
02095 {
02096     XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
02097     comment->SetValue( str );
02098     return comment;
02099 }
02100 
02101 
02102 XMLText* XMLDocument::NewText( const char* str )
02103 {
02104     XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
02105     text->SetValue( str );
02106     return text;
02107 }
02108 
02109 
02110 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
02111 {
02112     XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
02113     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
02114     return dec;
02115 }
02116 
02117 
02118 XMLUnknown* XMLDocument::NewUnknown( const char* str )
02119 {
02120     XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
02121     unk->SetValue( str );
02122     return unk;
02123 }
02124 
02125 static FILE* callfopen( const char* filepath, const char* mode )
02126 {
02127     TIXMLASSERT( filepath );
02128     TIXMLASSERT( mode );
02129 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
02130     FILE* fp = 0;
02131     errno_t err = fopen_s( &fp, filepath, mode );
02132     if ( err ) {
02133         return 0;
02134     }
02135 #else
02136     FILE* fp = fopen( filepath, mode );
02137 #endif
02138     return fp;
02139 }
02140 
02141 void XMLDocument::DeleteNode( XMLNode* node )   {
02142     TIXMLASSERT( node );
02143     TIXMLASSERT(node->_document == this );
02144     if (node->_parent) {
02145         node->_parent->DeleteChild( node );
02146     }
02147     else {
02148         // Isn't in the tree.
02149         // Use the parent delete.
02150         // Also, we need to mark it tracked: we 'know'
02151         // it was never used.
02152         node->_memPool->SetTracked();
02153         // Call the static XMLNode version:
02154         XMLNode::DeleteNode(node);
02155     }
02156 }
02157 
02158 
02159 XMLError XMLDocument::LoadFile( const char* filename )
02160 {
02161     if ( !filename ) {
02162         TIXMLASSERT( false );
02163         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
02164         return _errorID;
02165     }
02166 
02167     Clear();
02168     FILE* fp = callfopen( filename, "rb" );
02169     if ( !fp ) {
02170         SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
02171         return _errorID;
02172     }
02173     LoadFile( fp );
02174     fclose( fp );
02175     return _errorID;
02176 }
02177 
02178 // This is likely overengineered template art to have a check that unsigned long value incremented
02179 // by one still fits into size_t. If size_t type is larger than unsigned long type
02180 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
02181 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check
02182 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long
02183 // types sizes relate to each other.
02184 template
02185 <bool = (sizeof(unsigned long) >= sizeof(size_t))>
02186 struct LongFitsIntoSizeTMinusOne {
02187     static bool Fits( unsigned long value )
02188     {
02189         return value < (size_t)-1;
02190     }
02191 };
02192 
02193 template <>
02194 struct LongFitsIntoSizeTMinusOne<false> {
02195     static bool Fits( unsigned long )
02196     {
02197         return true;
02198     }
02199 };
02200 
02201 XMLError XMLDocument::LoadFile( FILE* fp )
02202 {
02203     Clear();
02204 
02205     fseek( fp, 0, SEEK_SET );
02206     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
02207         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02208         return _errorID;
02209     }
02210 
02211     fseek( fp, 0, SEEK_END );
02212     const long filelength = ftell( fp );
02213     fseek( fp, 0, SEEK_SET );
02214     if ( filelength == -1L ) {
02215         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02216         return _errorID;
02217     }
02218     TIXMLASSERT( filelength >= 0 );
02219 
02220     if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
02221         // Cannot handle files which won't fit in buffer together with null terminator
02222         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02223         return _errorID;
02224     }
02225 
02226     if ( filelength == 0 ) {
02227         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02228         return _errorID;
02229     }
02230 
02231     const size_t size = filelength;
02232     TIXMLASSERT( _charBuffer == 0 );
02233     _charBuffer = new char[size+1];
02234     size_t read = fread( _charBuffer, 1, size, fp );
02235     if ( read != size ) {
02236         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
02237         return _errorID;
02238     }
02239 
02240     _charBuffer[size] = 0;
02241 
02242     Parse();
02243     return _errorID;
02244 }
02245 
02246 
02247 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
02248 {
02249     if ( !filename ) {
02250         TIXMLASSERT( false );
02251         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
02252         return _errorID;
02253     }
02254 
02255     FILE* fp = callfopen( filename, "w" );
02256     if ( !fp ) {
02257         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
02258         return _errorID;
02259     }
02260     SaveFile(fp, compact);
02261     fclose( fp );
02262     return _errorID;
02263 }
02264 
02265 
02266 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
02267 {
02268     // Clear any error from the last save, otherwise it will get reported
02269     // for *this* call.
02270     ClearError();
02271     XMLPrinter stream( fp, compact );
02272     Print( &stream );
02273     return _errorID;
02274 }
02275 
02276 
02277 XMLError XMLDocument::Parse( const char* p, size_t len )
02278 {
02279     Clear();
02280 
02281     if ( len == 0 || !p || !*p ) {
02282         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02283         return _errorID;
02284     }
02285     if ( len == (size_t)(-1) ) {
02286         len = strlen( p );
02287     }
02288     TIXMLASSERT( _charBuffer == 0 );
02289     _charBuffer = new char[ len+1 ];
02290     memcpy( _charBuffer, p, len );
02291     _charBuffer[len] = 0;
02292 
02293     Parse();
02294     if ( Error() ) {
02295         // clean up now essentially dangling memory.
02296         // and the parse fail can put objects in the
02297         // pools that are dead and inaccessible.
02298         DeleteChildren();
02299         _elementPool.Clear();
02300         _attributePool.Clear();
02301         _textPool.Clear();
02302         _commentPool.Clear();
02303     }
02304     return _errorID;
02305 }
02306 
02307 
02308 void XMLDocument::Print( XMLPrinter* streamer ) const
02309 {
02310     if ( streamer ) {
02311         Accept( streamer );
02312     }
02313     else {
02314         XMLPrinter stdoutStreamer( stdout );
02315         Accept( &stdoutStreamer );
02316     }
02317 }
02318 
02319 
02320 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
02321 {
02322     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
02323     _errorID = error;
02324     _errorLineNum = lineNum;
02325         _errorStr.Reset();
02326 
02327     size_t BUFFER_SIZE = 1000;
02328     char* buffer = new char[BUFFER_SIZE];
02329 
02330     TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
02331 
02332         if (format) {
02333                 size_t len = strlen(buffer);
02334                 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
02335                 len = strlen(buffer);
02336 
02337                 va_list va;
02338                 va_start(va, format);
02339                 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
02340                 va_end(va);
02341         }
02342         _errorStr.SetStr(buffer);
02343         delete[] buffer;
02344 }
02345 
02346 
02347 /*static*/ const char* XMLDocument::ErrorIDToName(XMLError errorID)
02348 {
02349         TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
02350     const char* errorName = _errorNames[errorID];
02351     TIXMLASSERT( errorName && errorName[0] );
02352     return errorName;
02353 }
02354 
02355 const char* XMLDocument::ErrorStr() const
02356 {
02357         return _errorStr.Empty() ? "" : _errorStr.GetStr();
02358 }
02359 
02360 
02361 void XMLDocument::PrintError() const
02362 {
02363     printf("%s\n", ErrorStr());
02364 }
02365 
02366 const char* XMLDocument::ErrorName() const
02367 {
02368     return ErrorIDToName(_errorID);
02369 }
02370 
02371 void XMLDocument::Parse()
02372 {
02373     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
02374     TIXMLASSERT( _charBuffer );
02375     _parseCurLineNum = 1;
02376     _parseLineNum = 1;
02377     char* p = _charBuffer;
02378     p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
02379     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
02380     if ( !*p ) {
02381         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02382         return;
02383     }
02384     ParseDeep(p, 0, &_parseCurLineNum );
02385 }
02386 
02387 void XMLDocument::PushDepth()
02388 {
02389         _parsingDepth++;
02390         if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
02391                 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
02392         }
02393 }
02394 
02395 void XMLDocument::PopDepth()
02396 {
02397         TIXMLASSERT(_parsingDepth > 0);
02398         --_parsingDepth;
02399 }
02400 
02401 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
02402     _elementJustOpened( false ),
02403     _stack(),
02404     _firstElement( true ),
02405     _fp( file ),
02406     _depth( depth ),
02407     _textDepth( -1 ),
02408     _processEntities( true ),
02409     _compactMode( compact ),
02410     _buffer()
02411 {
02412     for( int i=0; i<ENTITY_RANGE; ++i ) {
02413         _entityFlag[i] = false;
02414         _restrictedEntityFlag[i] = false;
02415     }
02416     for( int i=0; i<NUM_ENTITIES; ++i ) {
02417         const char entityValue = entities[i].value;
02418         const unsigned char flagIndex = (unsigned char)entityValue;
02419         TIXMLASSERT( flagIndex < ENTITY_RANGE );
02420         _entityFlag[flagIndex] = true;
02421     }
02422     _restrictedEntityFlag[(unsigned char)'&'] = true;
02423     _restrictedEntityFlag[(unsigned char)'<'] = true;
02424     _restrictedEntityFlag[(unsigned char)'>'] = true;   // not required, but consistency is nice
02425     _buffer.Push( 0 );
02426 }
02427 
02428 
02429 void XMLPrinter::Print( const char* format, ... )
02430 {
02431     va_list     va;
02432     va_start( va, format );
02433 
02434     if ( _fp ) {
02435         vfprintf( _fp, format, va );
02436     }
02437     else {
02438         const int len = TIXML_VSCPRINTF( format, va );
02439         // Close out and re-start the va-args
02440         va_end( va );
02441         TIXMLASSERT( len >= 0 );
02442         va_start( va, format );
02443         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
02444         char* p = _buffer.PushArr( len ) - 1;   // back up over the null terminator.
02445                 TIXML_VSNPRINTF( p, len+1, format, va );
02446     }
02447     va_end( va );
02448 }
02449 
02450 
02451 void XMLPrinter::Write( const char* data, size_t size )
02452 {
02453     if ( _fp ) {
02454         fwrite ( data , sizeof(char), size, _fp);
02455     }
02456     else {
02457         char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;   // back up over the null terminator.
02458         memcpy( p, data, size );
02459         p[size] = 0;
02460     }
02461 }
02462 
02463 
02464 void XMLPrinter::Putc( char ch )
02465 {
02466     if ( _fp ) {
02467         fputc ( ch, _fp);
02468     }
02469     else {
02470         char* p = _buffer.PushArr( sizeof(char) ) - 1;   // back up over the null terminator.
02471         p[0] = ch;
02472         p[1] = 0;
02473     }
02474 }
02475 
02476 
02477 void XMLPrinter::PrintSpace( int depth )
02478 {
02479     for( int i=0; i<depth; ++i ) {
02480         Write( "    " );
02481     }
02482 }
02483 
02484 
02485 void XMLPrinter::PrintString( const char* p, bool restricted )
02486 {
02487     // Look for runs of bytes between entities to print.
02488     const char* q = p;
02489 
02490     if ( _processEntities ) {
02491         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
02492         while ( *q ) {
02493             TIXMLASSERT( p <= q );
02494             // Remember, char is sometimes signed. (How many times has that bitten me?)
02495             if ( *q > 0 && *q < ENTITY_RANGE ) {
02496                 // Check for entities. If one is found, flush
02497                 // the stream up until the entity, write the
02498                 // entity, and keep looking.
02499                 if ( flag[(unsigned char)(*q)] ) {
02500                     while ( p < q ) {
02501                         const size_t delta = q - p;
02502                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
02503                         Write( p, toPrint );
02504                         p += toPrint;
02505                     }
02506                     bool entityPatternPrinted = false;
02507                     for( int i=0; i<NUM_ENTITIES; ++i ) {
02508                         if ( entities[i].value == *q ) {
02509                             Putc( '&' );
02510                             Write( entities[i].pattern, entities[i].length );
02511                             Putc( ';' );
02512                             entityPatternPrinted = true;
02513                             break;
02514                         }
02515                     }
02516                     if ( !entityPatternPrinted ) {
02517                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
02518                         TIXMLASSERT( false );
02519                     }
02520                     ++p;
02521                 }
02522             }
02523             ++q;
02524             TIXMLASSERT( p <= q );
02525         }
02526     }
02527     // Flush the remaining string. This will be the entire
02528     // string if an entity wasn't found.
02529     TIXMLASSERT( p <= q );
02530     if ( !_processEntities || ( p < q ) ) {
02531         const size_t delta = q - p;
02532         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
02533         Write( p, toPrint );
02534     }
02535 }
02536 
02537 
02538 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
02539 {
02540     if ( writeBOM ) {
02541         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
02542         Write( reinterpret_cast< const char* >( bom ) );
02543     }
02544     if ( writeDec ) {
02545         PushDeclaration( "xml version=\"1.0\"" );
02546     }
02547 }
02548 
02549 
02550 void XMLPrinter::OpenElement( const char* name, bool compactMode )
02551 {
02552     SealElementIfJustOpened();
02553     _stack.Push( name );
02554 
02555     if ( _textDepth < 0 && !_firstElement && !compactMode ) {
02556         Putc( '\n' );
02557     }
02558     if ( !compactMode ) {
02559         PrintSpace( _depth );
02560     }
02561 
02562     Write ( "<" );
02563     Write ( name );
02564 
02565     _elementJustOpened = true;
02566     _firstElement = false;
02567     ++_depth;
02568 }
02569 
02570 
02571 void XMLPrinter::PushAttribute( const char* name, const char* value )
02572 {
02573     TIXMLASSERT( _elementJustOpened );
02574     Putc ( ' ' );
02575     Write( name );
02576     Write( "=\"" );
02577     PrintString( value, false );
02578     Putc ( '\"' );
02579 }
02580 
02581 
02582 void XMLPrinter::PushAttribute( const char* name, int v )
02583 {
02584     char buf[BUF_SIZE];
02585     XMLUtil::ToStr( v, buf, BUF_SIZE );
02586     PushAttribute( name, buf );
02587 }
02588 
02589 
02590 void XMLPrinter::PushAttribute( const char* name, unsigned v )
02591 {
02592     char buf[BUF_SIZE];
02593     XMLUtil::ToStr( v, buf, BUF_SIZE );
02594     PushAttribute( name, buf );
02595 }
02596 
02597 
02598 void XMLPrinter::PushAttribute(const char* name, int64_t v)
02599 {
02600         char buf[BUF_SIZE];
02601         XMLUtil::ToStr(v, buf, BUF_SIZE);
02602         PushAttribute(name, buf);
02603 }
02604 
02605 
02606 void XMLPrinter::PushAttribute( const char* name, bool v )
02607 {
02608     char buf[BUF_SIZE];
02609     XMLUtil::ToStr( v, buf, BUF_SIZE );
02610     PushAttribute( name, buf );
02611 }
02612 
02613 
02614 void XMLPrinter::PushAttribute( const char* name, double v )
02615 {
02616     char buf[BUF_SIZE];
02617     XMLUtil::ToStr( v, buf, BUF_SIZE );
02618     PushAttribute( name, buf );
02619 }
02620 
02621 
02622 void XMLPrinter::CloseElement( bool compactMode )
02623 {
02624     --_depth;
02625     const char* name = _stack.Pop();
02626 
02627     if ( _elementJustOpened ) {
02628         Write( "/>" );
02629     }
02630     else {
02631         if ( _textDepth < 0 && !compactMode) {
02632             Putc( '\n' );
02633             PrintSpace( _depth );
02634         }
02635         Write ( "</" );
02636         Write ( name );
02637         Write ( ">" );
02638     }
02639 
02640     if ( _textDepth == _depth ) {
02641         _textDepth = -1;
02642     }
02643     if ( _depth == 0 && !compactMode) {
02644         Putc( '\n' );
02645     }
02646     _elementJustOpened = false;
02647 }
02648 
02649 
02650 void XMLPrinter::SealElementIfJustOpened()
02651 {
02652     if ( !_elementJustOpened ) {
02653         return;
02654     }
02655     _elementJustOpened = false;
02656     Putc( '>' );
02657 }
02658 
02659 
02660 void XMLPrinter::PushText( const char* text, bool cdata )
02661 {
02662     _textDepth = _depth-1;
02663 
02664     SealElementIfJustOpened();
02665     if ( cdata ) {
02666         Write( "<![CDATA[" );
02667         Write( text );
02668         Write( "]]>" );
02669     }
02670     else {
02671         PrintString( text, true );
02672     }
02673 }
02674 
02675 void XMLPrinter::PushText( int64_t value )
02676 {
02677     char buf[BUF_SIZE];
02678     XMLUtil::ToStr( value, buf, BUF_SIZE );
02679     PushText( buf, false );
02680 }
02681 
02682 void XMLPrinter::PushText( int value )
02683 {
02684     char buf[BUF_SIZE];
02685     XMLUtil::ToStr( value, buf, BUF_SIZE );
02686     PushText( buf, false );
02687 }
02688 
02689 
02690 void XMLPrinter::PushText( unsigned value )
02691 {
02692     char buf[BUF_SIZE];
02693     XMLUtil::ToStr( value, buf, BUF_SIZE );
02694     PushText( buf, false );
02695 }
02696 
02697 
02698 void XMLPrinter::PushText( bool value )
02699 {
02700     char buf[BUF_SIZE];
02701     XMLUtil::ToStr( value, buf, BUF_SIZE );
02702     PushText( buf, false );
02703 }
02704 
02705 
02706 void XMLPrinter::PushText( float value )
02707 {
02708     char buf[BUF_SIZE];
02709     XMLUtil::ToStr( value, buf, BUF_SIZE );
02710     PushText( buf, false );
02711 }
02712 
02713 
02714 void XMLPrinter::PushText( double value )
02715 {
02716     char buf[BUF_SIZE];
02717     XMLUtil::ToStr( value, buf, BUF_SIZE );
02718     PushText( buf, false );
02719 }
02720 
02721 
02722 void XMLPrinter::PushComment( const char* comment )
02723 {
02724     SealElementIfJustOpened();
02725     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02726         Putc( '\n' );
02727         PrintSpace( _depth );
02728     }
02729     _firstElement = false;
02730 
02731     Write( "<!--" );
02732     Write( comment );
02733     Write( "-->" );
02734 }
02735 
02736 
02737 void XMLPrinter::PushDeclaration( const char* value )
02738 {
02739     SealElementIfJustOpened();
02740     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02741         Putc( '\n' );
02742         PrintSpace( _depth );
02743     }
02744     _firstElement = false;
02745 
02746     Write( "<?" );
02747     Write( value );
02748     Write( "?>" );
02749 }
02750 
02751 
02752 void XMLPrinter::PushUnknown( const char* value )
02753 {
02754     SealElementIfJustOpened();
02755     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02756         Putc( '\n' );
02757         PrintSpace( _depth );
02758     }
02759     _firstElement = false;
02760 
02761     Write( "<!" );
02762     Write( value );
02763     Putc( '>' );
02764 }
02765 
02766 
02767 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
02768 {
02769     _processEntities = doc.ProcessEntities();
02770     if ( doc.HasBOM() ) {
02771         PushHeader( true, false );
02772     }
02773     return true;
02774 }
02775 
02776 
02777 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
02778 {
02779     const XMLElement* parentElem = 0;
02780     if ( element.Parent() ) {
02781         parentElem = element.Parent()->ToElement();
02782     }
02783     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
02784     OpenElement( element.Name(), compactMode );
02785     while ( attribute ) {
02786         PushAttribute( attribute->Name(), attribute->Value() );
02787         attribute = attribute->Next();
02788     }
02789     return true;
02790 }
02791 
02792 
02793 bool XMLPrinter::VisitExit( const XMLElement& element )
02794 {
02795     CloseElement( CompactMode(element) );
02796     return true;
02797 }
02798 
02799 
02800 bool XMLPrinter::Visit( const XMLText& text )
02801 {
02802     PushText( text.Value(), text.CData() );
02803     return true;
02804 }
02805 
02806 
02807 bool XMLPrinter::Visit( const XMLComment& comment )
02808 {
02809     PushComment( comment.Value() );
02810     return true;
02811 }
02812 
02813 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
02814 {
02815     PushDeclaration( declaration.Value() );
02816     return true;
02817 }
02818 
02819 
02820 bool XMLPrinter::Visit( const XMLUnknown& unknown )
02821 {
02822     PushUnknown( unknown.Value() );
02823     return true;
02824 }
02825 
02826 }   // namespace tinyxml2


behaviortree_cpp
Author(s): Michele Colledanchise, Davide Faconti
autogenerated on Sat Feb 2 2019 03:50:10