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