Warning, file /pfRICH/Visualization/tinyxml2.cpp was not indexed
or was modified since last indexation (in which case cross-reference links may be missing, inaccurate or erroneous).
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 }