00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "tinyxml2.h"
00025
00026 #include <new>
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
00037
00038
00039
00040
00041
00042
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
00063 #define TIXML_SNPRINTF _snprintf
00064 #define TIXML_VSNPRINTF _vsnprintf
00065 #define TIXML_SSCANF sscanf
00066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
00067
00068 #define TIXML_VSCPRINTF _vscprintf // VS2003's C runtime has this, but VC6 C runtime or WinCE SDK doesn't have.
00069 #else
00070
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
00091
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;
00105 static const char LF = LINE_FEED;
00106 static const char CARRIAGE_RETURN = (char)0x0d;
00107 static const char CR = CARRIAGE_RETURN;
00108 static const char SINGLE_QUOTE = '\'';
00109 static const char DOUBLE_QUOTE = '\"';
00110
00111
00112
00113
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
00150
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
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
00241 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
00242
00243 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
00244
00245 if ( *_start ) {
00246 const char* p = _start;
00247 char* q = _start;
00248
00249 while( *p ) {
00250 if ( XMLUtil::IsWhiteSpace( *p )) {
00251 p = XMLUtil::SkipWhiteSpace( p, 0 );
00252 if ( *p == 0 ) {
00253 break;
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;
00277 char* q = _start;
00278
00279 while( p < _end ) {
00280 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
00281
00282
00283
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
00305
00306
00307
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
00334 *q = entity.value;
00335 ++q;
00336 p += entity.length + 2;
00337 entityFound = true;
00338 break;
00339 }
00340 }
00341 if ( !entityFound ) {
00342
00343 ++p;
00344 ++q;
00345 }
00346 }
00347 }
00348 else {
00349 *q = *p;
00350 ++p;
00351 ++q;
00352 }
00353 }
00354 *q = 0;
00355 }
00356
00357
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
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
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;
00423 return;
00424 }
00425
00426 output += *length;
00427
00428
00429
00430 switch (*length) {
00431 case 4:
00432 --output;
00433 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00434 input >>= 6;
00435
00436 case 3:
00437 --output;
00438 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00439 input >>= 6;
00440
00441 case 2:
00442 --output;
00443 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00444 input >>= 6;
00445
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
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
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
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
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
00571
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
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;
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
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 = { "<" };
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 ) );
00683 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );
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;
00715 p = start;
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
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
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
00918
00919
00920
00921 return addThis;
00922 }
00923
00924 if ( afterThis->_next == 0 ) {
00925
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
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
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
01035 bool wellLocated = ( ToDocument() != 0 );
01036 if ( wellLocated ) {
01037
01038
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
01056 if ( ele->ClosingType() == XMLElement::CLOSING ) {
01057 if ( parentEndTag ) {
01058 ele->_value.TransferTo( parentEndTag );
01059 }
01060 node->_memPool->SetTracked();
01061 DeleteNode( node );
01062 return p;
01063 }
01064
01065
01066
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 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
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() );
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
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
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() );
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
01239
01240 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
01241 {
01242 }
01243
01244
01245 XMLDeclaration::~XMLDeclaration()
01246 {
01247
01248 }
01249
01250
01251 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
01252 {
01253
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() );
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
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
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() );
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
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
01349 p = _name.ParseName( p );
01350 if ( !p || !*p ) {
01351 return 0;
01352 }
01353
01354
01355 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01356 if ( *p != '=' ) {
01357 return 0;
01358 }
01359
01360 ++p;
01361 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01362 if ( *p != '\"' && *p != '\'' ) {
01363 return 0;
01364 }
01365
01366 char endTag[2] = { *p, 0 };
01367 ++p;
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
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
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
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
01832
01833
01834
01835
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
01847 else if ( *p == '>' ) {
01848 ++p;
01849 break;
01850 }
01851
01852 else if ( *p == '/' && *(p+1) == '>' ) {
01853 _closingType = CLOSED;
01854 return p+2;
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
01886
01887
01888 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
01889 {
01890
01891 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
01892
01893
01894
01895
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() );
01923 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
01924 element->SetAttribute( a->Name(), a->Value() );
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
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
01971
01972
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
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]);
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;
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
02149
02150
02151
02152 node->_memPool->SetTracked();
02153
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
02179
02180
02181
02182
02183
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
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
02269
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
02296
02297
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 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() );
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;
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
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;
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;
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;
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
02488 const char* q = p;
02489
02490 if ( _processEntities ) {
02491 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
02492 while ( *q ) {
02493 TIXMLASSERT( p <= q );
02494
02495 if ( *q > 0 && *q < ENTITY_RANGE ) {
02496
02497
02498
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
02518 TIXMLASSERT( false );
02519 }
02520 ++p;
02521 }
02522 }
02523 ++q;
02524 TIXMLASSERT( p <= q );
02525 }
02526 }
02527
02528
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 }