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