File indexing completed on 2025-07-12 08:56:51
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024 #include "tinyxml2.h"
0025
0026 #include <new> // yes, this one new style header, is in the Android SDK.
0027 #if defined(ANDROID_NDK) || defined(__BORLANDC__) || defined(__QNXNTO__)
0028 # include <stddef.h>
0029 # include <stdarg.h>
0030 #else
0031 # include <cstddef>
0032 # include <cstdarg>
0033 #endif
0034
0035 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
0036
0037
0038
0039
0040
0041
0042
0043
0044 static inline int TIXML_SNPRINTF( char* buffer, size_t size, const char* format, ... )
0045 {
0046 va_list va;
0047 va_start( va, format );
0048 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
0049 va_end( va );
0050 return result;
0051 }
0052
0053 static inline int TIXML_VSNPRINTF( char* buffer, size_t size, const char* format, va_list va )
0054 {
0055 const int result = vsnprintf_s( buffer, size, _TRUNCATE, format, va );
0056 return result;
0057 }
0058
0059 #define TIXML_VSCPRINTF _vscprintf
0060 #define TIXML_SSCANF sscanf_s
0061 #elif defined _MSC_VER
0062
0063 #define TIXML_SNPRINTF _snprintf
0064 #define TIXML_VSNPRINTF _vsnprintf
0065 #define TIXML_SSCANF sscanf
0066 #if (_MSC_VER < 1400 ) && (!defined WINCE)
0067
0068 #define TIXML_VSCPRINTF _vscprintf
0069 #else
0070
0071 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
0072 {
0073 int len = 512;
0074 for (;;) {
0075 len = len*2;
0076 char* str = new char[len]();
0077 const int required = _vsnprintf(str, len, format, va);
0078 delete[] str;
0079 if ( required != -1 ) {
0080 TIXMLASSERT( required >= 0 );
0081 len = required;
0082 break;
0083 }
0084 }
0085 TIXMLASSERT( len >= 0 );
0086 return len;
0087 }
0088 #endif
0089 #else
0090
0091
0092 #define TIXML_SNPRINTF snprintf
0093 #define TIXML_VSNPRINTF vsnprintf
0094 static inline int TIXML_VSCPRINTF( const char* format, va_list va )
0095 {
0096 int len = vsnprintf( 0, 0, format, va );
0097 TIXMLASSERT( len >= 0 );
0098 return len;
0099 }
0100 #define TIXML_SSCANF sscanf
0101 #endif
0102
0103 #if defined(_WIN64)
0104 #define TIXML_FSEEK _fseeki64
0105 #define TIXML_FTELL _ftelli64
0106 #elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) || defined(__DragonFly__) || (__CYGWIN__)
0107 #define TIXML_FSEEK fseeko
0108 #define TIXML_FTELL ftello
0109 #elif defined(__ANDROID__)
0110 #if __ANDROID_API__ > 24
0111 #define TIXML_FSEEK fseeko64
0112 #define TIXML_FTELL ftello64
0113 #else
0114 #define TIXML_FSEEK fseeko
0115 #define TIXML_FTELL ftello
0116 #endif
0117 #elif defined(__unix__) && defined(__x86_64__)
0118 #define TIXML_FSEEK fseeko64
0119 #define TIXML_FTELL ftello64
0120 #else
0121 #define TIXML_FSEEK fseek
0122 #define TIXML_FTELL ftell
0123 #endif
0124
0125
0126 static const char LINE_FEED = static_cast<char>(0x0a);
0127 static const char LF = LINE_FEED;
0128 static const char CARRIAGE_RETURN = static_cast<char>(0x0d);
0129 static const char CR = CARRIAGE_RETURN;
0130 static const char SINGLE_QUOTE = '\'';
0131 static const char DOUBLE_QUOTE = '\"';
0132
0133
0134
0135
0136
0137 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
0138 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
0139 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
0140
0141 namespace tinyxml2
0142 {
0143
0144 struct Entity {
0145 const char* pattern;
0146 int length;
0147 char value;
0148 };
0149
0150 static const int NUM_ENTITIES = 5;
0151 static const Entity entities[NUM_ENTITIES] = {
0152 { "quot", 4, DOUBLE_QUOTE },
0153 { "amp", 3, '&' },
0154 { "apos", 4, SINGLE_QUOTE },
0155 { "lt", 2, '<' },
0156 { "gt", 2, '>' }
0157 };
0158
0159
0160 StrPair::~StrPair()
0161 {
0162 Reset();
0163 }
0164
0165
0166 void StrPair::TransferTo( StrPair* other )
0167 {
0168 if ( this == other ) {
0169 return;
0170 }
0171
0172
0173
0174 TIXMLASSERT( other != 0 );
0175 TIXMLASSERT( other->_flags == 0 );
0176 TIXMLASSERT( other->_start == 0 );
0177 TIXMLASSERT( other->_end == 0 );
0178
0179 other->Reset();
0180
0181 other->_flags = _flags;
0182 other->_start = _start;
0183 other->_end = _end;
0184
0185 _flags = 0;
0186 _start = 0;
0187 _end = 0;
0188 }
0189
0190
0191 void StrPair::Reset()
0192 {
0193 if ( _flags & NEEDS_DELETE ) {
0194 delete [] _start;
0195 }
0196 _flags = 0;
0197 _start = 0;
0198 _end = 0;
0199 }
0200
0201
0202 void StrPair::SetStr( const char* str, int flags )
0203 {
0204 TIXMLASSERT( str );
0205 Reset();
0206 size_t len = strlen( str );
0207 TIXMLASSERT( _start == 0 );
0208 _start = new char[ len+1 ];
0209 memcpy( _start, str, len+1 );
0210 _end = _start + len;
0211 _flags = flags | NEEDS_DELETE;
0212 }
0213
0214
0215 char* StrPair::ParseText( char* p, const char* endTag, int strFlags, int* curLineNumPtr )
0216 {
0217 TIXMLASSERT( p );
0218 TIXMLASSERT( endTag && *endTag );
0219 TIXMLASSERT(curLineNumPtr);
0220
0221 char* start = p;
0222 const char endChar = *endTag;
0223 size_t length = strlen( endTag );
0224
0225
0226 while ( *p ) {
0227 if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
0228 Set( start, p, strFlags );
0229 return p + length;
0230 } else if (*p == '\n') {
0231 ++(*curLineNumPtr);
0232 }
0233 ++p;
0234 TIXMLASSERT( p );
0235 }
0236 return 0;
0237 }
0238
0239
0240 char* StrPair::ParseName( char* p )
0241 {
0242 if ( !p || !(*p) ) {
0243 return 0;
0244 }
0245 if ( !XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
0246 return 0;
0247 }
0248
0249 char* const start = p;
0250 ++p;
0251 while ( *p && XMLUtil::IsNameChar( (unsigned char) *p ) ) {
0252 ++p;
0253 }
0254
0255 Set( start, p, 0 );
0256 return p;
0257 }
0258
0259
0260 void StrPair::CollapseWhitespace()
0261 {
0262
0263 TIXMLASSERT( ( _flags & NEEDS_DELETE ) == 0 );
0264
0265 _start = XMLUtil::SkipWhiteSpace( _start, 0 );
0266
0267 if ( *_start ) {
0268 const char* p = _start;
0269 char* q = _start;
0270
0271 while( *p ) {
0272 if ( XMLUtil::IsWhiteSpace( *p )) {
0273 p = XMLUtil::SkipWhiteSpace( p, 0 );
0274 if ( *p == 0 ) {
0275 break;
0276 }
0277 *q = ' ';
0278 ++q;
0279 }
0280 *q = *p;
0281 ++q;
0282 ++p;
0283 }
0284 *q = 0;
0285 }
0286 }
0287
0288
0289 const char* StrPair::GetStr()
0290 {
0291 TIXMLASSERT( _start );
0292 TIXMLASSERT( _end );
0293 if ( _flags & NEEDS_FLUSH ) {
0294 *_end = 0;
0295 _flags ^= NEEDS_FLUSH;
0296
0297 if ( _flags ) {
0298 const char* p = _start;
0299 char* q = _start;
0300
0301 while( p < _end ) {
0302 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
0303
0304
0305
0306 if ( *(p+1) == LF ) {
0307 p += 2;
0308 }
0309 else {
0310 ++p;
0311 }
0312 *q = LF;
0313 ++q;
0314 }
0315 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
0316 if ( *(p+1) == CR ) {
0317 p += 2;
0318 }
0319 else {
0320 ++p;
0321 }
0322 *q = LF;
0323 ++q;
0324 }
0325 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
0326
0327
0328
0329
0330
0331 if ( *(p+1) == '#' ) {
0332 const int buflen = 10;
0333 char buf[buflen] = { 0 };
0334 int len = 0;
0335 const char* adjusted = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
0336 if ( adjusted == 0 ) {
0337 *q = *p;
0338 ++p;
0339 ++q;
0340 }
0341 else {
0342 TIXMLASSERT( 0 <= len && len <= buflen );
0343 TIXMLASSERT( q + len <= adjusted );
0344 p = adjusted;
0345 memcpy( q, buf, len );
0346 q += len;
0347 }
0348 }
0349 else {
0350 bool entityFound = false;
0351 for( int i = 0; i < NUM_ENTITIES; ++i ) {
0352 const Entity& entity = entities[i];
0353 if ( strncmp( p + 1, entity.pattern, entity.length ) == 0
0354 && *( p + entity.length + 1 ) == ';' ) {
0355
0356 *q = entity.value;
0357 ++q;
0358 p += entity.length + 2;
0359 entityFound = true;
0360 break;
0361 }
0362 }
0363 if ( !entityFound ) {
0364
0365 ++p;
0366 ++q;
0367 }
0368 }
0369 }
0370 else {
0371 *q = *p;
0372 ++p;
0373 ++q;
0374 }
0375 }
0376 *q = 0;
0377 }
0378
0379
0380 if ( _flags & NEEDS_WHITESPACE_COLLAPSING ) {
0381 CollapseWhitespace();
0382 }
0383 _flags = (_flags & NEEDS_DELETE);
0384 }
0385 TIXMLASSERT( _start );
0386 return _start;
0387 }
0388
0389
0390
0391
0392
0393
0394 const char* XMLUtil::writeBoolTrue = "true";
0395 const char* XMLUtil::writeBoolFalse = "false";
0396
0397 void XMLUtil::SetBoolSerialization(const char* writeTrue, const char* writeFalse)
0398 {
0399 static const char* defTrue = "true";
0400 static const char* defFalse = "false";
0401
0402 writeBoolTrue = (writeTrue) ? writeTrue : defTrue;
0403 writeBoolFalse = (writeFalse) ? writeFalse : defFalse;
0404 }
0405
0406
0407 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
0408 {
0409 TIXMLASSERT( p );
0410 TIXMLASSERT( bom );
0411 *bom = false;
0412 const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
0413
0414 if ( *(pu+0) == TIXML_UTF_LEAD_0
0415 && *(pu+1) == TIXML_UTF_LEAD_1
0416 && *(pu+2) == TIXML_UTF_LEAD_2 ) {
0417 *bom = true;
0418 p += 3;
0419 }
0420 TIXMLASSERT( p );
0421 return p;
0422 }
0423
0424
0425 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
0426 {
0427 const unsigned long BYTE_MASK = 0xBF;
0428 const unsigned long BYTE_MARK = 0x80;
0429 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
0430
0431 if (input < 0x80) {
0432 *length = 1;
0433 }
0434 else if ( input < 0x800 ) {
0435 *length = 2;
0436 }
0437 else if ( input < 0x10000 ) {
0438 *length = 3;
0439 }
0440 else if ( input < 0x200000 ) {
0441 *length = 4;
0442 }
0443 else {
0444 *length = 0;
0445 return;
0446 }
0447
0448 output += *length;
0449
0450
0451
0452 switch (*length) {
0453 case 4:
0454 --output;
0455 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
0456 input >>= 6;
0457
0458 case 3:
0459 --output;
0460 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
0461 input >>= 6;
0462
0463 case 2:
0464 --output;
0465 *output = static_cast<char>((input | BYTE_MARK) & BYTE_MASK);
0466 input >>= 6;
0467
0468 case 1:
0469 --output;
0470 *output = static_cast<char>(input | FIRST_BYTE_MARK[*length]);
0471 break;
0472 default:
0473 TIXMLASSERT( false );
0474 }
0475 }
0476
0477
0478 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
0479 {
0480
0481 *length = 0;
0482
0483 if ( *(p+1) == '#' && *(p+2) ) {
0484 unsigned long ucs = 0;
0485 TIXMLASSERT( sizeof( ucs ) >= 4 );
0486 ptrdiff_t delta = 0;
0487 unsigned mult = 1;
0488 static const char SEMICOLON = ';';
0489
0490 if ( *(p+2) == 'x' ) {
0491
0492 const char* q = p+3;
0493 if ( !(*q) ) {
0494 return 0;
0495 }
0496
0497 q = strchr( q, SEMICOLON );
0498
0499 if ( !q ) {
0500 return 0;
0501 }
0502 TIXMLASSERT( *q == SEMICOLON );
0503
0504 delta = q-p;
0505 --q;
0506
0507 while ( *q != 'x' ) {
0508 unsigned int digit = 0;
0509
0510 if ( *q >= '0' && *q <= '9' ) {
0511 digit = *q - '0';
0512 }
0513 else if ( *q >= 'a' && *q <= 'f' ) {
0514 digit = *q - 'a' + 10;
0515 }
0516 else if ( *q >= 'A' && *q <= 'F' ) {
0517 digit = *q - 'A' + 10;
0518 }
0519 else {
0520 return 0;
0521 }
0522 TIXMLASSERT( digit < 16 );
0523 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
0524 const unsigned int digitScaled = mult * digit;
0525 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
0526 ucs += digitScaled;
0527 TIXMLASSERT( mult <= UINT_MAX / 16 );
0528 mult *= 16;
0529 --q;
0530 }
0531 }
0532 else {
0533
0534 const char* q = p+2;
0535 if ( !(*q) ) {
0536 return 0;
0537 }
0538
0539 q = strchr( q, SEMICOLON );
0540
0541 if ( !q ) {
0542 return 0;
0543 }
0544 TIXMLASSERT( *q == SEMICOLON );
0545
0546 delta = q-p;
0547 --q;
0548
0549 while ( *q != '#' ) {
0550 if ( *q >= '0' && *q <= '9' ) {
0551 const unsigned int digit = *q - '0';
0552 TIXMLASSERT( digit < 10 );
0553 TIXMLASSERT( digit == 0 || mult <= UINT_MAX / digit );
0554 const unsigned int digitScaled = mult * digit;
0555 TIXMLASSERT( ucs <= ULONG_MAX - digitScaled );
0556 ucs += digitScaled;
0557 }
0558 else {
0559 return 0;
0560 }
0561 TIXMLASSERT( mult <= UINT_MAX / 10 );
0562 mult *= 10;
0563 --q;
0564 }
0565 }
0566
0567 ConvertUTF32ToUTF8( ucs, value, length );
0568 return p + delta + 1;
0569 }
0570 return p+1;
0571 }
0572
0573
0574 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
0575 {
0576 TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
0577 }
0578
0579
0580 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
0581 {
0582 TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
0583 }
0584
0585
0586 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
0587 {
0588 TIXML_SNPRINTF( buffer, bufferSize, "%s", v ? writeBoolTrue : writeBoolFalse);
0589 }
0590
0591
0592
0593
0594
0595 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
0596 {
0597 TIXML_SNPRINTF( buffer, bufferSize, "%.8g", v );
0598 }
0599
0600
0601 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
0602 {
0603 TIXML_SNPRINTF( buffer, bufferSize, "%.17g", v );
0604 }
0605
0606
0607 void XMLUtil::ToStr( int64_t v, char* buffer, int bufferSize )
0608 {
0609
0610 TIXML_SNPRINTF(buffer, bufferSize, "%lld", static_cast<long long>(v));
0611 }
0612
0613 void XMLUtil::ToStr( uint64_t v, char* buffer, int bufferSize )
0614 {
0615
0616 TIXML_SNPRINTF(buffer, bufferSize, "%llu", (long long)v);
0617 }
0618
0619 bool XMLUtil::ToInt(const char* str, int* value)
0620 {
0621 if (IsPrefixHex(str)) {
0622 unsigned v;
0623 if (TIXML_SSCANF(str, "%x", &v) == 1) {
0624 *value = static_cast<int>(v);
0625 return true;
0626 }
0627 }
0628 else {
0629 if (TIXML_SSCANF(str, "%d", value) == 1) {
0630 return true;
0631 }
0632 }
0633 return false;
0634 }
0635
0636 bool XMLUtil::ToUnsigned(const char* str, unsigned* value)
0637 {
0638 if (TIXML_SSCANF(str, IsPrefixHex(str) ? "%x" : "%u", value) == 1) {
0639 return true;
0640 }
0641 return false;
0642 }
0643
0644 bool XMLUtil::ToBool( const char* str, bool* value )
0645 {
0646 int ival = 0;
0647 if ( ToInt( str, &ival )) {
0648 *value = (ival==0) ? false : true;
0649 return true;
0650 }
0651 static const char* TRUE_VALS[] = { "true", "True", "TRUE", 0 };
0652 static const char* FALSE_VALS[] = { "false", "False", "FALSE", 0 };
0653
0654 for (int i = 0; TRUE_VALS[i]; ++i) {
0655 if (StringEqual(str, TRUE_VALS[i])) {
0656 *value = true;
0657 return true;
0658 }
0659 }
0660 for (int i = 0; FALSE_VALS[i]; ++i) {
0661 if (StringEqual(str, FALSE_VALS[i])) {
0662 *value = false;
0663 return true;
0664 }
0665 }
0666 return false;
0667 }
0668
0669
0670 bool XMLUtil::ToFloat( const char* str, float* value )
0671 {
0672 if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
0673 return true;
0674 }
0675 return false;
0676 }
0677
0678
0679 bool XMLUtil::ToDouble( const char* str, double* value )
0680 {
0681 if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
0682 return true;
0683 }
0684 return false;
0685 }
0686
0687
0688 bool XMLUtil::ToInt64(const char* str, int64_t* value)
0689 {
0690 if (IsPrefixHex(str)) {
0691 unsigned long long v = 0;
0692 if (TIXML_SSCANF(str, "%llx", &v) == 1) {
0693 *value = static_cast<int64_t>(v);
0694 return true;
0695 }
0696 }
0697 else {
0698 long long v = 0;
0699 if (TIXML_SSCANF(str, "%lld", &v) == 1) {
0700 *value = static_cast<int64_t>(v);
0701 return true;
0702 }
0703 }
0704 return false;
0705 }
0706
0707
0708 bool XMLUtil::ToUnsigned64(const char* str, uint64_t* value) {
0709 unsigned long long v = 0;
0710 if(TIXML_SSCANF(str, IsPrefixHex(str) ? "%llx" : "%llu", &v) == 1) {
0711 *value = (uint64_t)v;
0712 return true;
0713 }
0714 return false;
0715 }
0716
0717
0718 char* XMLDocument::Identify( char* p, XMLNode** node )
0719 {
0720 TIXMLASSERT( node );
0721 TIXMLASSERT( p );
0722 char* const start = p;
0723 int const startLine = _parseCurLineNum;
0724 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
0725 if( !*p ) {
0726 *node = 0;
0727 TIXMLASSERT( p );
0728 return p;
0729 }
0730
0731
0732 static const char* xmlHeader = { "<?" };
0733 static const char* commentHeader = { "<!--" };
0734 static const char* cdataHeader = { "<![CDATA[" };
0735 static const char* dtdHeader = { "<!" };
0736 static const char* elementHeader = { "<" };
0737
0738 static const int xmlHeaderLen = 2;
0739 static const int commentHeaderLen = 4;
0740 static const int cdataHeaderLen = 9;
0741 static const int dtdHeaderLen = 2;
0742 static const int elementHeaderLen = 1;
0743
0744 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );
0745 TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );
0746 XMLNode* returnNode = 0;
0747 if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
0748 returnNode = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
0749 returnNode->_parseLineNum = _parseCurLineNum;
0750 p += xmlHeaderLen;
0751 }
0752 else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
0753 returnNode = CreateUnlinkedNode<XMLComment>( _commentPool );
0754 returnNode->_parseLineNum = _parseCurLineNum;
0755 p += commentHeaderLen;
0756 }
0757 else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
0758 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
0759 returnNode = text;
0760 returnNode->_parseLineNum = _parseCurLineNum;
0761 p += cdataHeaderLen;
0762 text->SetCData( true );
0763 }
0764 else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
0765 returnNode = CreateUnlinkedNode<XMLUnknown>( _commentPool );
0766 returnNode->_parseLineNum = _parseCurLineNum;
0767 p += dtdHeaderLen;
0768 }
0769 else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
0770 returnNode = CreateUnlinkedNode<XMLElement>( _elementPool );
0771 returnNode->_parseLineNum = _parseCurLineNum;
0772 p += elementHeaderLen;
0773 }
0774 else {
0775 returnNode = CreateUnlinkedNode<XMLText>( _textPool );
0776 returnNode->_parseLineNum = _parseCurLineNum;
0777 p = start;
0778 _parseCurLineNum = startLine;
0779 }
0780
0781 TIXMLASSERT( returnNode );
0782 TIXMLASSERT( p );
0783 *node = returnNode;
0784 return p;
0785 }
0786
0787
0788 bool XMLDocument::Accept( XMLVisitor* visitor ) const
0789 {
0790 TIXMLASSERT( visitor );
0791 if ( visitor->VisitEnter( *this ) ) {
0792 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
0793 if ( !node->Accept( visitor ) ) {
0794 break;
0795 }
0796 }
0797 }
0798 return visitor->VisitExit( *this );
0799 }
0800
0801
0802
0803
0804 XMLNode::XMLNode( XMLDocument* doc ) :
0805 _document( doc ),
0806 _parent( 0 ),
0807 _value(),
0808 _parseLineNum( 0 ),
0809 _firstChild( 0 ), _lastChild( 0 ),
0810 _prev( 0 ), _next( 0 ),
0811 _userData( 0 ),
0812 _memPool( 0 )
0813 {
0814 }
0815
0816
0817 XMLNode::~XMLNode()
0818 {
0819 DeleteChildren();
0820 if ( _parent ) {
0821 _parent->Unlink( this );
0822 }
0823 }
0824
0825 const char* XMLNode::Value() const
0826 {
0827
0828 if ( this->ToDocument() )
0829 return 0;
0830 return _value.GetStr();
0831 }
0832
0833 void XMLNode::SetValue( const char* str, bool staticMem )
0834 {
0835 if ( staticMem ) {
0836 _value.SetInternedStr( str );
0837 }
0838 else {
0839 _value.SetStr( str );
0840 }
0841 }
0842
0843 XMLNode* XMLNode::DeepClone(XMLDocument* target) const
0844 {
0845 XMLNode* clone = this->ShallowClone(target);
0846 if (!clone) return 0;
0847
0848 for (const XMLNode* child = this->FirstChild(); child; child = child->NextSibling()) {
0849 XMLNode* childClone = child->DeepClone(target);
0850 TIXMLASSERT(childClone);
0851 clone->InsertEndChild(childClone);
0852 }
0853 return clone;
0854 }
0855
0856 void XMLNode::DeleteChildren()
0857 {
0858 while( _firstChild ) {
0859 TIXMLASSERT( _lastChild );
0860 DeleteChild( _firstChild );
0861 }
0862 _firstChild = _lastChild = 0;
0863 }
0864
0865
0866 void XMLNode::Unlink( XMLNode* child )
0867 {
0868 TIXMLASSERT( child );
0869 TIXMLASSERT( child->_document == _document );
0870 TIXMLASSERT( child->_parent == this );
0871 if ( child == _firstChild ) {
0872 _firstChild = _firstChild->_next;
0873 }
0874 if ( child == _lastChild ) {
0875 _lastChild = _lastChild->_prev;
0876 }
0877
0878 if ( child->_prev ) {
0879 child->_prev->_next = child->_next;
0880 }
0881 if ( child->_next ) {
0882 child->_next->_prev = child->_prev;
0883 }
0884 child->_next = 0;
0885 child->_prev = 0;
0886 child->_parent = 0;
0887 }
0888
0889
0890 void XMLNode::DeleteChild( XMLNode* node )
0891 {
0892 TIXMLASSERT( node );
0893 TIXMLASSERT( node->_document == _document );
0894 TIXMLASSERT( node->_parent == this );
0895 Unlink( node );
0896 TIXMLASSERT(node->_prev == 0);
0897 TIXMLASSERT(node->_next == 0);
0898 TIXMLASSERT(node->_parent == 0);
0899 DeleteNode( node );
0900 }
0901
0902
0903 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
0904 {
0905 TIXMLASSERT( addThis );
0906 if ( addThis->_document != _document ) {
0907 TIXMLASSERT( false );
0908 return 0;
0909 }
0910 InsertChildPreamble( addThis );
0911
0912 if ( _lastChild ) {
0913 TIXMLASSERT( _firstChild );
0914 TIXMLASSERT( _lastChild->_next == 0 );
0915 _lastChild->_next = addThis;
0916 addThis->_prev = _lastChild;
0917 _lastChild = addThis;
0918
0919 addThis->_next = 0;
0920 }
0921 else {
0922 TIXMLASSERT( _firstChild == 0 );
0923 _firstChild = _lastChild = addThis;
0924
0925 addThis->_prev = 0;
0926 addThis->_next = 0;
0927 }
0928 addThis->_parent = this;
0929 return addThis;
0930 }
0931
0932
0933 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
0934 {
0935 TIXMLASSERT( addThis );
0936 if ( addThis->_document != _document ) {
0937 TIXMLASSERT( false );
0938 return 0;
0939 }
0940 InsertChildPreamble( addThis );
0941
0942 if ( _firstChild ) {
0943 TIXMLASSERT( _lastChild );
0944 TIXMLASSERT( _firstChild->_prev == 0 );
0945
0946 _firstChild->_prev = addThis;
0947 addThis->_next = _firstChild;
0948 _firstChild = addThis;
0949
0950 addThis->_prev = 0;
0951 }
0952 else {
0953 TIXMLASSERT( _lastChild == 0 );
0954 _firstChild = _lastChild = addThis;
0955
0956 addThis->_prev = 0;
0957 addThis->_next = 0;
0958 }
0959 addThis->_parent = this;
0960 return addThis;
0961 }
0962
0963
0964 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
0965 {
0966 TIXMLASSERT( addThis );
0967 if ( addThis->_document != _document ) {
0968 TIXMLASSERT( false );
0969 return 0;
0970 }
0971
0972 TIXMLASSERT( afterThis );
0973
0974 if ( afterThis->_parent != this ) {
0975 TIXMLASSERT( false );
0976 return 0;
0977 }
0978 if ( afterThis == addThis ) {
0979
0980
0981
0982
0983 return addThis;
0984 }
0985
0986 if ( afterThis->_next == 0 ) {
0987
0988 return InsertEndChild( addThis );
0989 }
0990 InsertChildPreamble( addThis );
0991 addThis->_prev = afterThis;
0992 addThis->_next = afterThis->_next;
0993 afterThis->_next->_prev = addThis;
0994 afterThis->_next = addThis;
0995 addThis->_parent = this;
0996 return addThis;
0997 }
0998
0999
1000
1001
1002 const XMLElement* XMLNode::FirstChildElement( const char* name ) const
1003 {
1004 for( const XMLNode* node = _firstChild; node; node = node->_next ) {
1005 const XMLElement* element = node->ToElementWithName( name );
1006 if ( element ) {
1007 return element;
1008 }
1009 }
1010 return 0;
1011 }
1012
1013
1014 const XMLElement* XMLNode::LastChildElement( const char* name ) const
1015 {
1016 for( const XMLNode* node = _lastChild; node; node = node->_prev ) {
1017 const XMLElement* element = node->ToElementWithName( name );
1018 if ( element ) {
1019 return element;
1020 }
1021 }
1022 return 0;
1023 }
1024
1025
1026 const XMLElement* XMLNode::NextSiblingElement( const char* name ) const
1027 {
1028 for( const XMLNode* node = _next; node; node = node->_next ) {
1029 const XMLElement* element = node->ToElementWithName( name );
1030 if ( element ) {
1031 return element;
1032 }
1033 }
1034 return 0;
1035 }
1036
1037
1038 const XMLElement* XMLNode::PreviousSiblingElement( const char* name ) const
1039 {
1040 for( const XMLNode* node = _prev; node; node = node->_prev ) {
1041 const XMLElement* element = node->ToElementWithName( name );
1042 if ( element ) {
1043 return element;
1044 }
1045 }
1046 return 0;
1047 }
1048
1049
1050 char* XMLNode::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
1051 {
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069 XMLDocument::DepthTracker tracker(_document);
1070 if (_document->Error())
1071 return 0;
1072
1073 while( p && *p ) {
1074 XMLNode* node = 0;
1075
1076 p = _document->Identify( p, &node );
1077 TIXMLASSERT( p );
1078 if ( node == 0 ) {
1079 break;
1080 }
1081
1082 const int initialLineNum = node->_parseLineNum;
1083
1084 StrPair endTag;
1085 p = node->ParseDeep( p, &endTag, curLineNumPtr );
1086 if ( !p ) {
1087 _document->DeleteNode( node );
1088 if ( !_document->Error() ) {
1089 _document->SetError( XML_ERROR_PARSING, initialLineNum, 0);
1090 }
1091 break;
1092 }
1093
1094 const XMLDeclaration* const decl = node->ToDeclaration();
1095 if ( decl ) {
1096
1097
1098
1099
1100
1101
1102
1103
1104 bool wellLocated = false;
1105
1106 if (ToDocument()) {
1107 if (FirstChild()) {
1108 wellLocated =
1109 FirstChild() &&
1110 FirstChild()->ToDeclaration() &&
1111 LastChild() &&
1112 LastChild()->ToDeclaration();
1113 }
1114 else {
1115 wellLocated = true;
1116 }
1117 }
1118 if ( !wellLocated ) {
1119 _document->SetError( XML_ERROR_PARSING_DECLARATION, initialLineNum, "XMLDeclaration value=%s", decl->Value());
1120 _document->DeleteNode( node );
1121 break;
1122 }
1123 }
1124
1125 XMLElement* ele = node->ToElement();
1126 if ( ele ) {
1127
1128 if ( ele->ClosingType() == XMLElement::CLOSING ) {
1129 if ( parentEndTag ) {
1130 ele->_value.TransferTo( parentEndTag );
1131 }
1132 node->_memPool->SetTracked();
1133 DeleteNode( node );
1134 return p;
1135 }
1136
1137
1138
1139 bool mismatch = false;
1140 if ( endTag.Empty() ) {
1141 if ( ele->ClosingType() == XMLElement::OPEN ) {
1142 mismatch = true;
1143 }
1144 }
1145 else {
1146 if ( ele->ClosingType() != XMLElement::OPEN ) {
1147 mismatch = true;
1148 }
1149 else if ( !XMLUtil::StringEqual( endTag.GetStr(), ele->Name() ) ) {
1150 mismatch = true;
1151 }
1152 }
1153 if ( mismatch ) {
1154 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, initialLineNum, "XMLElement name=%s", ele->Name());
1155 _document->DeleteNode( node );
1156 break;
1157 }
1158 }
1159 InsertEndChild( node );
1160 }
1161 return 0;
1162 }
1163
1164 void XMLNode::DeleteNode( XMLNode* node )
1165 {
1166 if ( node == 0 ) {
1167 return;
1168 }
1169 TIXMLASSERT(node->_document);
1170 if (!node->ToDocument()) {
1171 node->_document->MarkInUse(node);
1172 }
1173
1174 MemPool* pool = node->_memPool;
1175 node->~XMLNode();
1176 pool->Free( node );
1177 }
1178
1179 void XMLNode::InsertChildPreamble( XMLNode* insertThis ) const
1180 {
1181 TIXMLASSERT( insertThis );
1182 TIXMLASSERT( insertThis->_document == _document );
1183
1184 if (insertThis->_parent) {
1185 insertThis->_parent->Unlink( insertThis );
1186 }
1187 else {
1188 insertThis->_document->MarkInUse(insertThis);
1189 insertThis->_memPool->SetTracked();
1190 }
1191 }
1192
1193 const XMLElement* XMLNode::ToElementWithName( const char* name ) const
1194 {
1195 const XMLElement* element = this->ToElement();
1196 if ( element == 0 ) {
1197 return 0;
1198 }
1199 if ( name == 0 ) {
1200 return element;
1201 }
1202 if ( XMLUtil::StringEqual( element->Name(), name ) ) {
1203 return element;
1204 }
1205 return 0;
1206 }
1207
1208
1209 char* XMLText::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1210 {
1211 if ( this->CData() ) {
1212 p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1213 if ( !p ) {
1214 _document->SetError( XML_ERROR_PARSING_CDATA, _parseLineNum, 0 );
1215 }
1216 return p;
1217 }
1218 else {
1219 int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
1220 if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
1221 flags |= StrPair::NEEDS_WHITESPACE_COLLAPSING;
1222 }
1223
1224 p = _value.ParseText( p, "<", flags, curLineNumPtr );
1225 if ( p && *p ) {
1226 return p-1;
1227 }
1228 if ( !p ) {
1229 _document->SetError( XML_ERROR_PARSING_TEXT, _parseLineNum, 0 );
1230 }
1231 }
1232 return 0;
1233 }
1234
1235
1236 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
1237 {
1238 if ( !doc ) {
1239 doc = _document;
1240 }
1241 XMLText* text = doc->NewText( Value() );
1242 text->SetCData( this->CData() );
1243 return text;
1244 }
1245
1246
1247 bool XMLText::ShallowEqual( const XMLNode* compare ) const
1248 {
1249 TIXMLASSERT( compare );
1250 const XMLText* text = compare->ToText();
1251 return ( text && XMLUtil::StringEqual( text->Value(), Value() ) );
1252 }
1253
1254
1255 bool XMLText::Accept( XMLVisitor* visitor ) const
1256 {
1257 TIXMLASSERT( visitor );
1258 return visitor->Visit( *this );
1259 }
1260
1261
1262
1263
1264 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
1265 {
1266 }
1267
1268
1269 XMLComment::~XMLComment()
1270 {
1271 }
1272
1273
1274 char* XMLComment::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1275 {
1276
1277 p = _value.ParseText( p, "-->", StrPair::COMMENT, curLineNumPtr );
1278 if ( p == 0 ) {
1279 _document->SetError( XML_ERROR_PARSING_COMMENT, _parseLineNum, 0 );
1280 }
1281 return p;
1282 }
1283
1284
1285 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
1286 {
1287 if ( !doc ) {
1288 doc = _document;
1289 }
1290 XMLComment* comment = doc->NewComment( Value() );
1291 return comment;
1292 }
1293
1294
1295 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
1296 {
1297 TIXMLASSERT( compare );
1298 const XMLComment* comment = compare->ToComment();
1299 return ( comment && XMLUtil::StringEqual( comment->Value(), Value() ));
1300 }
1301
1302
1303 bool XMLComment::Accept( XMLVisitor* visitor ) const
1304 {
1305 TIXMLASSERT( visitor );
1306 return visitor->Visit( *this );
1307 }
1308
1309
1310
1311
1312 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
1313 {
1314 }
1315
1316
1317 XMLDeclaration::~XMLDeclaration()
1318 {
1319
1320 }
1321
1322
1323 char* XMLDeclaration::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1324 {
1325
1326 p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1327 if ( p == 0 ) {
1328 _document->SetError( XML_ERROR_PARSING_DECLARATION, _parseLineNum, 0 );
1329 }
1330 return p;
1331 }
1332
1333
1334 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
1335 {
1336 if ( !doc ) {
1337 doc = _document;
1338 }
1339 XMLDeclaration* dec = doc->NewDeclaration( Value() );
1340 return dec;
1341 }
1342
1343
1344 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
1345 {
1346 TIXMLASSERT( compare );
1347 const XMLDeclaration* declaration = compare->ToDeclaration();
1348 return ( declaration && XMLUtil::StringEqual( declaration->Value(), Value() ));
1349 }
1350
1351
1352
1353 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
1354 {
1355 TIXMLASSERT( visitor );
1356 return visitor->Visit( *this );
1357 }
1358
1359
1360
1361 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
1362 {
1363 }
1364
1365
1366 XMLUnknown::~XMLUnknown()
1367 {
1368 }
1369
1370
1371 char* XMLUnknown::ParseDeep( char* p, StrPair*, int* curLineNumPtr )
1372 {
1373
1374 p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION, curLineNumPtr );
1375 if ( !p ) {
1376 _document->SetError( XML_ERROR_PARSING_UNKNOWN, _parseLineNum, 0 );
1377 }
1378 return p;
1379 }
1380
1381
1382 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
1383 {
1384 if ( !doc ) {
1385 doc = _document;
1386 }
1387 XMLUnknown* text = doc->NewUnknown( Value() );
1388 return text;
1389 }
1390
1391
1392 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
1393 {
1394 TIXMLASSERT( compare );
1395 const XMLUnknown* unknown = compare->ToUnknown();
1396 return ( unknown && XMLUtil::StringEqual( unknown->Value(), Value() ));
1397 }
1398
1399
1400 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
1401 {
1402 TIXMLASSERT( visitor );
1403 return visitor->Visit( *this );
1404 }
1405
1406
1407
1408 const char* XMLAttribute::Name() const
1409 {
1410 return _name.GetStr();
1411 }
1412
1413 const char* XMLAttribute::Value() const
1414 {
1415 return _value.GetStr();
1416 }
1417
1418 char* XMLAttribute::ParseDeep( char* p, bool processEntities, int* curLineNumPtr )
1419 {
1420
1421 p = _name.ParseName( p );
1422 if ( !p || !*p ) {
1423 return 0;
1424 }
1425
1426
1427 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1428 if ( *p != '=' ) {
1429 return 0;
1430 }
1431
1432 ++p;
1433 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1434 if ( *p != '\"' && *p != '\'' ) {
1435 return 0;
1436 }
1437
1438 const char endTag[2] = { *p, 0 };
1439 ++p;
1440
1441 p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES, curLineNumPtr );
1442 return p;
1443 }
1444
1445
1446 void XMLAttribute::SetName( const char* n )
1447 {
1448 _name.SetStr( n );
1449 }
1450
1451
1452 XMLError XMLAttribute::QueryIntValue( int* value ) const
1453 {
1454 if ( XMLUtil::ToInt( Value(), value )) {
1455 return XML_SUCCESS;
1456 }
1457 return XML_WRONG_ATTRIBUTE_TYPE;
1458 }
1459
1460
1461 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
1462 {
1463 if ( XMLUtil::ToUnsigned( Value(), value )) {
1464 return XML_SUCCESS;
1465 }
1466 return XML_WRONG_ATTRIBUTE_TYPE;
1467 }
1468
1469
1470 XMLError XMLAttribute::QueryInt64Value(int64_t* value) const
1471 {
1472 if (XMLUtil::ToInt64(Value(), value)) {
1473 return XML_SUCCESS;
1474 }
1475 return XML_WRONG_ATTRIBUTE_TYPE;
1476 }
1477
1478
1479 XMLError XMLAttribute::QueryUnsigned64Value(uint64_t* value) const
1480 {
1481 if(XMLUtil::ToUnsigned64(Value(), value)) {
1482 return XML_SUCCESS;
1483 }
1484 return XML_WRONG_ATTRIBUTE_TYPE;
1485 }
1486
1487
1488 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
1489 {
1490 if ( XMLUtil::ToBool( Value(), value )) {
1491 return XML_SUCCESS;
1492 }
1493 return XML_WRONG_ATTRIBUTE_TYPE;
1494 }
1495
1496
1497 XMLError XMLAttribute::QueryFloatValue( float* value ) const
1498 {
1499 if ( XMLUtil::ToFloat( Value(), value )) {
1500 return XML_SUCCESS;
1501 }
1502 return XML_WRONG_ATTRIBUTE_TYPE;
1503 }
1504
1505
1506 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
1507 {
1508 if ( XMLUtil::ToDouble( Value(), value )) {
1509 return XML_SUCCESS;
1510 }
1511 return XML_WRONG_ATTRIBUTE_TYPE;
1512 }
1513
1514
1515 void XMLAttribute::SetAttribute( const char* v )
1516 {
1517 _value.SetStr( v );
1518 }
1519
1520
1521 void XMLAttribute::SetAttribute( int v )
1522 {
1523 char buf[BUF_SIZE];
1524 XMLUtil::ToStr( v, buf, BUF_SIZE );
1525 _value.SetStr( buf );
1526 }
1527
1528
1529 void XMLAttribute::SetAttribute( unsigned v )
1530 {
1531 char buf[BUF_SIZE];
1532 XMLUtil::ToStr( v, buf, BUF_SIZE );
1533 _value.SetStr( buf );
1534 }
1535
1536
1537 void XMLAttribute::SetAttribute(int64_t v)
1538 {
1539 char buf[BUF_SIZE];
1540 XMLUtil::ToStr(v, buf, BUF_SIZE);
1541 _value.SetStr(buf);
1542 }
1543
1544 void XMLAttribute::SetAttribute(uint64_t v)
1545 {
1546 char buf[BUF_SIZE];
1547 XMLUtil::ToStr(v, buf, BUF_SIZE);
1548 _value.SetStr(buf);
1549 }
1550
1551
1552 void XMLAttribute::SetAttribute( bool v )
1553 {
1554 char buf[BUF_SIZE];
1555 XMLUtil::ToStr( v, buf, BUF_SIZE );
1556 _value.SetStr( buf );
1557 }
1558
1559 void XMLAttribute::SetAttribute( double v )
1560 {
1561 char buf[BUF_SIZE];
1562 XMLUtil::ToStr( v, buf, BUF_SIZE );
1563 _value.SetStr( buf );
1564 }
1565
1566 void XMLAttribute::SetAttribute( float v )
1567 {
1568 char buf[BUF_SIZE];
1569 XMLUtil::ToStr( v, buf, BUF_SIZE );
1570 _value.SetStr( buf );
1571 }
1572
1573
1574
1575 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
1576 _closingType( OPEN ),
1577 _rootAttribute( 0 )
1578 {
1579 }
1580
1581
1582 XMLElement::~XMLElement()
1583 {
1584 while( _rootAttribute ) {
1585 XMLAttribute* next = _rootAttribute->_next;
1586 DeleteAttribute( _rootAttribute );
1587 _rootAttribute = next;
1588 }
1589 }
1590
1591
1592 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
1593 {
1594 for( XMLAttribute* a = _rootAttribute; a; a = a->_next ) {
1595 if ( XMLUtil::StringEqual( a->Name(), name ) ) {
1596 return a;
1597 }
1598 }
1599 return 0;
1600 }
1601
1602
1603 const char* XMLElement::Attribute( const char* name, const char* value ) const
1604 {
1605 const XMLAttribute* a = FindAttribute( name );
1606 if ( !a ) {
1607 return 0;
1608 }
1609 if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
1610 return a->Value();
1611 }
1612 return 0;
1613 }
1614
1615 int XMLElement::IntAttribute(const char* name, int defaultValue) const
1616 {
1617 int i = defaultValue;
1618 QueryIntAttribute(name, &i);
1619 return i;
1620 }
1621
1622 unsigned XMLElement::UnsignedAttribute(const char* name, unsigned defaultValue) const
1623 {
1624 unsigned i = defaultValue;
1625 QueryUnsignedAttribute(name, &i);
1626 return i;
1627 }
1628
1629 int64_t XMLElement::Int64Attribute(const char* name, int64_t defaultValue) const
1630 {
1631 int64_t i = defaultValue;
1632 QueryInt64Attribute(name, &i);
1633 return i;
1634 }
1635
1636 uint64_t XMLElement::Unsigned64Attribute(const char* name, uint64_t defaultValue) const
1637 {
1638 uint64_t i = defaultValue;
1639 QueryUnsigned64Attribute(name, &i);
1640 return i;
1641 }
1642
1643 bool XMLElement::BoolAttribute(const char* name, bool defaultValue) const
1644 {
1645 bool b = defaultValue;
1646 QueryBoolAttribute(name, &b);
1647 return b;
1648 }
1649
1650 double XMLElement::DoubleAttribute(const char* name, double defaultValue) const
1651 {
1652 double d = defaultValue;
1653 QueryDoubleAttribute(name, &d);
1654 return d;
1655 }
1656
1657 float XMLElement::FloatAttribute(const char* name, float defaultValue) const
1658 {
1659 float f = defaultValue;
1660 QueryFloatAttribute(name, &f);
1661 return f;
1662 }
1663
1664 const char* XMLElement::GetText() const
1665 {
1666
1667 const XMLNode* node = FirstChild();
1668 while (node) {
1669 if (node->ToComment()) {
1670 node = node->NextSibling();
1671 continue;
1672 }
1673 break;
1674 }
1675
1676 if ( node && node->ToText() ) {
1677 return node->Value();
1678 }
1679 return 0;
1680 }
1681
1682
1683 void XMLElement::SetText( const char* inText )
1684 {
1685 if ( FirstChild() && FirstChild()->ToText() )
1686 FirstChild()->SetValue( inText );
1687 else {
1688 XMLText* theText = GetDocument()->NewText( inText );
1689 InsertFirstChild( theText );
1690 }
1691 }
1692
1693
1694 void XMLElement::SetText( int v )
1695 {
1696 char buf[BUF_SIZE];
1697 XMLUtil::ToStr( v, buf, BUF_SIZE );
1698 SetText( buf );
1699 }
1700
1701
1702 void XMLElement::SetText( unsigned v )
1703 {
1704 char buf[BUF_SIZE];
1705 XMLUtil::ToStr( v, buf, BUF_SIZE );
1706 SetText( buf );
1707 }
1708
1709
1710 void XMLElement::SetText(int64_t v)
1711 {
1712 char buf[BUF_SIZE];
1713 XMLUtil::ToStr(v, buf, BUF_SIZE);
1714 SetText(buf);
1715 }
1716
1717 void XMLElement::SetText(uint64_t v) {
1718 char buf[BUF_SIZE];
1719 XMLUtil::ToStr(v, buf, BUF_SIZE);
1720 SetText(buf);
1721 }
1722
1723
1724 void XMLElement::SetText( bool v )
1725 {
1726 char buf[BUF_SIZE];
1727 XMLUtil::ToStr( v, buf, BUF_SIZE );
1728 SetText( buf );
1729 }
1730
1731
1732 void XMLElement::SetText( float v )
1733 {
1734 char buf[BUF_SIZE];
1735 XMLUtil::ToStr( v, buf, BUF_SIZE );
1736 SetText( buf );
1737 }
1738
1739
1740 void XMLElement::SetText( double v )
1741 {
1742 char buf[BUF_SIZE];
1743 XMLUtil::ToStr( v, buf, BUF_SIZE );
1744 SetText( buf );
1745 }
1746
1747
1748 XMLError XMLElement::QueryIntText( int* ival ) const
1749 {
1750 if ( FirstChild() && FirstChild()->ToText() ) {
1751 const char* t = FirstChild()->Value();
1752 if ( XMLUtil::ToInt( t, ival ) ) {
1753 return XML_SUCCESS;
1754 }
1755 return XML_CAN_NOT_CONVERT_TEXT;
1756 }
1757 return XML_NO_TEXT_NODE;
1758 }
1759
1760
1761 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
1762 {
1763 if ( FirstChild() && FirstChild()->ToText() ) {
1764 const char* t = FirstChild()->Value();
1765 if ( XMLUtil::ToUnsigned( t, uval ) ) {
1766 return XML_SUCCESS;
1767 }
1768 return XML_CAN_NOT_CONVERT_TEXT;
1769 }
1770 return XML_NO_TEXT_NODE;
1771 }
1772
1773
1774 XMLError XMLElement::QueryInt64Text(int64_t* ival) const
1775 {
1776 if (FirstChild() && FirstChild()->ToText()) {
1777 const char* t = FirstChild()->Value();
1778 if (XMLUtil::ToInt64(t, ival)) {
1779 return XML_SUCCESS;
1780 }
1781 return XML_CAN_NOT_CONVERT_TEXT;
1782 }
1783 return XML_NO_TEXT_NODE;
1784 }
1785
1786
1787 XMLError XMLElement::QueryUnsigned64Text(uint64_t* uval) const
1788 {
1789 if(FirstChild() && FirstChild()->ToText()) {
1790 const char* t = FirstChild()->Value();
1791 if(XMLUtil::ToUnsigned64(t, uval)) {
1792 return XML_SUCCESS;
1793 }
1794 return XML_CAN_NOT_CONVERT_TEXT;
1795 }
1796 return XML_NO_TEXT_NODE;
1797 }
1798
1799
1800 XMLError XMLElement::QueryBoolText( bool* bval ) const
1801 {
1802 if ( FirstChild() && FirstChild()->ToText() ) {
1803 const char* t = FirstChild()->Value();
1804 if ( XMLUtil::ToBool( t, bval ) ) {
1805 return XML_SUCCESS;
1806 }
1807 return XML_CAN_NOT_CONVERT_TEXT;
1808 }
1809 return XML_NO_TEXT_NODE;
1810 }
1811
1812
1813 XMLError XMLElement::QueryDoubleText( double* dval ) const
1814 {
1815 if ( FirstChild() && FirstChild()->ToText() ) {
1816 const char* t = FirstChild()->Value();
1817 if ( XMLUtil::ToDouble( t, dval ) ) {
1818 return XML_SUCCESS;
1819 }
1820 return XML_CAN_NOT_CONVERT_TEXT;
1821 }
1822 return XML_NO_TEXT_NODE;
1823 }
1824
1825
1826 XMLError XMLElement::QueryFloatText( float* fval ) const
1827 {
1828 if ( FirstChild() && FirstChild()->ToText() ) {
1829 const char* t = FirstChild()->Value();
1830 if ( XMLUtil::ToFloat( t, fval ) ) {
1831 return XML_SUCCESS;
1832 }
1833 return XML_CAN_NOT_CONVERT_TEXT;
1834 }
1835 return XML_NO_TEXT_NODE;
1836 }
1837
1838 int XMLElement::IntText(int defaultValue) const
1839 {
1840 int i = defaultValue;
1841 QueryIntText(&i);
1842 return i;
1843 }
1844
1845 unsigned XMLElement::UnsignedText(unsigned defaultValue) const
1846 {
1847 unsigned i = defaultValue;
1848 QueryUnsignedText(&i);
1849 return i;
1850 }
1851
1852 int64_t XMLElement::Int64Text(int64_t defaultValue) const
1853 {
1854 int64_t i = defaultValue;
1855 QueryInt64Text(&i);
1856 return i;
1857 }
1858
1859 uint64_t XMLElement::Unsigned64Text(uint64_t defaultValue) const
1860 {
1861 uint64_t i = defaultValue;
1862 QueryUnsigned64Text(&i);
1863 return i;
1864 }
1865
1866 bool XMLElement::BoolText(bool defaultValue) const
1867 {
1868 bool b = defaultValue;
1869 QueryBoolText(&b);
1870 return b;
1871 }
1872
1873 double XMLElement::DoubleText(double defaultValue) const
1874 {
1875 double d = defaultValue;
1876 QueryDoubleText(&d);
1877 return d;
1878 }
1879
1880 float XMLElement::FloatText(float defaultValue) const
1881 {
1882 float f = defaultValue;
1883 QueryFloatText(&f);
1884 return f;
1885 }
1886
1887
1888 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
1889 {
1890 XMLAttribute* last = 0;
1891 XMLAttribute* attrib = 0;
1892 for( attrib = _rootAttribute;
1893 attrib;
1894 last = attrib, attrib = attrib->_next ) {
1895 if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
1896 break;
1897 }
1898 }
1899 if ( !attrib ) {
1900 attrib = CreateAttribute();
1901 TIXMLASSERT( attrib );
1902 if ( last ) {
1903 TIXMLASSERT( last->_next == 0 );
1904 last->_next = attrib;
1905 }
1906 else {
1907 TIXMLASSERT( _rootAttribute == 0 );
1908 _rootAttribute = attrib;
1909 }
1910 attrib->SetName( name );
1911 }
1912 return attrib;
1913 }
1914
1915
1916 void XMLElement::DeleteAttribute( const char* name )
1917 {
1918 XMLAttribute* prev = 0;
1919 for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
1920 if ( XMLUtil::StringEqual( name, a->Name() ) ) {
1921 if ( prev ) {
1922 prev->_next = a->_next;
1923 }
1924 else {
1925 _rootAttribute = a->_next;
1926 }
1927 DeleteAttribute( a );
1928 break;
1929 }
1930 prev = a;
1931 }
1932 }
1933
1934
1935 char* XMLElement::ParseAttributes( char* p, int* curLineNumPtr )
1936 {
1937 XMLAttribute* prevAttribute = 0;
1938
1939
1940 while( p ) {
1941 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
1942 if ( !(*p) ) {
1943 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, "XMLElement name=%s", Name() );
1944 return 0;
1945 }
1946
1947
1948 if (XMLUtil::IsNameStartChar( (unsigned char) *p ) ) {
1949 XMLAttribute* attrib = CreateAttribute();
1950 TIXMLASSERT( attrib );
1951 attrib->_parseLineNum = _document->_parseCurLineNum;
1952
1953 const int attrLineNum = attrib->_parseLineNum;
1954
1955 p = attrib->ParseDeep( p, _document->ProcessEntities(), curLineNumPtr );
1956 if ( !p || Attribute( attrib->Name() ) ) {
1957 DeleteAttribute( attrib );
1958 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, attrLineNum, "XMLElement name=%s", Name() );
1959 return 0;
1960 }
1961
1962
1963
1964
1965
1966 if ( prevAttribute ) {
1967 TIXMLASSERT( prevAttribute->_next == 0 );
1968 prevAttribute->_next = attrib;
1969 }
1970 else {
1971 TIXMLASSERT( _rootAttribute == 0 );
1972 _rootAttribute = attrib;
1973 }
1974 prevAttribute = attrib;
1975 }
1976
1977 else if ( *p == '>' ) {
1978 ++p;
1979 break;
1980 }
1981
1982 else if ( *p == '/' && *(p+1) == '>' ) {
1983 _closingType = CLOSED;
1984 return p+2;
1985 }
1986 else {
1987 _document->SetError( XML_ERROR_PARSING_ELEMENT, _parseLineNum, 0 );
1988 return 0;
1989 }
1990 }
1991 return p;
1992 }
1993
1994 void XMLElement::DeleteAttribute( XMLAttribute* attribute )
1995 {
1996 if ( attribute == 0 ) {
1997 return;
1998 }
1999 MemPool* pool = attribute->_memPool;
2000 attribute->~XMLAttribute();
2001 pool->Free( attribute );
2002 }
2003
2004 XMLAttribute* XMLElement::CreateAttribute()
2005 {
2006 TIXMLASSERT( sizeof( XMLAttribute ) == _document->_attributePool.ItemSize() );
2007 XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
2008 TIXMLASSERT( attrib );
2009 attrib->_memPool = &_document->_attributePool;
2010 attrib->_memPool->SetTracked();
2011 return attrib;
2012 }
2013
2014
2015 XMLElement* XMLElement::InsertNewChildElement(const char* name)
2016 {
2017 XMLElement* node = _document->NewElement(name);
2018 return InsertEndChild(node) ? node : 0;
2019 }
2020
2021 XMLComment* XMLElement::InsertNewComment(const char* comment)
2022 {
2023 XMLComment* node = _document->NewComment(comment);
2024 return InsertEndChild(node) ? node : 0;
2025 }
2026
2027 XMLText* XMLElement::InsertNewText(const char* text)
2028 {
2029 XMLText* node = _document->NewText(text);
2030 return InsertEndChild(node) ? node : 0;
2031 }
2032
2033 XMLDeclaration* XMLElement::InsertNewDeclaration(const char* text)
2034 {
2035 XMLDeclaration* node = _document->NewDeclaration(text);
2036 return InsertEndChild(node) ? node : 0;
2037 }
2038
2039 XMLUnknown* XMLElement::InsertNewUnknown(const char* text)
2040 {
2041 XMLUnknown* node = _document->NewUnknown(text);
2042 return InsertEndChild(node) ? node : 0;
2043 }
2044
2045
2046
2047
2048
2049
2050
2051 char* XMLElement::ParseDeep( char* p, StrPair* parentEndTag, int* curLineNumPtr )
2052 {
2053
2054 p = XMLUtil::SkipWhiteSpace( p, curLineNumPtr );
2055
2056
2057
2058
2059 if ( *p == '/' ) {
2060 _closingType = CLOSING;
2061 ++p;
2062 }
2063
2064 p = _value.ParseName( p );
2065 if ( _value.Empty() ) {
2066 return 0;
2067 }
2068
2069 p = ParseAttributes( p, curLineNumPtr );
2070 if ( !p || !*p || _closingType != OPEN ) {
2071 return p;
2072 }
2073
2074 p = XMLNode::ParseDeep( p, parentEndTag, curLineNumPtr );
2075 return p;
2076 }
2077
2078
2079
2080 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
2081 {
2082 if ( !doc ) {
2083 doc = _document;
2084 }
2085 XMLElement* element = doc->NewElement( Value() );
2086 for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
2087 element->SetAttribute( a->Name(), a->Value() );
2088 }
2089 return element;
2090 }
2091
2092
2093 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
2094 {
2095 TIXMLASSERT( compare );
2096 const XMLElement* other = compare->ToElement();
2097 if ( other && XMLUtil::StringEqual( other->Name(), Name() )) {
2098
2099 const XMLAttribute* a=FirstAttribute();
2100 const XMLAttribute* b=other->FirstAttribute();
2101
2102 while ( a && b ) {
2103 if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
2104 return false;
2105 }
2106 a = a->Next();
2107 b = b->Next();
2108 }
2109 if ( a || b ) {
2110
2111 return false;
2112 }
2113 return true;
2114 }
2115 return false;
2116 }
2117
2118
2119 bool XMLElement::Accept( XMLVisitor* visitor ) const
2120 {
2121 TIXMLASSERT( visitor );
2122 if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
2123 for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
2124 if ( !node->Accept( visitor ) ) {
2125 break;
2126 }
2127 }
2128 }
2129 return visitor->VisitExit( *this );
2130 }
2131
2132
2133
2134
2135
2136 const char* XMLDocument::_errorNames[XML_ERROR_COUNT] = {
2137 "XML_SUCCESS",
2138 "XML_NO_ATTRIBUTE",
2139 "XML_WRONG_ATTRIBUTE_TYPE",
2140 "XML_ERROR_FILE_NOT_FOUND",
2141 "XML_ERROR_FILE_COULD_NOT_BE_OPENED",
2142 "XML_ERROR_FILE_READ_ERROR",
2143 "XML_ERROR_PARSING_ELEMENT",
2144 "XML_ERROR_PARSING_ATTRIBUTE",
2145 "XML_ERROR_PARSING_TEXT",
2146 "XML_ERROR_PARSING_CDATA",
2147 "XML_ERROR_PARSING_COMMENT",
2148 "XML_ERROR_PARSING_DECLARATION",
2149 "XML_ERROR_PARSING_UNKNOWN",
2150 "XML_ERROR_EMPTY_DOCUMENT",
2151 "XML_ERROR_MISMATCHED_ELEMENT",
2152 "XML_ERROR_PARSING",
2153 "XML_CAN_NOT_CONVERT_TEXT",
2154 "XML_NO_TEXT_NODE",
2155 "XML_ELEMENT_DEPTH_EXCEEDED"
2156 };
2157
2158
2159 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespaceMode ) :
2160 XMLNode( 0 ),
2161 _writeBOM( false ),
2162 _processEntities( processEntities ),
2163 _errorID(XML_SUCCESS),
2164 _whitespaceMode( whitespaceMode ),
2165 _errorStr(),
2166 _errorLineNum( 0 ),
2167 _charBuffer( 0 ),
2168 _parseCurLineNum( 0 ),
2169 _parsingDepth(0),
2170 _unlinked(),
2171 _elementPool(),
2172 _attributePool(),
2173 _textPool(),
2174 _commentPool()
2175 {
2176
2177 _document = this;
2178 }
2179
2180
2181 XMLDocument::~XMLDocument()
2182 {
2183 Clear();
2184 }
2185
2186
2187 void XMLDocument::MarkInUse(const XMLNode* const node)
2188 {
2189 TIXMLASSERT(node);
2190 TIXMLASSERT(node->_parent == 0);
2191
2192 for (int i = 0; i < _unlinked.Size(); ++i) {
2193 if (node == _unlinked[i]) {
2194 _unlinked.SwapRemove(i);
2195 break;
2196 }
2197 }
2198 }
2199
2200 void XMLDocument::Clear()
2201 {
2202 DeleteChildren();
2203 while( _unlinked.Size()) {
2204 DeleteNode(_unlinked[0]);
2205 }
2206
2207 #ifdef TINYXML2_DEBUG
2208 const bool hadError = Error();
2209 #endif
2210 ClearError();
2211
2212 delete [] _charBuffer;
2213 _charBuffer = 0;
2214 _parsingDepth = 0;
2215
2216 #if 0
2217 _textPool.Trace( "text" );
2218 _elementPool.Trace( "element" );
2219 _commentPool.Trace( "comment" );
2220 _attributePool.Trace( "attribute" );
2221 #endif
2222
2223 #ifdef TINYXML2_DEBUG
2224 if ( !hadError ) {
2225 TIXMLASSERT( _elementPool.CurrentAllocs() == _elementPool.Untracked() );
2226 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
2227 TIXMLASSERT( _textPool.CurrentAllocs() == _textPool.Untracked() );
2228 TIXMLASSERT( _commentPool.CurrentAllocs() == _commentPool.Untracked() );
2229 }
2230 #endif
2231 }
2232
2233
2234 void XMLDocument::DeepCopy(XMLDocument* target) const
2235 {
2236 TIXMLASSERT(target);
2237 if (target == this) {
2238 return;
2239 }
2240
2241 target->Clear();
2242 for (const XMLNode* node = this->FirstChild(); node; node = node->NextSibling()) {
2243 target->InsertEndChild(node->DeepClone(target));
2244 }
2245 }
2246
2247 XMLElement* XMLDocument::NewElement( const char* name )
2248 {
2249 XMLElement* ele = CreateUnlinkedNode<XMLElement>( _elementPool );
2250 ele->SetName( name );
2251 return ele;
2252 }
2253
2254
2255 XMLComment* XMLDocument::NewComment( const char* str )
2256 {
2257 XMLComment* comment = CreateUnlinkedNode<XMLComment>( _commentPool );
2258 comment->SetValue( str );
2259 return comment;
2260 }
2261
2262
2263 XMLText* XMLDocument::NewText( const char* str )
2264 {
2265 XMLText* text = CreateUnlinkedNode<XMLText>( _textPool );
2266 text->SetValue( str );
2267 return text;
2268 }
2269
2270
2271 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
2272 {
2273 XMLDeclaration* dec = CreateUnlinkedNode<XMLDeclaration>( _commentPool );
2274 dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
2275 return dec;
2276 }
2277
2278
2279 XMLUnknown* XMLDocument::NewUnknown( const char* str )
2280 {
2281 XMLUnknown* unk = CreateUnlinkedNode<XMLUnknown>( _commentPool );
2282 unk->SetValue( str );
2283 return unk;
2284 }
2285
2286 static FILE* callfopen( const char* filepath, const char* mode )
2287 {
2288 TIXMLASSERT( filepath );
2289 TIXMLASSERT( mode );
2290 #if defined(_MSC_VER) && (_MSC_VER >= 1400 ) && (!defined WINCE)
2291 FILE* fp = 0;
2292 const errno_t err = fopen_s( &fp, filepath, mode );
2293 if ( err ) {
2294 return 0;
2295 }
2296 #else
2297 FILE* fp = fopen( filepath, mode );
2298 #endif
2299 return fp;
2300 }
2301
2302 void XMLDocument::DeleteNode( XMLNode* node ) {
2303 TIXMLASSERT( node );
2304 TIXMLASSERT(node->_document == this );
2305 if (node->_parent) {
2306 node->_parent->DeleteChild( node );
2307 }
2308 else {
2309
2310
2311
2312
2313 node->_memPool->SetTracked();
2314
2315 XMLNode::DeleteNode(node);
2316 }
2317 }
2318
2319
2320 XMLError XMLDocument::LoadFile( const char* filename )
2321 {
2322 if ( !filename ) {
2323 TIXMLASSERT( false );
2324 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2325 return _errorID;
2326 }
2327
2328 Clear();
2329 FILE* fp = callfopen( filename, "rb" );
2330 if ( !fp ) {
2331 SetError( XML_ERROR_FILE_NOT_FOUND, 0, "filename=%s", filename );
2332 return _errorID;
2333 }
2334 LoadFile( fp );
2335 fclose( fp );
2336 return _errorID;
2337 }
2338
2339 XMLError XMLDocument::LoadFile( FILE* fp )
2340 {
2341 Clear();
2342
2343 TIXML_FSEEK( fp, 0, SEEK_SET );
2344 if ( fgetc( fp ) == EOF && ferror( fp ) != 0 ) {
2345 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2346 return _errorID;
2347 }
2348
2349 TIXML_FSEEK( fp, 0, SEEK_END );
2350
2351 unsigned long long filelength;
2352 {
2353 const long long fileLengthSigned = TIXML_FTELL( fp );
2354 TIXML_FSEEK( fp, 0, SEEK_SET );
2355 if ( fileLengthSigned == -1L ) {
2356 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2357 return _errorID;
2358 }
2359 TIXMLASSERT( fileLengthSigned >= 0 );
2360 filelength = static_cast<unsigned long long>(fileLengthSigned);
2361 }
2362
2363 const size_t maxSizeT = static_cast<size_t>(-1);
2364
2365
2366 if ( filelength >= static_cast<unsigned long long>(maxSizeT) ) {
2367
2368 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2369 return _errorID;
2370 }
2371
2372 if ( filelength == 0 ) {
2373 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2374 return _errorID;
2375 }
2376
2377 const size_t size = static_cast<size_t>(filelength);
2378 TIXMLASSERT( _charBuffer == 0 );
2379 _charBuffer = new char[size+1];
2380 const size_t read = fread( _charBuffer, 1, size, fp );
2381 if ( read != size ) {
2382 SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
2383 return _errorID;
2384 }
2385
2386 _charBuffer[size] = 0;
2387
2388 Parse();
2389 return _errorID;
2390 }
2391
2392
2393 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
2394 {
2395 if ( !filename ) {
2396 TIXMLASSERT( false );
2397 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=<null>" );
2398 return _errorID;
2399 }
2400
2401 FILE* fp = callfopen( filename, "w" );
2402 if ( !fp ) {
2403 SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, 0, "filename=%s", filename );
2404 return _errorID;
2405 }
2406 SaveFile(fp, compact);
2407 fclose( fp );
2408 return _errorID;
2409 }
2410
2411
2412 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
2413 {
2414
2415
2416 ClearError();
2417 XMLPrinter stream( fp, compact );
2418 Print( &stream );
2419 return _errorID;
2420 }
2421
2422
2423 XMLError XMLDocument::Parse( const char* xml, size_t nBytes )
2424 {
2425 Clear();
2426
2427 if ( nBytes == 0 || !xml || !*xml ) {
2428 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2429 return _errorID;
2430 }
2431 if ( nBytes == static_cast<size_t>(-1) ) {
2432 nBytes = strlen( xml );
2433 }
2434 TIXMLASSERT( _charBuffer == 0 );
2435 _charBuffer = new char[ nBytes+1 ];
2436 memcpy( _charBuffer, xml, nBytes );
2437 _charBuffer[nBytes] = 0;
2438
2439 Parse();
2440 if ( Error() ) {
2441
2442
2443
2444 DeleteChildren();
2445 _elementPool.Clear();
2446 _attributePool.Clear();
2447 _textPool.Clear();
2448 _commentPool.Clear();
2449 }
2450 return _errorID;
2451 }
2452
2453
2454 void XMLDocument::Print( XMLPrinter* streamer ) const
2455 {
2456 if ( streamer ) {
2457 Accept( streamer );
2458 }
2459 else {
2460 XMLPrinter stdoutStreamer( stdout );
2461 Accept( &stdoutStreamer );
2462 }
2463 }
2464
2465
2466 void XMLDocument::ClearError() {
2467 _errorID = XML_SUCCESS;
2468 _errorLineNum = 0;
2469 _errorStr.Reset();
2470 }
2471
2472
2473 void XMLDocument::SetError( XMLError error, int lineNum, const char* format, ... )
2474 {
2475 TIXMLASSERT( error >= 0 && error < XML_ERROR_COUNT );
2476 _errorID = error;
2477 _errorLineNum = lineNum;
2478 _errorStr.Reset();
2479
2480 const size_t BUFFER_SIZE = 1000;
2481 char* buffer = new char[BUFFER_SIZE];
2482
2483 TIXMLASSERT(sizeof(error) <= sizeof(int));
2484 TIXML_SNPRINTF(buffer, BUFFER_SIZE, "Error=%s ErrorID=%d (0x%x) Line number=%d", ErrorIDToName(error), int(error), int(error), lineNum);
2485
2486 if (format) {
2487 size_t len = strlen(buffer);
2488 TIXML_SNPRINTF(buffer + len, BUFFER_SIZE - len, ": ");
2489 len = strlen(buffer);
2490
2491 va_list va;
2492 va_start(va, format);
2493 TIXML_VSNPRINTF(buffer + len, BUFFER_SIZE - len, format, va);
2494 va_end(va);
2495 }
2496 _errorStr.SetStr(buffer);
2497 delete[] buffer;
2498 }
2499
2500
2501 const char* XMLDocument::ErrorIDToName(XMLError errorID)
2502 {
2503 TIXMLASSERT( errorID >= 0 && errorID < XML_ERROR_COUNT );
2504 const char* errorName = _errorNames[errorID];
2505 TIXMLASSERT( errorName && errorName[0] );
2506 return errorName;
2507 }
2508
2509 const char* XMLDocument::ErrorStr() const
2510 {
2511 return _errorStr.Empty() ? "" : _errorStr.GetStr();
2512 }
2513
2514
2515 void XMLDocument::PrintError() const
2516 {
2517 printf("%s\n", ErrorStr());
2518 }
2519
2520 const char* XMLDocument::ErrorName() const
2521 {
2522 return ErrorIDToName(_errorID);
2523 }
2524
2525 void XMLDocument::Parse()
2526 {
2527 TIXMLASSERT( NoChildren() );
2528 TIXMLASSERT( _charBuffer );
2529 _parseCurLineNum = 1;
2530 _parseLineNum = 1;
2531 char* p = _charBuffer;
2532 p = XMLUtil::SkipWhiteSpace( p, &_parseCurLineNum );
2533 p = const_cast<char*>( XMLUtil::ReadBOM( p, &_writeBOM ) );
2534 if ( !*p ) {
2535 SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
2536 return;
2537 }
2538 ParseDeep(p, 0, &_parseCurLineNum );
2539 }
2540
2541 void XMLDocument::PushDepth()
2542 {
2543 _parsingDepth++;
2544 if (_parsingDepth == TINYXML2_MAX_ELEMENT_DEPTH) {
2545 SetError(XML_ELEMENT_DEPTH_EXCEEDED, _parseCurLineNum, "Element nesting is too deep." );
2546 }
2547 }
2548
2549 void XMLDocument::PopDepth()
2550 {
2551 TIXMLASSERT(_parsingDepth > 0);
2552 --_parsingDepth;
2553 }
2554
2555 XMLPrinter::XMLPrinter( FILE* file, bool compact, int depth ) :
2556 _elementJustOpened( false ),
2557 _stack(),
2558 _firstElement( true ),
2559 _fp( file ),
2560 _depth( depth ),
2561 _textDepth( -1 ),
2562 _processEntities( true ),
2563 _compactMode( compact ),
2564 _buffer()
2565 {
2566 for( int i=0; i<ENTITY_RANGE; ++i ) {
2567 _entityFlag[i] = false;
2568 _restrictedEntityFlag[i] = false;
2569 }
2570 for( int i=0; i<NUM_ENTITIES; ++i ) {
2571 const char entityValue = entities[i].value;
2572 const unsigned char flagIndex = static_cast<unsigned char>(entityValue);
2573 TIXMLASSERT( flagIndex < ENTITY_RANGE );
2574 _entityFlag[flagIndex] = true;
2575 }
2576 _restrictedEntityFlag[static_cast<unsigned char>('&')] = true;
2577 _restrictedEntityFlag[static_cast<unsigned char>('<')] = true;
2578 _restrictedEntityFlag[static_cast<unsigned char>('>')] = true;
2579 _buffer.Push( 0 );
2580 }
2581
2582
2583 void XMLPrinter::Print( const char* format, ... )
2584 {
2585 va_list va;
2586 va_start( va, format );
2587
2588 if ( _fp ) {
2589 vfprintf( _fp, format, va );
2590 }
2591 else {
2592 const int len = TIXML_VSCPRINTF( format, va );
2593
2594 va_end( va );
2595 TIXMLASSERT( len >= 0 );
2596 va_start( va, format );
2597 TIXMLASSERT( _buffer.Size() > 0 && _buffer[_buffer.Size() - 1] == 0 );
2598 char* p = _buffer.PushArr( len ) - 1;
2599 TIXML_VSNPRINTF( p, len+1, format, va );
2600 }
2601 va_end( va );
2602 }
2603
2604
2605 void XMLPrinter::Write( const char* data, size_t size )
2606 {
2607 if ( _fp ) {
2608 fwrite ( data , sizeof(char), size, _fp);
2609 }
2610 else {
2611 char* p = _buffer.PushArr( static_cast<int>(size) ) - 1;
2612 memcpy( p, data, size );
2613 p[size] = 0;
2614 }
2615 }
2616
2617
2618 void XMLPrinter::Putc( char ch )
2619 {
2620 if ( _fp ) {
2621 fputc ( ch, _fp);
2622 }
2623 else {
2624 char* p = _buffer.PushArr( sizeof(char) ) - 1;
2625 p[0] = ch;
2626 p[1] = 0;
2627 }
2628 }
2629
2630
2631 void XMLPrinter::PrintSpace( int depth )
2632 {
2633 for( int i=0; i<depth; ++i ) {
2634 Write( " " );
2635 }
2636 }
2637
2638
2639 void XMLPrinter::PrintString( const char* p, bool restricted )
2640 {
2641
2642 const char* q = p;
2643
2644 if ( _processEntities ) {
2645 const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
2646 while ( *q ) {
2647 TIXMLASSERT( p <= q );
2648
2649 if ( *q > 0 && *q < ENTITY_RANGE ) {
2650
2651
2652
2653 if ( flag[static_cast<unsigned char>(*q)] ) {
2654 while ( p < q ) {
2655 const size_t delta = q - p;
2656 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2657 Write( p, toPrint );
2658 p += toPrint;
2659 }
2660 bool entityPatternPrinted = false;
2661 for( int i=0; i<NUM_ENTITIES; ++i ) {
2662 if ( entities[i].value == *q ) {
2663 Putc( '&' );
2664 Write( entities[i].pattern, entities[i].length );
2665 Putc( ';' );
2666 entityPatternPrinted = true;
2667 break;
2668 }
2669 }
2670 if ( !entityPatternPrinted ) {
2671
2672 TIXMLASSERT( false );
2673 }
2674 ++p;
2675 }
2676 }
2677 ++q;
2678 TIXMLASSERT( p <= q );
2679 }
2680
2681
2682 if ( p < q ) {
2683 const size_t delta = q - p;
2684 const int toPrint = ( INT_MAX < delta ) ? INT_MAX : static_cast<int>(delta);
2685 Write( p, toPrint );
2686 }
2687 }
2688 else {
2689 Write( p );
2690 }
2691 }
2692
2693
2694 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
2695 {
2696 if ( writeBOM ) {
2697 static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
2698 Write( reinterpret_cast< const char* >( bom ) );
2699 }
2700 if ( writeDec ) {
2701 PushDeclaration( "xml version=\"1.0\"" );
2702 }
2703 }
2704
2705 void XMLPrinter::PrepareForNewNode( bool compactMode )
2706 {
2707 SealElementIfJustOpened();
2708
2709 if ( compactMode ) {
2710 return;
2711 }
2712
2713 if ( _firstElement ) {
2714 PrintSpace (_depth);
2715 } else if ( _textDepth < 0) {
2716 Putc( '\n' );
2717 PrintSpace( _depth );
2718 }
2719
2720 _firstElement = false;
2721 }
2722
2723 void XMLPrinter::OpenElement( const char* name, bool compactMode )
2724 {
2725 PrepareForNewNode( compactMode );
2726 _stack.Push( name );
2727
2728 Write ( "<" );
2729 Write ( name );
2730
2731 _elementJustOpened = true;
2732 ++_depth;
2733 }
2734
2735
2736 void XMLPrinter::PushAttribute( const char* name, const char* value )
2737 {
2738 TIXMLASSERT( _elementJustOpened );
2739 Putc ( ' ' );
2740 Write( name );
2741 Write( "=\"" );
2742 PrintString( value, false );
2743 Putc ( '\"' );
2744 }
2745
2746
2747 void XMLPrinter::PushAttribute( const char* name, int v )
2748 {
2749 char buf[BUF_SIZE];
2750 XMLUtil::ToStr( v, buf, BUF_SIZE );
2751 PushAttribute( name, buf );
2752 }
2753
2754
2755 void XMLPrinter::PushAttribute( const char* name, unsigned v )
2756 {
2757 char buf[BUF_SIZE];
2758 XMLUtil::ToStr( v, buf, BUF_SIZE );
2759 PushAttribute( name, buf );
2760 }
2761
2762
2763 void XMLPrinter::PushAttribute(const char* name, int64_t v)
2764 {
2765 char buf[BUF_SIZE];
2766 XMLUtil::ToStr(v, buf, BUF_SIZE);
2767 PushAttribute(name, buf);
2768 }
2769
2770
2771 void XMLPrinter::PushAttribute(const char* name, uint64_t v)
2772 {
2773 char buf[BUF_SIZE];
2774 XMLUtil::ToStr(v, buf, BUF_SIZE);
2775 PushAttribute(name, buf);
2776 }
2777
2778
2779 void XMLPrinter::PushAttribute( const char* name, bool v )
2780 {
2781 char buf[BUF_SIZE];
2782 XMLUtil::ToStr( v, buf, BUF_SIZE );
2783 PushAttribute( name, buf );
2784 }
2785
2786
2787 void XMLPrinter::PushAttribute( const char* name, double v )
2788 {
2789 char buf[BUF_SIZE];
2790 XMLUtil::ToStr( v, buf, BUF_SIZE );
2791 PushAttribute( name, buf );
2792 }
2793
2794
2795 void XMLPrinter::CloseElement( bool compactMode )
2796 {
2797 --_depth;
2798 const char* name = _stack.Pop();
2799
2800 if ( _elementJustOpened ) {
2801 Write( "/>" );
2802 }
2803 else {
2804 if ( _textDepth < 0 && !compactMode) {
2805 Putc( '\n' );
2806 PrintSpace( _depth );
2807 }
2808 Write ( "</" );
2809 Write ( name );
2810 Write ( ">" );
2811 }
2812
2813 if ( _textDepth == _depth ) {
2814 _textDepth = -1;
2815 }
2816 if ( _depth == 0 && !compactMode) {
2817 Putc( '\n' );
2818 }
2819 _elementJustOpened = false;
2820 }
2821
2822
2823 void XMLPrinter::SealElementIfJustOpened()
2824 {
2825 if ( !_elementJustOpened ) {
2826 return;
2827 }
2828 _elementJustOpened = false;
2829 Putc( '>' );
2830 }
2831
2832
2833 void XMLPrinter::PushText( const char* text, bool cdata )
2834 {
2835 _textDepth = _depth-1;
2836
2837 SealElementIfJustOpened();
2838 if ( cdata ) {
2839 Write( "<![CDATA[" );
2840 Write( text );
2841 Write( "]]>" );
2842 }
2843 else {
2844 PrintString( text, true );
2845 }
2846 }
2847
2848
2849 void XMLPrinter::PushText( int64_t value )
2850 {
2851 char buf[BUF_SIZE];
2852 XMLUtil::ToStr( value, buf, BUF_SIZE );
2853 PushText( buf, false );
2854 }
2855
2856
2857 void XMLPrinter::PushText( uint64_t value )
2858 {
2859 char buf[BUF_SIZE];
2860 XMLUtil::ToStr(value, buf, BUF_SIZE);
2861 PushText(buf, false);
2862 }
2863
2864
2865 void XMLPrinter::PushText( int value )
2866 {
2867 char buf[BUF_SIZE];
2868 XMLUtil::ToStr( value, buf, BUF_SIZE );
2869 PushText( buf, false );
2870 }
2871
2872
2873 void XMLPrinter::PushText( unsigned value )
2874 {
2875 char buf[BUF_SIZE];
2876 XMLUtil::ToStr( value, buf, BUF_SIZE );
2877 PushText( buf, false );
2878 }
2879
2880
2881 void XMLPrinter::PushText( bool value )
2882 {
2883 char buf[BUF_SIZE];
2884 XMLUtil::ToStr( value, buf, BUF_SIZE );
2885 PushText( buf, false );
2886 }
2887
2888
2889 void XMLPrinter::PushText( float value )
2890 {
2891 char buf[BUF_SIZE];
2892 XMLUtil::ToStr( value, buf, BUF_SIZE );
2893 PushText( buf, false );
2894 }
2895
2896
2897 void XMLPrinter::PushText( double value )
2898 {
2899 char buf[BUF_SIZE];
2900 XMLUtil::ToStr( value, buf, BUF_SIZE );
2901 PushText( buf, false );
2902 }
2903
2904
2905 void XMLPrinter::PushComment( const char* comment )
2906 {
2907 PrepareForNewNode( _compactMode );
2908
2909 Write( "<!--" );
2910 Write( comment );
2911 Write( "-->" );
2912 }
2913
2914
2915 void XMLPrinter::PushDeclaration( const char* value )
2916 {
2917 PrepareForNewNode( _compactMode );
2918
2919 Write( "<?" );
2920 Write( value );
2921 Write( "?>" );
2922 }
2923
2924
2925 void XMLPrinter::PushUnknown( const char* value )
2926 {
2927 PrepareForNewNode( _compactMode );
2928
2929 Write( "<!" );
2930 Write( value );
2931 Putc( '>' );
2932 }
2933
2934
2935 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
2936 {
2937 _processEntities = doc.ProcessEntities();
2938 if ( doc.HasBOM() ) {
2939 PushHeader( true, false );
2940 }
2941 return true;
2942 }
2943
2944
2945 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
2946 {
2947 const XMLElement* parentElem = 0;
2948 if ( element.Parent() ) {
2949 parentElem = element.Parent()->ToElement();
2950 }
2951 const bool compactMode = parentElem ? CompactMode( *parentElem ) : _compactMode;
2952 OpenElement( element.Name(), compactMode );
2953 while ( attribute ) {
2954 PushAttribute( attribute->Name(), attribute->Value() );
2955 attribute = attribute->Next();
2956 }
2957 return true;
2958 }
2959
2960
2961 bool XMLPrinter::VisitExit( const XMLElement& element )
2962 {
2963 CloseElement( CompactMode(element) );
2964 return true;
2965 }
2966
2967
2968 bool XMLPrinter::Visit( const XMLText& text )
2969 {
2970 PushText( text.Value(), text.CData() );
2971 return true;
2972 }
2973
2974
2975 bool XMLPrinter::Visit( const XMLComment& comment )
2976 {
2977 PushComment( comment.Value() );
2978 return true;
2979 }
2980
2981 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
2982 {
2983 PushDeclaration( declaration.Value() );
2984 return true;
2985 }
2986
2987
2988 bool XMLPrinter::Visit( const XMLUnknown& unknown )
2989 {
2990 PushUnknown( unknown.Value() );
2991 return true;
2992 }
2993
2994 }