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 "denso_robot_core/tinyxml2.h"
00025 
00026 #include <new>          // yes, this one new style header, is in the Android SDK.
00027 #if defined(ANDROID_NDK) || 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->_flags == 0 );
00153     TIXMLASSERT( other->_start == 0 );
00154     TIXMLASSERT( other->_end == 0 );
00155 
00156     other->Reset();
00157 
00158     other->_flags = _flags;
00159     other->_start = _start;
00160     other->_end = _end;
00161 
00162     _flags = 0;
00163     _start = 0;
00164     _end = 0;
00165 }
00166 
00167 void StrPair::Reset()
00168 {
00169     if ( _flags & NEEDS_DELETE ) {
00170         delete [] _start;
00171     }
00172     _flags = 0;
00173     _start = 0;
00174     _end = 0;
00175 }
00176 
00177 
00178 void StrPair::SetStr( const char* str, int flags )
00179 {
00180     Reset();
00181     size_t len = strlen( str );
00182     TIXMLASSERT( _start == 0 );
00183     _start = new char[ len+1 ];
00184     memcpy( _start, str, len+1 );
00185     _end = _start + len;
00186     _flags = flags | NEEDS_DELETE;
00187 }
00188 
00189 
00190 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
00191 {
00192     TIXMLASSERT( endTag && *endTag );
00193 
00194     char* start = p;
00195     char  endChar = *endTag;
00196     size_t length = strlen( endTag );
00197 
00198     // Inner loop of text parsing.
00199     while ( *p ) {
00200         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
00201             Set( start, p, strFlags );
00202             return p + length;
00203         }
00204         ++p;
00205     }
00206     return 0;
00207 }
00208 
00209 
00210 char* StrPair::ParseName( char* p )
00211 {
00212     if ( !p || !(*p) ) {
00213         return 0;
00214     }
00215     if ( !XMLUtil::IsNameStartChar( *p ) ) {
00216         return 0;
00217     }
00218 
00219     char* const start = p;
00220     ++p;
00221     while ( *p && XMLUtil::IsNameChar( *p ) ) {
00222         ++p;
00223     }
00224 
00225     Set( start, p, 0 );
00226     return p;
00227 }
00228 
00229 
00230 void StrPair::CollapseWhitespace()
00231 {
00232     // Adjusting _start would cause undefined behavior on delete[]
00233     TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
00234     // Trim leading space.
00235     _start = XMLUtil::SkipWhiteSpace( _start );
00236 
00237     if ( *_start ) {
00238         char* p = _start;       // the read pointer
00239         char* q = _start;       // the write pointer
00240 
00241         while( *p ) {
00242             if ( XMLUtil::IsWhiteSpace( *p )) {
00243                 p = XMLUtil::SkipWhiteSpace( p );
00244                 if ( *p == 0 ) {
00245                     break;    // don't write to q; this trims the trailing space.
00246                 }
00247                 *q = ' ';
00248                 ++q;
00249             }
00250             *q = *p;
00251             ++q;
00252             ++p;
00253         }
00254         *q = 0;
00255     }
00256 }
00257 
00258 
00259 const char* StrPair::GetStr()
00260 {
00261     TIXMLASSERT( _start );
00262     TIXMLASSERT( _end );
00263     if ( _flags & NEEDS_FLUSH ) {
00264         *_end = 0;
00265         _flags ^= NEEDS_FLUSH;
00266 
00267         if ( _flags ) {
00268             char* p = _start;   // the read pointer
00269             char* q = _start;   // the write pointer
00270 
00271             while( p < _end ) {
00272                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
00273                     // CR-LF pair becomes LF
00274                     // CR alone becomes LF
00275                     // LF-CR becomes LF
00276                     if ( *(p+1) == LF ) {
00277                         p += 2;
00278                     }
00279                     else {
00280                         ++p;
00281                     }
00282                     *q++ = LF;
00283                 }
00284                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
00285                     if ( *(p+1) == CR ) {
00286                         p += 2;
00287                     }
00288                     else {
00289                         ++p;
00290                     }
00291                     *q++ = LF;
00292                 }
00293                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
00294                     // Entities handled by tinyXML2:
00295                     // - special entities in the entity table [in/out]
00296                     // - numeric character reference [in]
00297                     //   &#20013; or &#x4e2d;
00298 
00299                     if ( *(p+1) == '#' ) {
00300                         const int buflen = 10;
00301                         char buf[buflen] = { 0 };
00302                         int len = 0;
00303                         char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
00304                         if ( adjusted == 0 ) {
00305                             *q = *p;
00306                             ++p;
00307                             ++q;
00308                         }
00309                         else {
00310                             TIXMLASSERT( 0 <= len && len <= buflen );
00311                             TIXMLASSERT( q + len <= adjusted );
00312                             p = adjusted;
00313                             memcpy( q, buf, len );
00314                             q += len;
00315                         }
00316                     }
00317                     else {
00318                         bool entityFound = false;
00319                         for( int i = 0; i < NUM_ENTITIES; ++i ) {
00320                             const Entity& entity = entities[i];
00321                             if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
00322                                     && *( p + entity.length + 1 ) == ';' ) {
00323                                 // Found an entity - convert.
00324                                 *q = entity.value;
00325                                 ++q;
00326                                 p += entity.length + 2;
00327                                 entityFound = true;
00328                                 break;
00329                             }
00330                         }
00331                         if ( !entityFound ) {
00332                             // fixme: treat as error?
00333                             ++p;
00334                             ++q;
00335                         }
00336                     }
00337                 }
00338                 else {
00339                     *q = *p;
00340                     ++p;
00341                     ++q;
00342                 }
00343             }
00344             *q = 0;
00345         }
00346         // The loop below has plenty going on, and this
00347         // is a less useful mode. Break it out.
00348         if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
00349             CollapseWhitespace();
00350         }
00351         _flags = (_flags & NEEDS_DELETE);
00352     }
00353     TIXMLASSERT( _start );
00354     return _start;
00355 }
00356 
00357 
00358 
00359 
00360 // --------- XMLUtil ----------- //
00361 
00362 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
00363 {
00364     TIXMLASSERT( p );
00365     TIXMLASSERT( bom );
00366     *bom = false;
00367     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
00368     // Check for BOM:
00369     if (    *(pu+0) == TIXML_UTF_LEAD_0
00370             && *(pu+1) == TIXML_UTF_LEAD_1
00371             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
00372         *bom = true;
00373         p += 3;
00374     }
00375     TIXMLASSERT( p );
00376     return p;
00377 }
00378 
00379 
00380 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
00381 {
00382     const unsigned long BYTE_MASK = 0xBF;
00383     const unsigned long BYTE_MARK = 0x80;
00384     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
00385 
00386     if (input < 0x80) {
00387         *length = 1;
00388     }
00389     else if ( input < 0x800 ) {
00390         *length = 2;
00391     }
00392     else if ( input < 0x10000 ) {
00393         *length = 3;
00394     }
00395     else if ( input < 0x200000 ) {
00396         *length = 4;
00397     }
00398     else {
00399         *length = 0;    // This code won't convert this correctly anyway.
00400         return;
00401     }
00402 
00403     output += *length;
00404 
00405     // Scary scary fall throughs.
00406     switch (*length) {
00407         case 4:
00408             --output;
00409             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00410             input >>= 6;
00411         case 3:
00412             --output;
00413             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00414             input >>= 6;
00415         case 2:
00416             --output;
00417             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00418             input >>= 6;
00419         case 1:
00420             --output;
00421             *output = (char)(input | FIRST_BYTE_MARK[*length]);
00422             break;
00423         default:
00424             TIXMLASSERT( false );
00425     }
00426 }
00427 
00428 
00429 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
00430 {
00431     // Presume an entity, and pull it out.
00432     *length = 0;
00433 
00434     if ( *(p+1) == '#' && *(p+2) ) {
00435         unsigned long ucs = 0;
00436         TIXMLASSERT( sizeof( ucs ) >= 4 );
00437         ptrdiff_t delta = 0;
00438         unsigned mult = 1;
00439         static const char SEMICOLON = ';';
00440 
00441         if ( *(p+2) == 'x' ) {
00442             // Hexadecimal.
00443             const char* q = p+3;
00444             if ( !(*q) ) {
00445                 return 0;
00446             }
00447 
00448             q = strchr( q, SEMICOLON );
00449 
00450             if ( !q ) {
00451                 return 0;
00452             }
00453             TIXMLASSERT( *q == SEMICOLON );
00454 
00455             delta = q-p;
00456             --q;
00457 
00458             while ( *q != 'x' ) {
00459                 unsigned int digit = 0;
00460 
00461                 if ( *q >= '0' && *q <= '9' ) {
00462                     digit = *q - '0';
00463                 }
00464                 else if ( *q >= 'a' && *q <= 'f' ) {
00465                     digit = *q - 'a' + 10;
00466                 }
00467                 else if ( *q >= 'A' && *q <= 'F' ) {
00468                     digit = *q - 'A' + 10;
00469                 }
00470                 else {
00471                     return 0;
00472                 }
00473                 TIXMLASSERT( digit >= 0 && digit < 16);
00474                 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
00475                 const unsigned int digitScaled = mult * digit;
00476                 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
00477                 ucs += digitScaled;
00478                 TIXMLASSERT( mult <= UINT_MAX / 16 );
00479                 mult *= 16;
00480                 --q;
00481             }
00482         }
00483         else {
00484             // Decimal.
00485             const char* q = p+2;
00486             if ( !(*q) ) {
00487                 return 0;
00488             }
00489 
00490             q = strchr( q, SEMICOLON );
00491 
00492             if ( !q ) {
00493                 return 0;
00494             }
00495             TIXMLASSERT( *q == SEMICOLON );
00496 
00497             delta = q-p;
00498             --q;
00499 
00500             while ( *q != '#' ) {
00501                 if ( *q >= '0' && *q <= '9' ) {
00502                     const unsigned int digit = *q - '0';
00503                     TIXMLASSERT( digit >= 0 && digit < 10);
00504                     TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
00505                     const unsigned int digitScaled = mult * digit;
00506                     TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
00507                     ucs += digitScaled;
00508                 }
00509                 else {
00510                     return 0;
00511                 }
00512                 TIXMLASSERT( mult <= UINT_MAX / 10 );
00513                 mult *= 10;
00514                 --q;
00515             }
00516         }
00517         // convert the UCS to UTF-8
00518         ConvertUTF32ToUTF8( ucs, value, length );
00519         return p + delta + 1;
00520     }
00521     return p+1;
00522 }
00523 
00524 
00525 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
00526 {
00527     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
00528 }
00529 
00530 
00531 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
00532 {
00533     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
00534 }
00535 
00536 
00537 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
00538 {
00539     TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
00540 }
00541 
00542 /*
00543         ToStr() of a number is a very tricky topic.
00544         https://github.com/leethomason/tinyxml2/issues/106
00545 */
00546 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
00547 {
00548     TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
00549 }
00550 
00551 
00552 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
00553 {
00554     TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
00555 }
00556 
00557 
00558 bool XMLUtil::ToInt( const char* str, int* value )
00559 {
00560     if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
00561         return true;
00562     }
00563     return false;
00564 }
00565 
00566 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
00567 {
00568     if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
00569         return true;
00570     }
00571     return false;
00572 }
00573 
00574 bool XMLUtil::ToBool( const char* str, bool* value )
00575 {
00576     int ival = 0;
00577     if ( ToInt( str, &ival )) {
00578         *value = (ival==0) ? false : true;
00579         return true;
00580     }
00581     if ( StringEqual( str, "true" ) ) {
00582         *value = true;
00583         return true;
00584     }
00585     else if ( StringEqual( str, "false" ) ) {
00586         *value = false;
00587         return true;
00588     }
00589     return false;
00590 }
00591 
00592 
00593 bool XMLUtil::ToFloat( const char* str, float* value )
00594 {
00595     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
00596         return true;
00597     }
00598     return false;
00599 }
00600 
00601 bool XMLUtil::ToDouble( const char* str, double* value )
00602 {
00603     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
00604         return true;
00605     }
00606     return false;
00607 }
00608 
00609 
00610 char* XMLDocument::Identify( char* p, XMLNode** node )
00611 {
00612     TIXMLASSERT( node );
00613     TIXMLASSERT( p );
00614     char* const start = p;
00615     p = XMLUtil::SkipWhiteSpace( p );
00616     if( !*p ) {
00617         *node = 0;
00618         TIXMLASSERT( p );
00619         return p;
00620     }
00621 
00622     // These strings define the matching patterns:
00623     static const char* xmlHeader                = { "<?" };
00624     static const char* commentHeader    = { "<!--" };
00625     static const char* cdataHeader              = { "<![CDATA[" };
00626     static const char* dtdHeader                = { "<!" };
00627     static const char* elementHeader    = { "<" };      // and a header for everything else; check last.
00628 
00629     static const int xmlHeaderLen               = 2;
00630     static const int commentHeaderLen   = 4;
00631     static const int cdataHeaderLen             = 9;
00632     static const int dtdHeaderLen               = 2;
00633     static const int elementHeaderLen   = 1;
00634 
00635     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );                // use same memory pool
00636     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
00637     XMLNode* returnNode = 0;
00638     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
00639         TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
00640         returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
00641         returnNode->_memPool = &_commentPool;
00642         p += xmlHeaderLen;
00643     }
00644     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
00645         TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
00646         returnNode = new (_commentPool.Alloc()) XMLComment( this );
00647         returnNode->_memPool = &_commentPool;
00648         p += commentHeaderLen;
00649     }
00650     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
00651         TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
00652         XMLText* text = new (_textPool.Alloc()) XMLText( this );
00653         returnNode = text;
00654         returnNode->_memPool = &_textPool;
00655         p += cdataHeaderLen;
00656         text->SetCData( true );
00657     }
00658     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
00659         TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
00660         returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
00661         returnNode->_memPool = &_commentPool;
00662         p += dtdHeaderLen;
00663     }
00664     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
00665         TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
00666         returnNode = new (_elementPool.Alloc()) XMLElement( this );
00667         returnNode->_memPool = &_elementPool;
00668         p += elementHeaderLen;
00669     }
00670     else {
00671         TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
00672         returnNode = new (_textPool.Alloc()) XMLText( this );
00673         returnNode->_memPool = &_textPool;
00674         p = start;      // Back it up, all the text counts.
00675     }
00676 
00677     TIXMLASSERT( returnNode );
00678     TIXMLASSERT( p );
00679     *node = returnNode;
00680     return p;
00681 }
00682 
00683 
00684 bool XMLDocument::Accept( XMLVisitor* visitor ) const
00685 {
00686     TIXMLASSERT( visitor );
00687     if ( visitor->VisitEnter( *this ) ) {
00688         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
00689             if ( !node->Accept( visitor ) ) {
00690                 break;
00691             }
00692         }
00693     }
00694     return visitor->VisitExit( *this );
00695 }
00696 
00697 
00698 // --------- XMLNode ----------- //
00699 
00700 XMLNode::XMLNode( XMLDocument* doc ) :
00701     _document( doc ),
00702     _parent( 0 ),
00703     _firstChild( 0 ), _lastChild( 0 ),
00704     _prev( 0 ), _next( 0 ),
00705     _memPool( 0 )
00706 {
00707 }
00708 
00709 
00710 XMLNode::~XMLNode()
00711 {
00712     DeleteChildren();
00713     if ( _parent ) {
00714         _parent->Unlink( this );
00715     }
00716 }
00717 
00718 const char* XMLNode::Value() const 
00719 {
00720     // Catch an edge case: XMLDocuments don't have a a Value. Carefully return nullptr.
00721     if ( this->ToDocument() )
00722         return 0;
00723     return _value.GetStr();
00724 }
00725 
00726 void XMLNode::SetValue( const char* str, bool staticMem )
00727 {
00728     if ( staticMem ) {
00729         _value.SetInternedStr( str );
00730     }
00731     else {
00732         _value.SetStr( str );
00733     }
00734 }
00735 
00736 
00737 void XMLNode::DeleteChildren()
00738 {
00739     while( _firstChild ) {
00740         TIXMLASSERT( _lastChild );
00741         TIXMLASSERT( _firstChild->_document == _document );
00742         XMLNode* node = _firstChild;
00743         Unlink( node );
00744 
00745         DeleteNode( node );
00746     }
00747     _firstChild = _lastChild = 0;
00748 }
00749 
00750 
00751 void XMLNode::Unlink( XMLNode* child )
00752 {
00753     TIXMLASSERT( child );
00754     TIXMLASSERT( child->_document == _document );
00755     TIXMLASSERT( child->_parent == this );
00756     if ( child == _firstChild ) {
00757         _firstChild = _firstChild->_next;
00758     }
00759     if ( child == _lastChild ) {
00760         _lastChild = _lastChild->_prev;
00761     }
00762 
00763     if ( child->_prev ) {
00764         child->_prev->_next = child->_next;
00765     }
00766     if ( child->_next ) {
00767         child->_next->_prev = child->_prev;
00768     }
00769         child->_parent = 0;
00770 }
00771 
00772 
00773 void XMLNode::DeleteChild( XMLNode* node )
00774 {
00775     TIXMLASSERT( node );
00776     TIXMLASSERT( node->_document == _document );
00777     TIXMLASSERT( node->_parent == this );
00778     DeleteNode( node );
00779 }
00780 
00781 
00782 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
00783 {
00784     TIXMLASSERT( addThis );
00785     if ( addThis->_document != _document ) {
00786         TIXMLASSERT( false );
00787         return 0;
00788     }
00789     InsertChildPreamble( addThis );
00790 
00791     if ( _lastChild ) {
00792         TIXMLASSERT( _firstChild );
00793         TIXMLASSERT( _lastChild->_next == 0 );
00794         _lastChild->_next = addThis;
00795         addThis->_prev = _lastChild;
00796         _lastChild = addThis;
00797 
00798         addThis->_next = 0;
00799     }
00800     else {
00801         TIXMLASSERT( _firstChild == 0 );
00802         _firstChild = _lastChild = addThis;
00803 
00804         addThis->_prev = 0;
00805         addThis->_next = 0;
00806     }
00807     addThis->_parent = this;
00808     return addThis;
00809 }
00810 
00811 
00812 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
00813 {
00814     TIXMLASSERT( addThis );
00815     if ( addThis->_document != _document ) {
00816         TIXMLASSERT( false );
00817         return 0;
00818     }
00819     InsertChildPreamble( addThis );
00820 
00821     if ( _firstChild ) {
00822         TIXMLASSERT( _lastChild );
00823         TIXMLASSERT( _firstChild->_prev == 0 );
00824 
00825         _firstChild->_prev = addThis;
00826         addThis->_next = _firstChild;
00827         _firstChild = addThis;
00828 
00829         addThis->_prev = 0;
00830     }
00831     else {
00832         TIXMLASSERT( _lastChild == 0 );
00833         _firstChild = _lastChild = addThis;
00834 
00835         addThis->_prev = 0;
00836         addThis->_next = 0;
00837     }
00838     addThis->_parent = this;
00839     return addThis;
00840 }
00841 
00842 
00843 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
00844 {
00845     TIXMLASSERT( addThis );
00846     if ( addThis->_document != _document ) {
00847         TIXMLASSERT( false );
00848         return 0;
00849     }
00850 
00851     TIXMLASSERT( afterThis );
00852 
00853     if ( afterThis->_parent != this ) {
00854         TIXMLASSERT( false );
00855         return 0;
00856     }
00857 
00858     if ( afterThis->_next == 0 ) {
00859         // The last node or the only node.
00860         return InsertEndChild( addThis );
00861     }
00862     InsertChildPreamble( addThis );
00863     addThis->_prev = afterThis;
00864     addThis->_next = afterThis->_next;
00865     afterThis->_next->_prev = addThis;
00866     afterThis->_next = addThis;
00867     addThis->_parent = this;
00868     return addThis;
00869 }
00870 
00871 
00872 
00873 
00874 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
00875 {
00876     for( const XMLNode* node = _firstChild; node; node = node->_next ) {
00877         const XMLElement* element = node->ToElement();
00878         if ( element ) {
00879             if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
00880                 return element;
00881             }
00882         }
00883     }
00884     return 0;
00885 }
00886 
00887 
00888 const XMLElement* XMLNode::LastChildElement( const char* name ) const
00889 {
00890     for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
00891         const XMLElement* element = node->ToElement();
00892         if ( element ) {
00893             if ( !name || XMLUtil::StringEqual( element->Name(), name ) ) {
00894                 return element;
00895             }
00896         }
00897     }
00898     return 0;
00899 }
00900 
00901 
00902 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
00903 {
00904     for( const XMLNode* node = _next; node; node = node->_next ) {
00905         const XMLElement* element = node->ToElement();
00906         if ( element
00907                 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
00908             return element;
00909         }
00910     }
00911     return 0;
00912 }
00913 
00914 
00915 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
00916 {
00917     for( const XMLNode* node = _prev; node; node = node->_prev ) {
00918         const XMLElement* element = node->ToElement();
00919         if ( element
00920                 && (!name || XMLUtil::StringEqual( name, element->Name() ))) {
00921             return element;
00922         }
00923     }
00924     return 0;
00925 }
00926 
00927 
00928 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
00929 {
00930     // This is a recursive method, but thinking about it "at the current level"
00931     // it is a pretty simple flat list:
00932     //          <foo/>
00933     //          <!-- comment -->
00934     //
00935     // With a special case:
00936     //          <foo>
00937     //          </foo>
00938     //          <!-- comment -->
00939     //
00940     // Where the closing element (/foo) *must* be the next thing after the opening
00941     // element, and the names must match. BUT the tricky bit is that the closing
00942     // element will be read by the child.
00943     //
00944     // 'endTag' is the end tag for this node, it is returned by a call to a child.
00945     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
00946 
00947     while( p && *p ) {
00948         XMLNode* node = 0;
00949 
00950         p = _document->Identify( p, &node );
00951         if ( node == 0 ) {
00952             break;
00953         }
00954 
00955         StrPair endTag;
00956         p = node->ParseDeep( p, &endTag );
00957         if ( !p ) {
00958             DeleteNode( node );
00959             if ( !_document->Error() ) {
00960                 _document->SetError( XML_ERROR_PARSING, 0, 0 );
00961             }
00962             break;
00963         }
00964 
00965         XMLDeclaration* decl = node->ToDeclaration();
00966         if ( decl ) {
00967                 // A declaration can only be the first child of a document.
00968                 // Set error, if document already has children.
00969                 if ( !_document->NoChildren() ) {
00970                         _document->SetError( XML_ERROR_PARSING_DECLARATION, decl->Value(), 0);
00971                         DeleteNode( decl );
00972                         break;
00973                 }
00974         }
00975 
00976         XMLElement* ele = node->ToElement();
00977         if ( ele ) {
00978             // We read the end tag. Return it to the parent.
00979             if ( ele->ClosingType() == XMLElement::CLOSING ) {
00980                 if ( parentEnd ) {
00981                     ele->_value.TransferTo( parentEnd );
00982                 }
00983                 node->_memPool->SetTracked();   // created and then immediately deleted.
00984                 DeleteNode( node );
00985                 return p;
00986             }
00987 
00988             // Handle an end tag returned to this level.
00989             // And handle a bunch of annoying errors.
00990             bool mismatch = false;
00991             if ( endTag.Empty() ) {
00992                 if ( ele->ClosingType() == XMLElement::OPEN ) {
00993                     mismatch = true;
00994                 }
00995             }
00996             else {
00997                 if ( ele->ClosingType() != XMLElement::OPEN ) {
00998                     mismatch = true;
00999                 }
01000                 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
01001                     mismatch = true;
01002                 }
01003             }
01004             if ( mismatch ) {
01005                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, ele->Name(), 0 );
01006                 DeleteNode( node );
01007                 break;
01008             }
01009         }
01010         InsertEndChild( node );
01011     }
01012     return 0;
01013 }
01014 
01015 void XMLNode::DeleteNode( XMLNode* node )
01016 {
01017     if ( node == 0 ) {
01018         return;
01019     }
01020     MemPool* pool = node->_memPool;
01021     node->~XMLNode();
01022     pool->Free( node );
01023 }
01024 
01025 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
01026 {
01027     TIXMLASSERT( insertThis );
01028     TIXMLASSERT( insertThis->_document == _document );
01029 
01030     if ( insertThis->_parent )
01031         insertThis->_parent->Unlink( insertThis );
01032     else
01033         insertThis->_memPool->SetTracked();
01034 }
01035 
01036 // --------- XMLText ---------- //
01037 char* XMLText::ParseDeep( char* p, StrPair* )
01038 {
01039     const char* start = p;
01040     if ( this->CData() ) {
01041         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
01042         if ( !p ) {
01043             _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
01044         }
01045         return p;
01046     }
01047     else {
01048         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
01049         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
01050             flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
01051         }
01052 
01053         p = _value.ParseText( p, "<", flags );
01054         if ( p && *p ) {
01055             return p-1;
01056         }
01057         if ( !p ) {
01058             _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
01059         }
01060     }
01061     return 0;
01062 }
01063 
01064 
01065 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
01066 {
01067     if ( !doc ) {
01068         doc = _document;
01069     }
01070     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
01071     text->SetCData( this->CData() );
01072     return text;
01073 }
01074 
01075 
01076 bool XMLText::ShallowEqual( const XMLNode* compare ) const
01077 {
01078     const XMLText* text = compare->ToText();
01079     return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
01080 }
01081 
01082 
01083 bool XMLText::Accept( XMLVisitor* visitor ) const
01084 {
01085     TIXMLASSERT( visitor );
01086     return visitor->Visit( *this );
01087 }
01088 
01089 
01090 // --------- XMLComment ---------- //
01091 
01092 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
01093 {
01094 }
01095 
01096 
01097 XMLComment::~XMLComment()
01098 {
01099 }
01100 
01101 
01102 char* XMLComment::ParseDeep( char* p, StrPair* )
01103 {
01104     // Comment parses as text.
01105     const char* start = p;
01106     p = _value.ParseText( p, "-->", StrPair::COMMENT );
01107     if ( p == 0 ) {
01108         _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
01109     }
01110     return p;
01111 }
01112 
01113 
01114 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
01115 {
01116     if ( !doc ) {
01117         doc = _document;
01118     }
01119     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?
01120     return comment;
01121 }
01122 
01123 
01124 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
01125 {
01126     TIXMLASSERT( compare );
01127     const XMLComment* comment = compare->ToComment();
01128     return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
01129 }
01130 
01131 
01132 bool XMLComment::Accept( XMLVisitor* visitor ) const
01133 {
01134     TIXMLASSERT( visitor );
01135     return visitor->Visit( *this );
01136 }
01137 
01138 
01139 // --------- XMLDeclaration ---------- //
01140 
01141 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
01142 {
01143 }
01144 
01145 
01146 XMLDeclaration::~XMLDeclaration()
01147 {
01148     //printf( "~XMLDeclaration\n" );
01149 }
01150 
01151 
01152 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
01153 {
01154     // Declaration parses as text.
01155     const char* start = p;
01156     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
01157     if ( p == 0 ) {
01158         _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
01159     }
01160     return p;
01161 }
01162 
01163 
01164 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
01165 {
01166     if ( !doc ) {
01167         doc = _document;
01168     }
01169     XMLDeclaration* dec = doc->NewDeclaration( Value() );       // fixme: this will always allocate memory. Intern?
01170     return dec;
01171 }
01172 
01173 
01174 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
01175 {
01176     TIXMLASSERT( compare );
01177     const XMLDeclaration* declaration = compare->ToDeclaration();
01178     return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
01179 }
01180 
01181 
01182 
01183 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
01184 {
01185     TIXMLASSERT( visitor );
01186     return visitor->Visit( *this );
01187 }
01188 
01189 // --------- XMLUnknown ---------- //
01190 
01191 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
01192 {
01193 }
01194 
01195 
01196 XMLUnknown::~XMLUnknown()
01197 {
01198 }
01199 
01200 
01201 char* XMLUnknown::ParseDeep( char* p, StrPair* )
01202 {
01203     // Unknown parses as text.
01204     const char* start = p;
01205 
01206     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
01207     if ( !p ) {
01208         _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
01209     }
01210     return p;
01211 }
01212 
01213 
01214 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
01215 {
01216     if ( !doc ) {
01217         doc = _document;
01218     }
01219     XMLUnknown* text = doc->NewUnknown( Value() );      // fixme: this will always allocate memory. Intern?
01220     return text;
01221 }
01222 
01223 
01224 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
01225 {
01226     TIXMLASSERT( compare );
01227     const XMLUnknown* unknown = compare->ToUnknown();
01228     return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
01229 }
01230 
01231 
01232 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
01233 {
01234     TIXMLASSERT( visitor );
01235     return visitor->Visit( *this );
01236 }
01237 
01238 // --------- XMLAttribute ---------- //
01239 
01240 const char* XMLAttribute::Name() const 
01241 {
01242     return _name.GetStr();
01243 }
01244 
01245 const char* XMLAttribute::Value() const 
01246 {
01247     return _value.GetStr();
01248 }
01249 
01250 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
01251 {
01252     // Parse using the name rules: bug fix, was using ParseText before
01253     p = _name.ParseName( p );
01254     if ( !p || !*p ) {
01255         return 0;
01256     }
01257 
01258     // Skip white space before =
01259     p = XMLUtil::SkipWhiteSpace( p );
01260     if ( *p != '=' ) {
01261         return 0;
01262     }
01263 
01264     ++p;        // move up to opening quote
01265     p = XMLUtil::SkipWhiteSpace( p );
01266     if ( *p != '\"' && *p != '\'' ) {
01267         return 0;
01268     }
01269 
01270     char endTag[2] = { *p, 0 };
01271     ++p;        // move past opening quote
01272 
01273     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
01274     return p;
01275 }
01276 
01277 
01278 void XMLAttribute::SetName( const char* n )
01279 {
01280     _name.SetStr( n );
01281 }
01282 
01283 
01284 XMLError XMLAttribute::QueryIntValue( int* value ) const
01285 {
01286     if ( XMLUtil::ToInt( Value(), value )) {
01287         return XML_NO_ERROR;
01288     }
01289     return XML_WRONG_ATTRIBUTE_TYPE;
01290 }
01291 
01292 
01293 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
01294 {
01295     if ( XMLUtil::ToUnsigned( Value(), value )) {
01296         return XML_NO_ERROR;
01297     }
01298     return XML_WRONG_ATTRIBUTE_TYPE;
01299 }
01300 
01301 
01302 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
01303 {
01304     if ( XMLUtil::ToBool( Value(), value )) {
01305         return XML_NO_ERROR;
01306     }
01307     return XML_WRONG_ATTRIBUTE_TYPE;
01308 }
01309 
01310 
01311 XMLError XMLAttribute::QueryFloatValue( float* value ) const
01312 {
01313     if ( XMLUtil::ToFloat( Value(), value )) {
01314         return XML_NO_ERROR;
01315     }
01316     return XML_WRONG_ATTRIBUTE_TYPE;
01317 }
01318 
01319 
01320 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
01321 {
01322     if ( XMLUtil::ToDouble( Value(), value )) {
01323         return XML_NO_ERROR;
01324     }
01325     return XML_WRONG_ATTRIBUTE_TYPE;
01326 }
01327 
01328 
01329 void XMLAttribute::SetAttribute( const char* v )
01330 {
01331     _value.SetStr( v );
01332 }
01333 
01334 
01335 void XMLAttribute::SetAttribute( int v )
01336 {
01337     char buf[BUF_SIZE];
01338     XMLUtil::ToStr( v, buf, BUF_SIZE );
01339     _value.SetStr( buf );
01340 }
01341 
01342 
01343 void XMLAttribute::SetAttribute( unsigned v )
01344 {
01345     char buf[BUF_SIZE];
01346     XMLUtil::ToStr( v, buf, BUF_SIZE );
01347     _value.SetStr( buf );
01348 }
01349 
01350 
01351 void XMLAttribute::SetAttribute( bool v )
01352 {
01353     char buf[BUF_SIZE];
01354     XMLUtil::ToStr( v, buf, BUF_SIZE );
01355     _value.SetStr( buf );
01356 }
01357 
01358 void XMLAttribute::SetAttribute( double v )
01359 {
01360     char buf[BUF_SIZE];
01361     XMLUtil::ToStr( v, buf, BUF_SIZE );
01362     _value.SetStr( buf );
01363 }
01364 
01365 void XMLAttribute::SetAttribute( float v )
01366 {
01367     char buf[BUF_SIZE];
01368     XMLUtil::ToStr( v, buf, BUF_SIZE );
01369     _value.SetStr( buf );
01370 }
01371 
01372 
01373 // --------- XMLElement ---------- //
01374 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
01375     _closingType( 0 ),
01376     _rootAttribute( 0 )
01377 {
01378 }
01379 
01380 
01381 XMLElement::~XMLElement()
01382 {
01383     while( _rootAttribute ) {
01384         XMLAttribute* next = _rootAttribute->_next;
01385         DeleteAttribute( _rootAttribute );
01386         _rootAttribute = next;
01387     }
01388 }
01389 
01390 
01391 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
01392 {
01393     for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
01394         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
01395             return a;
01396         }
01397     }
01398     return 0;
01399 }
01400 
01401 
01402 const char* XMLElement::Attribute( const char* name, const char* value ) const
01403 {
01404     const XMLAttribute* a = FindAttribute( name );
01405     if ( !a ) {
01406         return 0;
01407     }
01408     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
01409         return a->Value();
01410     }
01411     return 0;
01412 }
01413 
01414 
01415 const char* XMLElement::GetText() const
01416 {
01417     if ( FirstChild() && FirstChild()->ToText() ) {
01418         return FirstChild()->Value();
01419     }
01420     return 0;
01421 }
01422 
01423 
01424 void    XMLElement::SetText( const char* inText )
01425 {
01426         if ( FirstChild() && FirstChild()->ToText() )
01427                 FirstChild()->SetValue( inText );
01428         else {
01429                 XMLText*        theText = GetDocument()->NewText( inText );
01430                 InsertFirstChild( theText );
01431         }
01432 }
01433 
01434 
01435 void XMLElement::SetText( int v ) 
01436 {
01437     char buf[BUF_SIZE];
01438     XMLUtil::ToStr( v, buf, BUF_SIZE );
01439     SetText( buf );
01440 }
01441 
01442 
01443 void XMLElement::SetText( unsigned v ) 
01444 {
01445     char buf[BUF_SIZE];
01446     XMLUtil::ToStr( v, buf, BUF_SIZE );
01447     SetText( buf );
01448 }
01449 
01450 
01451 void XMLElement::SetText( bool v ) 
01452 {
01453     char buf[BUF_SIZE];
01454     XMLUtil::ToStr( v, buf, BUF_SIZE );
01455     SetText( buf );
01456 }
01457 
01458 
01459 void XMLElement::SetText( float v ) 
01460 {
01461     char buf[BUF_SIZE];
01462     XMLUtil::ToStr( v, buf, BUF_SIZE );
01463     SetText( buf );
01464 }
01465 
01466 
01467 void XMLElement::SetText( double v ) 
01468 {
01469     char buf[BUF_SIZE];
01470     XMLUtil::ToStr( v, buf, BUF_SIZE );
01471     SetText( buf );
01472 }
01473 
01474 
01475 XMLError XMLElement::QueryIntText( int* ival ) const
01476 {
01477     if ( FirstChild() && FirstChild()->ToText() ) {
01478         const char* t = FirstChild()->Value();
01479         if ( XMLUtil::ToInt( t, ival ) ) {
01480             return XML_SUCCESS;
01481         }
01482         return XML_CAN_NOT_CONVERT_TEXT;
01483     }
01484     return XML_NO_TEXT_NODE;
01485 }
01486 
01487 
01488 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
01489 {
01490     if ( FirstChild() && FirstChild()->ToText() ) {
01491         const char* t = FirstChild()->Value();
01492         if ( XMLUtil::ToUnsigned( t, uval ) ) {
01493             return XML_SUCCESS;
01494         }
01495         return XML_CAN_NOT_CONVERT_TEXT;
01496     }
01497     return XML_NO_TEXT_NODE;
01498 }
01499 
01500 
01501 XMLError XMLElement::QueryBoolText( bool* bval ) const
01502 {
01503     if ( FirstChild() && FirstChild()->ToText() ) {
01504         const char* t = FirstChild()->Value();
01505         if ( XMLUtil::ToBool( t, bval ) ) {
01506             return XML_SUCCESS;
01507         }
01508         return XML_CAN_NOT_CONVERT_TEXT;
01509     }
01510     return XML_NO_TEXT_NODE;
01511 }
01512 
01513 
01514 XMLError XMLElement::QueryDoubleText( double* dval ) const
01515 {
01516     if ( FirstChild() && FirstChild()->ToText() ) {
01517         const char* t = FirstChild()->Value();
01518         if ( XMLUtil::ToDouble( t, dval ) ) {
01519             return XML_SUCCESS;
01520         }
01521         return XML_CAN_NOT_CONVERT_TEXT;
01522     }
01523     return XML_NO_TEXT_NODE;
01524 }
01525 
01526 
01527 XMLError XMLElement::QueryFloatText( float* fval ) const
01528 {
01529     if ( FirstChild() && FirstChild()->ToText() ) {
01530         const char* t = FirstChild()->Value();
01531         if ( XMLUtil::ToFloat( t, fval ) ) {
01532             return XML_SUCCESS;
01533         }
01534         return XML_CAN_NOT_CONVERT_TEXT;
01535     }
01536     return XML_NO_TEXT_NODE;
01537 }
01538 
01539 
01540 
01541 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
01542 {
01543     XMLAttribute* last = 0;
01544     XMLAttribute* attrib = 0;
01545     for( attrib = _rootAttribute;
01546             attrib;
01547             last = attrib, attrib = attrib->_next ) {
01548         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
01549             break;
01550         }
01551     }
01552     if ( !attrib ) {
01553         TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
01554         attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
01555         attrib->_memPool = &_document->_attributePool;
01556         if ( last ) {
01557             last->_next = attrib;
01558         }
01559         else {
01560             _rootAttribute = attrib;
01561         }
01562         attrib->SetName( name );
01563         attrib->_memPool->SetTracked(); // always created and linked.
01564     }
01565     return attrib;
01566 }
01567 
01568 
01569 void XMLElement::DeleteAttribute( const char* name )
01570 {
01571     XMLAttribute* prev = 0;
01572     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
01573         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
01574             if ( prev ) {
01575                 prev->_next = a->_next;
01576             }
01577             else {
01578                 _rootAttribute = a->_next;
01579             }
01580             DeleteAttribute( a );
01581             break;
01582         }
01583         prev = a;
01584     }
01585 }
01586 
01587 
01588 char* XMLElement::ParseAttributes( char* p )
01589 {
01590     const char* start = p;
01591     XMLAttribute* prevAttribute = 0;
01592 
01593     // Read the attributes.
01594     while( p ) {
01595         p = XMLUtil::SkipWhiteSpace( p );
01596         if ( !(*p) ) {
01597             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
01598             return 0;
01599         }
01600 
01601         // attribute.
01602         if (XMLUtil::IsNameStartChar( *p ) ) {
01603             TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
01604             XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
01605             attrib->_memPool = &_document->_attributePool;
01606                         attrib->_memPool->SetTracked();
01607 
01608             p = attrib->ParseDeep( p, _document->ProcessEntities() );
01609             if ( !p || Attribute( attrib->Name() ) ) {
01610                 DeleteAttribute( attrib );
01611                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
01612                 return 0;
01613             }
01614             // There is a minor bug here: if the attribute in the source xml
01615             // document is duplicated, it will not be detected and the
01616             // attribute will be doubly added. However, tracking the 'prevAttribute'
01617             // avoids re-scanning the attribute list. Preferring performance for
01618             // now, may reconsider in the future.
01619             if ( prevAttribute ) {
01620                 prevAttribute->_next = attrib;
01621             }
01622             else {
01623                 _rootAttribute = attrib;
01624             }
01625             prevAttribute = attrib;
01626         }
01627         // end of the tag
01628         else if ( *p == '>' ) {
01629             ++p;
01630             break;
01631         }
01632         // end of the tag
01633         else if ( *p == '/' && *(p+1) == '>' ) {
01634             _closingType = CLOSED;
01635             return p+2; // done; sealed element.
01636         }
01637         else {
01638             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
01639             return 0;
01640         }
01641     }
01642     return p;
01643 }
01644 
01645 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
01646 {
01647     if ( attribute == 0 ) {
01648         return;
01649     }
01650     MemPool* pool = attribute->_memPool;
01651     attribute->~XMLAttribute();
01652     pool->Free( attribute );
01653 }
01654 
01655 //
01656 //      <ele></ele>
01657 //      <ele>foo<b>bar</b></ele>
01658 //
01659 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
01660 {
01661     // Read the element name.
01662     p = XMLUtil::SkipWhiteSpace( p );
01663 
01664     // The closing element is the </element> form. It is
01665     // parsed just like a regular element then deleted from
01666     // the DOM.
01667     if ( *p == '/' ) {
01668         _closingType = CLOSING;
01669         ++p;
01670     }
01671 
01672     p = _value.ParseName( p );
01673     if ( _value.Empty() ) {
01674         return 0;
01675     }
01676 
01677     p = ParseAttributes( p );
01678     if ( !p || !*p || _closingType ) {
01679         return p;
01680     }
01681 
01682     p = XMLNode::ParseDeep( p, strPair );
01683     return p;
01684 }
01685 
01686 
01687 
01688 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
01689 {
01690     if ( !doc ) {
01691         doc = _document;
01692     }
01693     XMLElement* element = doc->NewElement( Value() );                                   // fixme: this will always allocate memory. Intern?
01694     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
01695         element->SetAttribute( a->Name(), a->Value() );                                 // fixme: this will always allocate memory. Intern?
01696     }
01697     return element;
01698 }
01699 
01700 
01701 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
01702 {
01703     TIXMLASSERT( compare );
01704     const XMLElement* other = compare->ToElement();
01705     if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
01706 
01707         const XMLAttribute* a=FirstAttribute();
01708         const XMLAttribute* b=other->FirstAttribute();
01709 
01710         while ( a && b ) {
01711             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
01712                 return false;
01713             }
01714             a = a->Next();
01715             b = b->Next();
01716         }
01717         if ( a || b ) {
01718             // different count
01719             return false;
01720         }
01721         return true;
01722     }
01723     return false;
01724 }
01725 
01726 
01727 bool XMLElement::Accept( XMLVisitor* visitor ) const
01728 {
01729     TIXMLASSERT( visitor );
01730     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
01731         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
01732             if ( !node->Accept( visitor ) ) {
01733                 break;
01734             }
01735         }
01736     }
01737     return visitor->VisitExit( *this );
01738 }
01739 
01740 
01741 // --------- XMLDocument ----------- //
01742 
01743 // Warning: List must match 'enum XMLError'
01744 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
01745     "XML_SUCCESS",
01746     "XML_NO_ATTRIBUTE",
01747     "XML_WRONG_ATTRIBUTE_TYPE",
01748     "XML_ERROR_FILE_NOT_FOUND",
01749     "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
01750     "XML_ERROR_FILE_READ_ERROR",
01751     "XML_ERROR_ELEMENT_MISMATCH",
01752     "XML_ERROR_PARSING_ELEMENT",
01753     "XML_ERROR_PARSING_ATTRIBUTE",
01754     "XML_ERROR_IDENTIFYING_TAG",
01755     "XML_ERROR_PARSING_TEXT",
01756     "XML_ERROR_PARSING_CDATA",
01757     "XML_ERROR_PARSING_COMMENT",
01758     "XML_ERROR_PARSING_DECLARATION",
01759     "XML_ERROR_PARSING_UNKNOWN",
01760     "XML_ERROR_EMPTY_DOCUMENT",
01761     "XML_ERROR_MISMATCHED_ELEMENT",
01762     "XML_ERROR_PARSING",
01763     "XML_CAN_NOT_CONVERT_TEXT",
01764     "XML_NO_TEXT_NODE"
01765 };
01766 
01767 
01768 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
01769     XMLNode( 0 ),
01770     _writeBOM( false ),
01771     _processEntities( processEntities ),
01772     _errorID( XML_NO_ERROR ),
01773     _whitespace( whitespace ),
01774     _errorStr1( 0 ),
01775     _errorStr2( 0 ),
01776     _charBuffer( 0 )
01777 {
01778     // avoid VC++ C4355 warning about 'this' in initializer list (C4355 is off by default in VS2012+)
01779     _document = this;
01780 }
01781 
01782 
01783 XMLDocument::~XMLDocument()
01784 {
01785     Clear();
01786 }
01787 
01788 
01789 void XMLDocument::Clear()
01790 {
01791     DeleteChildren();
01792 
01793 #ifdef DEBUG
01794     const bool hadError = Error();
01795 #endif
01796     _errorID = XML_NO_ERROR;
01797     _errorStr1 = 0;
01798     _errorStr2 = 0;
01799 
01800     delete [] _charBuffer;
01801     _charBuffer = 0;
01802 
01803 #if 0
01804     _textPool.Trace( "text" );
01805     _elementPool.Trace( "element" );
01806     _commentPool.Trace( "comment" );
01807     _attributePool.Trace( "attribute" );
01808 #endif
01809     
01810 #ifdef DEBUG
01811     if ( !hadError ) {
01812         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
01813         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
01814         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
01815         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
01816     }
01817 #endif
01818 }
01819 
01820 
01821 XMLElement* XMLDocument::NewElement( const char* name )
01822 {
01823     TIXMLASSERT( sizeof( XMLElement ) == _elementPool.ItemSize() );
01824     XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
01825     ele->_memPool = &_elementPool;
01826     ele->SetName( name );
01827     return ele;
01828 }
01829 
01830 
01831 XMLComment* XMLDocument::NewComment( const char* str )
01832 {
01833     TIXMLASSERT( sizeof( XMLComment ) == _commentPool.ItemSize() );
01834     XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
01835     comment->_memPool = &_commentPool;
01836     comment->SetValue( str );
01837     return comment;
01838 }
01839 
01840 
01841 XMLText* XMLDocument::NewText( const char* str )
01842 {
01843     TIXMLASSERT( sizeof( XMLText ) == _textPool.ItemSize() );
01844     XMLText* text = new (_textPool.Alloc()) XMLText( this );
01845     text->_memPool = &_textPool;
01846     text->SetValue( str );
01847     return text;
01848 }
01849 
01850 
01851 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
01852 {
01853     TIXMLASSERT( sizeof( XMLDeclaration ) == _commentPool.ItemSize() );
01854     XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
01855     dec->_memPool = &_commentPool;
01856     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
01857     return dec;
01858 }
01859 
01860 
01861 XMLUnknown* XMLDocument::NewUnknown( const char* str )
01862 {
01863     TIXMLASSERT( sizeof( XMLUnknown ) == _commentPool.ItemSize() );
01864     XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
01865     unk->_memPool = &_commentPool;
01866     unk->SetValue( str );
01867     return unk;
01868 }
01869 
01870 static FILE* callfopen( const char* filepath, const char* mode )
01871 {
01872     TIXMLASSERT( filepath );
01873     TIXMLASSERT( mode );
01874 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
01875     FILE* fp = 0;
01876     errno_t err = fopen_s( &fp, filepath, mode );
01877     if ( err ) {
01878         return 0;
01879     }
01880 #else
01881     FILE* fp = fopen( filepath, mode );
01882 #endif
01883     return fp;
01884 }
01885     
01886 void XMLDocument::DeleteNode( XMLNode* node )   {
01887     TIXMLASSERT( node );
01888     TIXMLASSERT(node->_document == this );
01889     if (node->_parent) {
01890         node->_parent->DeleteChild( node );
01891     }
01892     else {
01893         // Isn't in the tree.
01894         // Use the parent delete.
01895         // Also, we need to mark it tracked: we 'know'
01896         // it was never used.
01897         node->_memPool->SetTracked();
01898         // Call the static XMLNode version:
01899         XMLNode::DeleteNode(node);
01900     }
01901 }
01902 
01903 
01904 XMLError XMLDocument::LoadFile( const char* filename )
01905 {
01906     Clear();
01907     FILE* fp = callfopen( filename, "rb" );
01908     if ( !fp ) {
01909         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
01910         return _errorID;
01911     }
01912     LoadFile( fp );
01913     fclose( fp );
01914     return _errorID;
01915 }
01916 
01917 // This is likely overengineered template art to have a check that unsigned long value incremented
01918 // by one still fits into size_t. If size_t type is larger than unsigned long type
01919 // (x86_64-w64-mingw32 target) then the check is redundant and gcc and clang emit
01920 // -Wtype-limits warning. This piece makes the compiler select code with a check when a check
01921 // is useful and code with no check when a check is redundant depending on how size_t and unsigned long
01922 // types sizes relate to each other.
01923 template
01924 <bool = (sizeof(unsigned long) >= sizeof(size_t))>
01925 struct LongFitsIntoSizeTMinusOne {
01926     static bool Fits( unsigned long value )
01927     {
01928         return value < (size_t)-1;
01929     }
01930 };
01931 
01932 template <>
01933 bool LongFitsIntoSizeTMinusOne<false>::Fits( unsigned long /*value*/ )
01934 {
01935     return true;
01936 }
01937 
01938 XMLError XMLDocument::LoadFile( FILE* fp )
01939 {
01940     Clear();
01941 
01942     fseek( fp, 0, SEEK_SET );
01943     if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
01944         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
01945         return _errorID;
01946     }
01947 
01948     fseek( fp, 0, SEEK_END );
01949     const long filelength = ftell( fp );
01950     fseek( fp, 0, SEEK_SET );
01951     if ( filelength == -1L ) {
01952         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
01953         return _errorID;
01954     }
01955 
01956     if ( !LongFitsIntoSizeTMinusOne<>::Fits( filelength ) ) {
01957         // Cannot handle files which won't fit in buffer together with null terminator
01958         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
01959         return _errorID;
01960     }
01961 
01962     if ( filelength == 0 ) {
01963         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
01964         return _errorID;
01965     }
01966 
01967     const size_t size = filelength;
01968     TIXMLASSERT( _charBuffer == 0 );
01969     _charBuffer = new char[size+1];
01970     size_t read = fread( _charBuffer, 1, size, fp );
01971     if ( read != size ) {
01972         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
01973         return _errorID;
01974     }
01975 
01976     _charBuffer[size] = 0;
01977 
01978     Parse();
01979     return _errorID;
01980 }
01981 
01982 
01983 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
01984 {
01985     FILE* fp = callfopen( filename, "w" );
01986     if ( !fp ) {
01987         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
01988         return _errorID;
01989     }
01990     SaveFile(fp, compact);
01991     fclose( fp );
01992     return _errorID;
01993 }
01994 
01995 
01996 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
01997 {
01998     // Clear any error from the last save, otherwise it will get reported
01999     // for *this* call.
02000     SetError( XML_NO_ERROR, 0, 0 );
02001     XMLPrinter stream( fp, compact );
02002     Print( &stream );
02003     return _errorID;
02004 }
02005 
02006 
02007 XMLError XMLDocument::Parse( const char* p, size_t len )
02008 {
02009     Clear();
02010 
02011     if ( len == 0 || !p || !*p ) {
02012         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02013         return _errorID;
02014     }
02015     if ( len == (size_t)(-1) ) {
02016         len = strlen( p );
02017     }
02018     TIXMLASSERT( _charBuffer == 0 );
02019     _charBuffer = new char[ len+1 ];
02020     memcpy( _charBuffer, p, len );
02021     _charBuffer[len] = 0;
02022 
02023     Parse();
02024     if ( Error() ) {
02025         // clean up now essentially dangling memory.
02026         // and the parse fail can put objects in the
02027         // pools that are dead and inaccessible.
02028         DeleteChildren();
02029         _elementPool.Clear();
02030         _attributePool.Clear();
02031         _textPool.Clear();
02032         _commentPool.Clear();
02033     }
02034     return _errorID;
02035 }
02036 
02037 
02038 void XMLDocument::Print( XMLPrinter* streamer ) const
02039 {
02040     if ( streamer ) {
02041         Accept( streamer );
02042     }
02043     else {
02044         XMLPrinter stdoutStreamer( stdout );
02045         Accept( &stdoutStreamer );
02046     }
02047 }
02048 
02049 
02050 void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
02051 {
02052     TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
02053     _errorID = error;
02054     _errorStr1 = str1;
02055     _errorStr2 = str2;
02056 }
02057 
02058 const char* XMLDocument::ErrorName() const
02059 {
02060         TIXMLASSERT( _errorID >= 0 && _errorID < XML_ERROR_COUNT );
02061     const char* errorName = _errorNames[_errorID];
02062     TIXMLASSERT( errorName && errorName[0] );
02063     return errorName;
02064 }
02065 
02066 void XMLDocument::PrintError() const
02067 {
02068     if ( Error() ) {
02069         static const int LEN = 20;
02070         char buf1[LEN] = { 0 };
02071         char buf2[LEN] = { 0 };
02072 
02073         if ( _errorStr1 ) {
02074             TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
02075         }
02076         if ( _errorStr2 ) {
02077             TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
02078         }
02079 
02080         // Should check INT_MIN <= _errorID && _errorId <= INT_MAX, but that
02081         // causes a clang "always true" -Wtautological-constant-out-of-range-compare warning
02082         TIXMLASSERT( 0 <= _errorID && XML_ERROR_COUNT - 1 <= INT_MAX );
02083         printf( "XMLDocument error id=%d '%s' str1=%s str2=%s\n",
02084                 static_cast<int>( _errorID ), ErrorName(), buf1, buf2 );
02085     }
02086 }
02087 
02088 void XMLDocument::Parse()
02089 {
02090     TIXMLASSERT( NoChildren() ); // Clear() must have been called previously
02091     TIXMLASSERT( _charBuffer );
02092     char* p = _charBuffer;
02093     p = XMLUtil::SkipWhiteSpace( p );
02094     p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
02095     if ( !*p ) {
02096         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
02097         return;
02098     }
02099     ParseDeep(p, 0 );
02100 }
02101 
02102 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
02103     _elementJustOpened( false ),
02104     _firstElement( true ),
02105     _fp( file ),
02106     _depth( depth ),
02107     _textDepth( -1 ),
02108     _processEntities( true ),
02109     _compactMode( compact )
02110 {
02111     for( int i=0; i<ENTITY_RANGE; ++i ) {
02112         _entityFlag[i] = false;
02113         _restrictedEntityFlag[i] = false;
02114     }
02115     for( int i=0; i<NUM_ENTITIES; ++i ) {
02116         const char entityValue = entities[i].value;
02117         TIXMLASSERT( 0 <= entityValue && entityValue < ENTITY_RANGE );
02118         _entityFlag[ (unsigned char)entityValue ] = true;
02119     }
02120     _restrictedEntityFlag[(unsigned char)'&'] = true;
02121     _restrictedEntityFlag[(unsigned char)'<'] = true;
02122     _restrictedEntityFlag[(unsigned char)'>'] = true;   // not required, but consistency is nice
02123     _buffer.Push( 0 );
02124 }
02125 
02126 
02127 void XMLPrinter::Print( const char* format, ... )
02128 {
02129     va_list     va;
02130     va_start( va, format );
02131 
02132     if ( _fp ) {
02133         vfprintf( _fp, format, va );
02134     }
02135     else {
02136         const int len = TIXML_VSCPRINTF( format, va );
02137         // Close out and re-start the va-args
02138         va_end( va );
02139         TIXMLASSERT( len >= 0 );
02140         va_start( va, format );
02141         TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
02142         char* p = _buffer.PushArr( len ) - 1;   // back up over the null terminator.
02143                 TIXML_VSNPRINTF( p, len+1, format, va );
02144     }
02145     va_end( va );
02146 }
02147 
02148 
02149 void XMLPrinter::PrintSpace( int depth )
02150 {
02151     for( int i=0; i<depth; ++i ) {
02152         Print( "    " );
02153     }
02154 }
02155 
02156 
02157 void XMLPrinter::PrintString( const char* p, bool restricted )
02158 {
02159     // Look for runs of bytes between entities to print.
02160     const char* q = p;
02161 
02162     if ( _processEntities ) {
02163         const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
02164         while ( *q ) {
02165             TIXMLASSERT( p <= q );
02166             // Remember, char is sometimes signed. (How many times has that bitten me?)
02167             if ( *q > 0 && *q < ENTITY_RANGE ) {
02168                 // Check for entities. If one is found, flush
02169                 // the stream up until the entity, write the
02170                 // entity, and keep looking.
02171                 if ( flag[(unsigned char)(*q)] ) {
02172                     while ( p < q ) {
02173                         const size_t delta = q - p;
02174                         // %.*s accepts type int as "precision"
02175                         const int toPrint = ( INT_MAX < delta ) ? INT_MAX : (int)delta;
02176                         Print( "%.*s", toPrint, p );
02177                         p += toPrint;
02178                     }
02179                     bool entityPatternPrinted = false;
02180                     for( int i=0; i<NUM_ENTITIES; ++i ) {
02181                         if ( entities[i].value == *q ) {
02182                             Print( "&%s;", entities[i].pattern );
02183                             entityPatternPrinted = true;
02184                             break;
02185                         }
02186                     }
02187                     if ( !entityPatternPrinted ) {
02188                         // TIXMLASSERT( entityPatternPrinted ) causes gcc -Wunused-but-set-variable in release
02189                         TIXMLASSERT( false );
02190                     }
02191                     ++p;
02192                 }
02193             }
02194             ++q;
02195             TIXMLASSERT( p <= q );
02196         }
02197     }
02198     // Flush the remaining string. This will be the entire
02199     // string if an entity wasn't found.
02200     TIXMLASSERT( p <= q );
02201     if ( !_processEntities || ( p < q ) ) {
02202         Print( "%s", p );
02203     }
02204 }
02205 
02206 
02207 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
02208 {
02209     if ( writeBOM ) {
02210         static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
02211         Print( "%s", bom );
02212     }
02213     if ( writeDec ) {
02214         PushDeclaration( "xml version=\"1.0\"" );
02215     }
02216 }
02217 
02218 
02219 void XMLPrinter::OpenElement( const char* name, bool compactMode )
02220 {
02221     SealElementIfJustOpened();
02222     _stack.Push( name );
02223 
02224     if ( _textDepth < 0 && !_firstElement && !compactMode ) {
02225         Print( "\n" );
02226     }
02227     if ( !compactMode ) {
02228         PrintSpace( _depth );
02229     }
02230 
02231     Print( "<%s", name );
02232     _elementJustOpened = true;
02233     _firstElement = false;
02234     ++_depth;
02235 }
02236 
02237 
02238 void XMLPrinter::PushAttribute( const char* name, const char* value )
02239 {
02240     TIXMLASSERT( _elementJustOpened );
02241     Print( " %s=\"", name );
02242     PrintString( value, false );
02243     Print( "\"" );
02244 }
02245 
02246 
02247 void XMLPrinter::PushAttribute( const char* name, int v )
02248 {
02249     char buf[BUF_SIZE];
02250     XMLUtil::ToStr( v, buf, BUF_SIZE );
02251     PushAttribute( name, buf );
02252 }
02253 
02254 
02255 void XMLPrinter::PushAttribute( const char* name, unsigned v )
02256 {
02257     char buf[BUF_SIZE];
02258     XMLUtil::ToStr( v, buf, BUF_SIZE );
02259     PushAttribute( name, buf );
02260 }
02261 
02262 
02263 void XMLPrinter::PushAttribute( const char* name, bool v )
02264 {
02265     char buf[BUF_SIZE];
02266     XMLUtil::ToStr( v, buf, BUF_SIZE );
02267     PushAttribute( name, buf );
02268 }
02269 
02270 
02271 void XMLPrinter::PushAttribute( const char* name, double v )
02272 {
02273     char buf[BUF_SIZE];
02274     XMLUtil::ToStr( v, buf, BUF_SIZE );
02275     PushAttribute( name, buf );
02276 }
02277 
02278 
02279 void XMLPrinter::CloseElement( bool compactMode )
02280 {
02281     --_depth;
02282     const char* name = _stack.Pop();
02283 
02284     if ( _elementJustOpened ) {
02285         Print( "/>" );
02286     }
02287     else {
02288         if ( _textDepth < 0 && !compactMode) {
02289             Print( "\n" );
02290             PrintSpace( _depth );
02291         }
02292         Print( "</%s>", name );
02293     }
02294 
02295     if ( _textDepth == _depth ) {
02296         _textDepth = -1;
02297     }
02298     if ( _depth == 0 && !compactMode) {
02299         Print( "\n" );
02300     }
02301     _elementJustOpened = false;
02302 }
02303 
02304 
02305 void XMLPrinter::SealElementIfJustOpened()
02306 {
02307     if ( !_elementJustOpened ) {
02308         return;
02309     }
02310     _elementJustOpened = false;
02311     Print( ">" );
02312 }
02313 
02314 
02315 void XMLPrinter::PushText( const char* text, bool cdata )
02316 {
02317     _textDepth = _depth-1;
02318 
02319     SealElementIfJustOpened();
02320     if ( cdata ) {
02321         Print( "<![CDATA[%s]]>", text );
02322     }
02323     else {
02324         PrintString( text, true );
02325     }
02326 }
02327 
02328 void XMLPrinter::PushText( int value )
02329 {
02330     char buf[BUF_SIZE];
02331     XMLUtil::ToStr( value, buf, BUF_SIZE );
02332     PushText( buf, false );
02333 }
02334 
02335 
02336 void XMLPrinter::PushText( unsigned value )
02337 {
02338     char buf[BUF_SIZE];
02339     XMLUtil::ToStr( value, buf, BUF_SIZE );
02340     PushText( buf, false );
02341 }
02342 
02343 
02344 void XMLPrinter::PushText( bool value )
02345 {
02346     char buf[BUF_SIZE];
02347     XMLUtil::ToStr( value, buf, BUF_SIZE );
02348     PushText( buf, false );
02349 }
02350 
02351 
02352 void XMLPrinter::PushText( float value )
02353 {
02354     char buf[BUF_SIZE];
02355     XMLUtil::ToStr( value, buf, BUF_SIZE );
02356     PushText( buf, false );
02357 }
02358 
02359 
02360 void XMLPrinter::PushText( double value )
02361 {
02362     char buf[BUF_SIZE];
02363     XMLUtil::ToStr( value, buf, BUF_SIZE );
02364     PushText( buf, false );
02365 }
02366 
02367 
02368 void XMLPrinter::PushComment( const char* comment )
02369 {
02370     SealElementIfJustOpened();
02371     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02372         Print( "\n" );
02373         PrintSpace( _depth );
02374     }
02375     _firstElement = false;
02376     Print( "<!--%s-->", comment );
02377 }
02378 
02379 
02380 void XMLPrinter::PushDeclaration( const char* value )
02381 {
02382     SealElementIfJustOpened();
02383     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02384         Print( "\n" );
02385         PrintSpace( _depth );
02386     }
02387     _firstElement = false;
02388     Print( "<?%s?>", value );
02389 }
02390 
02391 
02392 void XMLPrinter::PushUnknown( const char* value )
02393 {
02394     SealElementIfJustOpened();
02395     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02396         Print( "\n" );
02397         PrintSpace( _depth );
02398     }
02399     _firstElement = false;
02400     Print( "<!%s>", value );
02401 }
02402 
02403 
02404 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
02405 {
02406     _processEntities = doc.ProcessEntities();
02407     if ( doc.HasBOM() ) {
02408         PushHeader( true, false );
02409     }
02410     return true;
02411 }
02412 
02413 
02414 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
02415 {
02416     const XMLElement* parentElem = 0;
02417     if ( element.Parent() ) {
02418         parentElem = element.Parent()->ToElement();
02419     }
02420     const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
02421     OpenElement( element.Name(), compactMode );
02422     while ( attribute ) {
02423         PushAttribute( attribute->Name(), attribute->Value() );
02424         attribute = attribute->Next();
02425     }
02426     return true;
02427 }
02428 
02429 
02430 bool XMLPrinter::VisitExit( const XMLElement& element )
02431 {
02432     CloseElement( CompactMode(element) );
02433     return true;
02434 }
02435 
02436 
02437 bool XMLPrinter::Visit( const XMLText& text )
02438 {
02439     PushText( text.Value(), text.CData() );
02440     return true;
02441 }
02442 
02443 
02444 bool XMLPrinter::Visit( const XMLComment& comment )
02445 {
02446     PushComment( comment.Value() );
02447     return true;
02448 }
02449 
02450 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
02451 {
02452     PushDeclaration( declaration.Value() );
02453     return true;
02454 }
02455 
02456 
02457 bool XMLPrinter::Visit( const XMLUnknown& unknown )
02458 {
02459     PushUnknown( unknown.Value() );
02460     return true;
02461 }
02462 
02463 }   // namespace tinyxml2
02464 


denso_robot_core
Author(s): DENSO WAVE INCORPORATED
autogenerated on Thu Jun 6 2019 21:00:11