00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include <ctype.h>
00026 #include <stddef.h>
00027
00028 #include "tinyxml.h"
00029
00030
00031 #ifndef TIXML_USE_STL
00032 #include "tinystr.h"
00033 #endif
00034
00035
00036 #ifdef TIXML_USE_STL
00037 #include <sstream>
00038 #include <iostream>
00039 #endif
00040
00041
00042 #if defined( DEBUG_PARSER )
00043 # if defined( DEBUG ) && defined( _MSC_VER )
00044 # include <windows.h>
00045 # define TIXML_LOG OutputDebugString
00046 # else
00047 # define TIXML_LOG printf
00048 # endif
00049 #endif
00050
00051
00052 #ifndef TIXML_USE_STL
00053
00054
00055 const TiXmlString::size_type TiXmlString::npos = static_cast< TiXmlString::size_type >(-1);
00056
00057
00058
00059 TiXmlString::Rep TiXmlString::nullrep_ = { 0, 0, { '\0' } };
00060
00061
00062 void TiXmlString::reserve (size_type cap)
00063 {
00064 if (cap > capacity())
00065 {
00066 TiXmlString tmp;
00067 tmp.init(length(), cap);
00068 memcpy(tmp.start(), data(), length());
00069 swap(tmp);
00070 }
00071 }
00072
00073
00074 TiXmlString& TiXmlString::assign(const char* str, size_type len)
00075 {
00076 size_type cap = capacity();
00077 if (len > cap || cap > 3*(len + 8))
00078 {
00079 TiXmlString tmp;
00080 tmp.init(len);
00081 memcpy(tmp.start(), str, len);
00082 swap(tmp);
00083 }
00084 else
00085 {
00086 memmove(start(), str, len);
00087 set_size(len);
00088 }
00089 return *this;
00090 }
00091
00092
00093 TiXmlString& TiXmlString::append(const char* str, size_type len)
00094 {
00095 size_type newsize = length() + len;
00096 if (newsize > capacity())
00097 {
00098 reserve (newsize + capacity());
00099 }
00100 memmove(finish(), str, len);
00101 set_size(newsize);
00102 return *this;
00103 }
00104
00105
00106 TiXmlString operator + (const TiXmlString & a, const TiXmlString & b)
00107 {
00108 TiXmlString tmp;
00109 tmp.reserve(a.length() + b.length());
00110 tmp += a;
00111 tmp += b;
00112 return tmp;
00113 }
00114
00115 TiXmlString operator + (const TiXmlString & a, const char* b)
00116 {
00117 TiXmlString tmp;
00118 TiXmlString::size_type b_len = static_cast<TiXmlString::size_type>( strlen(b) );
00119 tmp.reserve(a.length() + b_len);
00120 tmp += a;
00121 tmp.append(b, b_len);
00122 return tmp;
00123 }
00124
00125 TiXmlString operator + (const char* a, const TiXmlString & b)
00126 {
00127 TiXmlString tmp;
00128 TiXmlString::size_type a_len = static_cast<TiXmlString::size_type>( strlen(a) );
00129 tmp.reserve(a_len + b.length());
00130 tmp.append(a, a_len);
00131 tmp += b;
00132 return tmp;
00133 }
00134
00135
00136 #endif // TIXML_USE_STL
00137
00138
00139
00140 const char* TiXmlBase::errorString[ TIXML_ERROR_STRING_COUNT ] =
00141 {
00142 "No error",
00143 "Error",
00144 "Failed to open file",
00145 "Memory allocation failed.",
00146 "Error parsing Element.",
00147 "Failed to read Element name",
00148 "Error reading Element value.",
00149 "Error reading Attributes.",
00150 "Error: empty tag.",
00151 "Error reading end tag.",
00152 "Error parsing Unknown.",
00153 "Error parsing Comment.",
00154 "Error parsing Declaration.",
00155 "Error document empty.",
00156 "Error null (0) or unexpected EOF found in input stream.",
00157 "Error parsing CDATA.",
00158 "Error when TiXmlDocument added to document, because TiXmlDocument can only be at the root.",
00159 };
00160
00161
00162
00163
00164
00165 TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
00166 {
00167 { "&", 5, '&' },
00168 { "<", 4, '<' },
00169 { ">", 4, '>' },
00170 { """, 6, '\"' },
00171 { "'", 6, '\'' }
00172 };
00173
00174
00175
00176
00177
00178
00179
00180
00181
00182
00183
00184 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
00185 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
00186 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
00187
00188 const int TiXmlBase::utf8ByteTable[256] =
00189 {
00190
00191 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00192 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00193 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00194 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00195 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00196 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00197 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00198 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00199 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00200 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00201 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00202 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
00203 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
00204 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
00205 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
00206 4, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
00207 };
00208
00209
00210 void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
00211 {
00212 const unsigned long BYTE_MASK = 0xBF;
00213 const unsigned long BYTE_MARK = 0x80;
00214 const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
00215
00216 if (input < 0x80)
00217 *length = 1;
00218 else if ( input < 0x800 )
00219 *length = 2;
00220 else if ( input < 0x10000 )
00221 *length = 3;
00222 else if ( input < 0x200000 )
00223 *length = 4;
00224 else
00225 { *length = 0; return; }
00226
00227 output += *length;
00228
00229
00230 switch (*length)
00231 {
00232 case 4:
00233 --output;
00234 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00235 input >>= 6;
00236 case 3:
00237 --output;
00238 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00239 input >>= 6;
00240 case 2:
00241 --output;
00242 *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00243 input >>= 6;
00244 case 1:
00245 --output;
00246 *output = (char)(input | FIRST_BYTE_MARK[*length]);
00247 }
00248 }
00249
00250
00251 int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding )
00252 {
00253
00254
00255
00256
00257
00258
00259
00260 if ( anyByte < 127 )
00261 return isalpha( anyByte );
00262 else
00263 return 1;
00264
00265
00266
00267
00268
00269 }
00270
00271
00272 int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding )
00273 {
00274
00275
00276
00277
00278
00279
00280
00281 if ( anyByte < 127 )
00282 return isalnum( anyByte );
00283 else
00284 return 1;
00285
00286
00287
00288
00289
00290 }
00291
00292
00293 class TiXmlParsingData
00294 {
00295 friend class TiXmlDocument;
00296 public:
00297 void Stamp( const char* now, TiXmlEncoding encoding );
00298
00299 const TiXmlCursor& Cursor() { return cursor; }
00300
00301 private:
00302
00303 TiXmlParsingData( const char* start, int _tabsize, int row, int col )
00304 {
00305 assert( start );
00306 stamp = start;
00307 tabsize = _tabsize;
00308 cursor.row = row;
00309 cursor.col = col;
00310 }
00311
00312 TiXmlCursor cursor;
00313 const char* stamp;
00314 int tabsize;
00315 };
00316
00317
00318 void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
00319 {
00320 assert( now );
00321
00322
00323 if ( tabsize < 1 )
00324 {
00325 return;
00326 }
00327
00328
00329 int row = cursor.row;
00330 int col = cursor.col;
00331 const char* p = stamp;
00332 assert( p );
00333
00334 while ( p < now )
00335 {
00336
00337 const unsigned char* pU = (const unsigned char*)p;
00338
00339
00340 switch (*pU) {
00341 case 0:
00342
00343
00344 return;
00345
00346 case '\r':
00347
00348 ++row;
00349 col = 0;
00350
00351 ++p;
00352
00353
00354 if (*p == '\n') {
00355 ++p;
00356 }
00357 break;
00358
00359 case '\n':
00360
00361 ++row;
00362 col = 0;
00363
00364
00365 ++p;
00366
00367
00368
00369
00370 if (*p == '\r') {
00371 ++p;
00372 }
00373 break;
00374
00375 case '\t':
00376
00377 ++p;
00378
00379
00380 col = (col / tabsize + 1) * tabsize;
00381 break;
00382
00383 case TIXML_UTF_LEAD_0:
00384 if ( encoding == TIXML_ENCODING_UTF8 )
00385 {
00386 if ( *(p+1) && *(p+2) )
00387 {
00388
00389
00390 if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
00391 p += 3;
00392 else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
00393 p += 3;
00394 else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
00395 p += 3;
00396 else
00397 { p +=3; ++col; }
00398 }
00399 }
00400 else
00401 {
00402 ++p;
00403 ++col;
00404 }
00405 break;
00406
00407 default:
00408 if ( encoding == TIXML_ENCODING_UTF8 )
00409 {
00410
00411 int step = TiXmlBase::utf8ByteTable[*((const unsigned char*)p)];
00412 if ( step == 0 )
00413 step = 1;
00414 p += step;
00415
00416
00417 ++col;
00418 }
00419 else
00420 {
00421 ++p;
00422 ++col;
00423 }
00424 break;
00425 }
00426 }
00427 cursor.row = row;
00428 cursor.col = col;
00429 assert( cursor.row >= -1 );
00430 assert( cursor.col >= -1 );
00431 stamp = p;
00432 assert( stamp );
00433 }
00434
00435
00436 const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
00437 {
00438 if ( !p || !*p )
00439 {
00440 return 0;
00441 }
00442 if ( encoding == TIXML_ENCODING_UTF8 )
00443 {
00444 while ( *p )
00445 {
00446 const unsigned char* pU = (const unsigned char*)p;
00447
00448
00449 if ( *(pU+0)==TIXML_UTF_LEAD_0
00450 && *(pU+1)==TIXML_UTF_LEAD_1
00451 && *(pU+2)==TIXML_UTF_LEAD_2 )
00452 {
00453 p += 3;
00454 continue;
00455 }
00456 else if(*(pU+0)==TIXML_UTF_LEAD_0
00457 && *(pU+1)==0xbfU
00458 && *(pU+2)==0xbeU )
00459 {
00460 p += 3;
00461 continue;
00462 }
00463 else if(*(pU+0)==TIXML_UTF_LEAD_0
00464 && *(pU+1)==0xbfU
00465 && *(pU+2)==0xbfU )
00466 {
00467 p += 3;
00468 continue;
00469 }
00470
00471 if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
00472 ++p;
00473 else
00474 break;
00475 }
00476 }
00477 else
00478 {
00479 while ( *p && IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )
00480 ++p;
00481 }
00482
00483 return p;
00484 }
00485
00486 #ifdef TIXML_USE_STL
00487 bool TiXmlBase::StreamWhiteSpace( std::istream * in, TIXML_STRING * tag )
00488 {
00489 for( ;; )
00490 {
00491 if ( !in->good() ) return false;
00492
00493 int c = in->peek();
00494
00495 if ( !IsWhiteSpace( c ) || c <= 0 )
00496 return true;
00497
00498 *tag += (char) in->get();
00499 }
00500 }
00501
00502 bool TiXmlBase::StreamTo( std::istream * in, int character, TIXML_STRING * tag )
00503 {
00504
00505 while ( in->good() )
00506 {
00507 int c = in->peek();
00508 if ( c == character )
00509 return true;
00510 if ( c <= 0 )
00511 return false;
00512
00513 in->get();
00514 *tag += (char) c;
00515 }
00516 return false;
00517 }
00518 #endif
00519
00520
00521
00522
00523 const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
00524 {
00525
00526
00527
00528 *name = "";
00529 assert( p );
00530
00531
00532
00533
00534
00535
00536
00537
00538 if ( p && *p
00539 && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
00540 {
00541 const char* start = p;
00542 while( p && *p
00543 && ( IsAlphaNum( (unsigned char ) *p, encoding )
00544 || *p == '_'
00545 || *p == '-'
00546 || *p == '.'
00547 || *p == ':' ) )
00548 {
00549
00550 ++p;
00551 }
00552 if ( p-start > 0 ) {
00553 name->assign( start, p-start );
00554 }
00555 return p;
00556 }
00557 return 0;
00558 }
00559
00560 const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
00561 {
00562
00563 TIXML_STRING ent;
00564 int i;
00565 *length = 0;
00566
00567 if ( *(p+1) && *(p+1) == '#' && *(p+2) )
00568 {
00569 unsigned long ucs = 0;
00570 ptrdiff_t delta = 0;
00571 unsigned mult = 1;
00572
00573 if ( *(p+2) == 'x' )
00574 {
00575
00576 if ( !*(p+3) ) return 0;
00577
00578 const char* q = p+3;
00579 q = strchr( q, ';' );
00580
00581 if ( !q || !*q ) return 0;
00582
00583 delta = q-p;
00584 --q;
00585
00586 while ( *q != 'x' )
00587 {
00588 if ( *q >= '0' && *q <= '9' )
00589 ucs += mult * (*q - '0');
00590 else if ( *q >= 'a' && *q <= 'f' )
00591 ucs += mult * (*q - 'a' + 10);
00592 else if ( *q >= 'A' && *q <= 'F' )
00593 ucs += mult * (*q - 'A' + 10 );
00594 else
00595 return 0;
00596 mult *= 16;
00597 --q;
00598 }
00599 }
00600 else
00601 {
00602
00603 if ( !*(p+2) ) return 0;
00604
00605 const char* q = p+2;
00606 q = strchr( q, ';' );
00607
00608 if ( !q || !*q ) return 0;
00609
00610 delta = q-p;
00611 --q;
00612
00613 while ( *q != '#' )
00614 {
00615 if ( *q >= '0' && *q <= '9' )
00616 ucs += mult * (*q - '0');
00617 else
00618 return 0;
00619 mult *= 10;
00620 --q;
00621 }
00622 }
00623 if ( encoding == TIXML_ENCODING_UTF8 )
00624 {
00625
00626 ConvertUTF32ToUTF8( ucs, value, length );
00627 }
00628 else
00629 {
00630 *value = (char)ucs;
00631 *length = 1;
00632 }
00633 return p + delta + 1;
00634 }
00635
00636
00637 for( i=0; i<NUM_ENTITY; ++i )
00638 {
00639 if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
00640 {
00641 assert( strlen( entity[i].str ) == entity[i].strLength );
00642 *value = entity[i].chr;
00643 *length = 1;
00644 return ( p + entity[i].strLength );
00645 }
00646 }
00647
00648
00649 *value = *p;
00650
00651
00652 return p+1;
00653 }
00654
00655
00656 bool TiXmlBase::StringEqual( const char* p,
00657 const char* tag,
00658 bool ignoreCase,
00659 TiXmlEncoding encoding )
00660 {
00661 assert( p );
00662 assert( tag );
00663 if ( !p || !*p )
00664 {
00665 assert( 0 );
00666 return false;
00667 }
00668
00669 const char* q = p;
00670
00671 if ( ignoreCase )
00672 {
00673 while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
00674 {
00675 ++q;
00676 ++tag;
00677 }
00678
00679 if ( *tag == 0 )
00680 return true;
00681 }
00682 else
00683 {
00684 while ( *q && *tag && *q == *tag )
00685 {
00686 ++q;
00687 ++tag;
00688 }
00689
00690 if ( *tag == 0 )
00691 return true;
00692 }
00693 return false;
00694 }
00695
00696 const char* TiXmlBase::ReadText( const char* p,
00697 TIXML_STRING * text,
00698 bool trimWhiteSpace,
00699 const char* endTag,
00700 bool caseInsensitive,
00701 TiXmlEncoding encoding )
00702 {
00703 *text = "";
00704 if ( !trimWhiteSpace
00705 || !condenseWhiteSpace )
00706 {
00707
00708 while ( p && *p
00709 && !StringEqual( p, endTag, caseInsensitive, encoding )
00710 )
00711 {
00712 int len;
00713 char cArr[4] = { 0, 0, 0, 0 };
00714 p = GetChar( p, cArr, &len, encoding );
00715 text->append( cArr, len );
00716 }
00717 }
00718 else
00719 {
00720 bool whitespace = false;
00721
00722
00723 p = SkipWhiteSpace( p, encoding );
00724 while ( p && *p
00725 && !StringEqual( p, endTag, caseInsensitive, encoding ) )
00726 {
00727 if ( *p == '\r' || *p == '\n' )
00728 {
00729 whitespace = true;
00730 ++p;
00731 }
00732 else if ( IsWhiteSpace( *p ) )
00733 {
00734 whitespace = true;
00735 ++p;
00736 }
00737 else
00738 {
00739
00740
00741 if ( whitespace )
00742 {
00743 (*text) += ' ';
00744 whitespace = false;
00745 }
00746 int len;
00747 char cArr[4] = { 0, 0, 0, 0 };
00748 p = GetChar( p, cArr, &len, encoding );
00749 if ( len == 1 )
00750 (*text) += cArr[0];
00751 else
00752 text->append( cArr, len );
00753 }
00754 }
00755 }
00756 if ( p )
00757 p += strlen( endTag );
00758 return p;
00759 }
00760
00761 #ifdef TIXML_USE_STL
00762
00763 void TiXmlDocument::StreamIn( std::istream * in, TIXML_STRING * tag )
00764 {
00765
00766
00767
00768
00769
00770
00771
00772 if ( !StreamTo( in, '<', tag ) )
00773 {
00774 SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
00775 return;
00776 }
00777
00778 while ( in->good() )
00779 {
00780 int tagIndex = (int) tag->length();
00781 while ( in->good() && in->peek() != '>' )
00782 {
00783 int c = in->get();
00784 if ( c <= 0 )
00785 {
00786 SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
00787 break;
00788 }
00789 (*tag) += (char) c;
00790 }
00791
00792 if ( in->good() )
00793 {
00794
00795
00796
00797 TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
00798
00799 if ( node )
00800 {
00801 node->StreamIn( in, tag );
00802 bool isElement = node->ToElement() != 0;
00803 delete node;
00804 node = 0;
00805
00806
00807
00808 if ( isElement )
00809 {
00810 return;
00811 }
00812 }
00813 else
00814 {
00815 SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
00816 return;
00817 }
00818 }
00819 }
00820
00821 SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
00822 }
00823
00824 #endif
00825
00826 const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
00827 {
00828 ClearError();
00829
00830
00831
00832
00833 if ( !p || !*p )
00834 {
00835 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
00836 return 0;
00837 }
00838
00839
00840
00841
00842 location.Clear();
00843 if ( prevData )
00844 {
00845 location.row = prevData->cursor.row;
00846 location.col = prevData->cursor.col;
00847 }
00848 else
00849 {
00850 location.row = 0;
00851 location.col = 0;
00852 }
00853 TiXmlParsingData data( p, TabSize(), location.row, location.col );
00854 location = data.Cursor();
00855
00856 if ( encoding == TIXML_ENCODING_UNKNOWN )
00857 {
00858
00859 const unsigned char* pU = (const unsigned char*)p;
00860 if ( *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
00861 && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
00862 && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
00863 {
00864 encoding = TIXML_ENCODING_UTF8;
00865 useMicrosoftBOM = true;
00866 }
00867 }
00868
00869 p = SkipWhiteSpace( p, encoding );
00870 if ( !p )
00871 {
00872 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
00873 return 0;
00874 }
00875
00876 while ( p && *p )
00877 {
00878 TiXmlNode* node = Identify( p, encoding );
00879 if ( node )
00880 {
00881 p = node->Parse( p, &data, encoding );
00882 LinkEndChild( node );
00883 }
00884 else
00885 {
00886 break;
00887 }
00888
00889
00890 if ( encoding == TIXML_ENCODING_UNKNOWN
00891 && node->ToDeclaration() )
00892 {
00893 TiXmlDeclaration* dec = node->ToDeclaration();
00894 const char* enc = dec->Encoding();
00895 assert( enc );
00896
00897 if ( *enc == 0 )
00898 encoding = TIXML_ENCODING_UTF8;
00899 else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
00900 encoding = TIXML_ENCODING_UTF8;
00901 else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
00902 encoding = TIXML_ENCODING_UTF8;
00903 else
00904 encoding = TIXML_ENCODING_LEGACY;
00905 }
00906
00907 p = SkipWhiteSpace( p, encoding );
00908 }
00909
00910
00911 if ( !firstChild ) {
00912 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
00913 return 0;
00914 }
00915
00916
00917 return p;
00918 }
00919
00920 void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
00921 {
00922
00923 if ( error )
00924 return;
00925
00926 assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
00927 error = true;
00928 errorId = err;
00929 errorDesc = errorString[ errorId ];
00930
00931 errorLocation.Clear();
00932 if ( pError && data )
00933 {
00934 data->Stamp( pError, encoding );
00935 errorLocation = data->Cursor();
00936 }
00937 }
00938
00939
00940 TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
00941 {
00942 TiXmlNode* returnNode = 0;
00943
00944 p = SkipWhiteSpace( p, encoding );
00945 if( !p || !*p || *p != '<' )
00946 {
00947 return 0;
00948 }
00949
00950 TiXmlDocument* doc = GetDocument();
00951 p = SkipWhiteSpace( p, encoding );
00952
00953 if ( !p || !*p )
00954 {
00955 return 0;
00956 }
00957
00958
00959
00960
00961
00962
00963
00964
00965 const char* xmlHeader = { "<?xml" };
00966 const char* commentHeader = { "<!--" };
00967 const char* dtdHeader = { "<!" };
00968 const char* cdataHeader = { "<![CDATA[" };
00969
00970 if ( StringEqual( p, xmlHeader, true, encoding ) )
00971 {
00972 #ifdef DEBUG_PARSER
00973 TIXML_LOG( "XML parsing Declaration\n" );
00974 #endif
00975 returnNode = new TiXmlDeclaration();
00976 }
00977 else if ( StringEqual( p, commentHeader, false, encoding ) )
00978 {
00979 #ifdef DEBUG_PARSER
00980 TIXML_LOG( "XML parsing Comment\n" );
00981 #endif
00982 returnNode = new TiXmlComment();
00983 }
00984 else if ( StringEqual( p, cdataHeader, false, encoding ) )
00985 {
00986 #ifdef DEBUG_PARSER
00987 TIXML_LOG( "XML parsing CDATA\n" );
00988 #endif
00989 TiXmlText* text = new TiXmlText( "" );
00990 text->SetCDATA( true );
00991 returnNode = text;
00992 }
00993 else if ( StringEqual( p, dtdHeader, false, encoding ) )
00994 {
00995 #ifdef DEBUG_PARSER
00996 TIXML_LOG( "XML parsing Unknown(1)\n" );
00997 #endif
00998 returnNode = new TiXmlUnknown();
00999 }
01000 else if ( IsAlpha( *(p+1), encoding )
01001 || *(p+1) == '_' )
01002 {
01003 #ifdef DEBUG_PARSER
01004 TIXML_LOG( "XML parsing Element\n" );
01005 #endif
01006 returnNode = new TiXmlElement( "" );
01007 }
01008 else
01009 {
01010 #ifdef DEBUG_PARSER
01011 TIXML_LOG( "XML parsing Unknown(2)\n" );
01012 #endif
01013 returnNode = new TiXmlUnknown();
01014 }
01015
01016 if ( returnNode )
01017 {
01018
01019 returnNode->parent = this;
01020 }
01021 else
01022 {
01023 if ( doc )
01024 doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
01025 }
01026 return returnNode;
01027 }
01028
01029 #ifdef TIXML_USE_STL
01030
01031 void TiXmlElement::StreamIn (std::istream * in, TIXML_STRING * tag)
01032 {
01033
01034
01035 while( in->good() )
01036 {
01037 int c = in->get();
01038 if ( c <= 0 )
01039 {
01040 TiXmlDocument* document = GetDocument();
01041 if ( document )
01042 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01043 return;
01044 }
01045 (*tag) += (char) c ;
01046
01047 if ( c == '>' )
01048 break;
01049 }
01050
01051 if ( tag->length() < 3 ) return;
01052
01053
01054
01055
01056 if ( tag->at( tag->length() - 1 ) == '>'
01057 && tag->at( tag->length() - 2 ) == '/' )
01058 {
01059
01060 return;
01061 }
01062 else if ( tag->at( tag->length() - 1 ) == '>' )
01063 {
01064
01065
01066
01067
01068
01069 for ( ;; )
01070 {
01071 StreamWhiteSpace( in, tag );
01072
01073
01074 if ( in->good() && in->peek() != '<' )
01075 {
01076
01077 TiXmlText text( "" );
01078 text.StreamIn( in, tag );
01079
01080
01081
01082 continue;
01083 }
01084
01085
01086
01087 if ( !in->good() ) return;
01088 assert( in->peek() == '<' );
01089 int tagIndex = (int) tag->length();
01090
01091 bool closingTag = false;
01092 bool firstCharFound = false;
01093
01094 for( ;; )
01095 {
01096 if ( !in->good() )
01097 return;
01098
01099 int c = in->peek();
01100 if ( c <= 0 )
01101 {
01102 TiXmlDocument* document = GetDocument();
01103 if ( document )
01104 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01105 return;
01106 }
01107
01108 if ( c == '>' )
01109 break;
01110
01111 *tag += (char) c;
01112 in->get();
01113
01114
01115 if ( c == '[' && tag->size() >= 9 )
01116 {
01117 size_t len = tag->size();
01118 const char* start = tag->c_str() + len - 9;
01119 if ( strcmp( start, "<![CDATA[" ) == 0 ) {
01120 assert( !closingTag );
01121 break;
01122 }
01123 }
01124
01125 if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
01126 {
01127 firstCharFound = true;
01128 if ( c == '/' )
01129 closingTag = true;
01130 }
01131 }
01132
01133
01134 if ( closingTag )
01135 {
01136 if ( !in->good() )
01137 return;
01138
01139 int c = in->get();
01140 if ( c <= 0 )
01141 {
01142 TiXmlDocument* document = GetDocument();
01143 if ( document )
01144 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01145 return;
01146 }
01147 assert( c == '>' );
01148 *tag += (char) c;
01149
01150
01151 return;
01152 }
01153 else
01154 {
01155
01156 const char* tagloc = tag->c_str() + tagIndex;
01157 TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
01158 if ( !node )
01159 return;
01160 node->StreamIn( in, tag );
01161 delete node;
01162 node = 0;
01163
01164
01165 }
01166 }
01167 }
01168 }
01169 #endif
01170
01171 const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01172 {
01173 p = SkipWhiteSpace( p, encoding );
01174 TiXmlDocument* document = GetDocument();
01175
01176 if ( !p || !*p )
01177 {
01178 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
01179 return 0;
01180 }
01181
01182 if ( data )
01183 {
01184 data->Stamp( p, encoding );
01185 location = data->Cursor();
01186 }
01187
01188 if ( *p != '<' )
01189 {
01190 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
01191 return 0;
01192 }
01193
01194 p = SkipWhiteSpace( p+1, encoding );
01195
01196
01197 const char* pErr = p;
01198
01199 p = ReadName( p, &value, encoding );
01200 if ( !p || !*p )
01201 {
01202 if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
01203 return 0;
01204 }
01205
01206 TIXML_STRING endTag ("</");
01207 endTag += value;
01208 endTag += ">";
01209
01210
01211
01212 while ( p && *p )
01213 {
01214 pErr = p;
01215 p = SkipWhiteSpace( p, encoding );
01216 if ( !p || !*p )
01217 {
01218 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
01219 return 0;
01220 }
01221 if ( *p == '/' )
01222 {
01223 ++p;
01224
01225 if ( *p != '>' )
01226 {
01227 if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
01228 return 0;
01229 }
01230 return (p+1);
01231 }
01232 else if ( *p == '>' )
01233 {
01234
01235
01236
01237 ++p;
01238 p = ReadValue( p, data, encoding );
01239 if ( !p || !*p ) {
01240
01241
01242 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
01243 return 0;
01244 }
01245
01246
01247 if ( StringEqual( p, endTag.c_str(), false, encoding ) )
01248 {
01249 p += endTag.length();
01250 return p;
01251 }
01252 else
01253 {
01254 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
01255 return 0;
01256 }
01257 }
01258 else
01259 {
01260
01261 TiXmlAttribute* attrib = new TiXmlAttribute();
01262 if ( !attrib )
01263 {
01264 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
01265 return 0;
01266 }
01267
01268 attrib->SetDocument( document );
01269 pErr = p;
01270 p = attrib->Parse( p, data, encoding );
01271
01272 if ( !p || !*p )
01273 {
01274 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
01275 delete attrib;
01276 return 0;
01277 }
01278
01279
01280 #ifdef TIXML_USE_STL
01281 TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
01282 #else
01283 TiXmlAttribute* node = attributeSet.Find( attrib->Name() );
01284 #endif
01285 if ( node )
01286 {
01287 node->SetValue( attrib->Value() );
01288 delete attrib;
01289 return 0;
01290 }
01291
01292 attributeSet.Add( attrib );
01293 }
01294 }
01295 return p;
01296 }
01297
01298
01299 const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01300 {
01301 TiXmlDocument* document = GetDocument();
01302
01303
01304 const char* pWithWhiteSpace = p;
01305 p = SkipWhiteSpace( p, encoding );
01306
01307 while ( p && *p )
01308 {
01309 if ( *p != '<' )
01310 {
01311
01312 TiXmlText* textNode = new TiXmlText( "" );
01313
01314 if ( !textNode )
01315 {
01316 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
01317 return 0;
01318 }
01319
01320 if ( TiXmlBase::IsWhiteSpaceCondensed() )
01321 {
01322 p = textNode->Parse( p, data, encoding );
01323 }
01324 else
01325 {
01326
01327
01328 p = textNode->Parse( pWithWhiteSpace, data, encoding );
01329 }
01330
01331 if ( !textNode->Blank() )
01332 LinkEndChild( textNode );
01333 else
01334 delete textNode;
01335 }
01336 else
01337 {
01338
01339
01340
01341 if ( StringEqual( p, "</", false, encoding ) )
01342 {
01343 return p;
01344 }
01345 else
01346 {
01347 TiXmlNode* node = Identify( p, encoding );
01348 if ( node )
01349 {
01350 p = node->Parse( p, data, encoding );
01351 LinkEndChild( node );
01352 }
01353 else
01354 {
01355 return 0;
01356 }
01357 }
01358 }
01359 pWithWhiteSpace = p;
01360 p = SkipWhiteSpace( p, encoding );
01361 }
01362
01363 if ( !p )
01364 {
01365 if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
01366 }
01367 return p;
01368 }
01369
01370
01371 #ifdef TIXML_USE_STL
01372 void TiXmlUnknown::StreamIn( std::istream * in, TIXML_STRING * tag )
01373 {
01374 while ( in->good() )
01375 {
01376 int c = in->get();
01377 if ( c <= 0 )
01378 {
01379 TiXmlDocument* document = GetDocument();
01380 if ( document )
01381 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01382 return;
01383 }
01384 (*tag) += (char) c;
01385
01386 if ( c == '>' )
01387 {
01388
01389 return;
01390 }
01391 }
01392 }
01393 #endif
01394
01395
01396 const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01397 {
01398 TiXmlDocument* document = GetDocument();
01399 p = SkipWhiteSpace( p, encoding );
01400
01401 if ( data )
01402 {
01403 data->Stamp( p, encoding );
01404 location = data->Cursor();
01405 }
01406 if ( !p || !*p || *p != '<' )
01407 {
01408 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
01409 return 0;
01410 }
01411 ++p;
01412 value = "";
01413
01414 while ( p && *p && *p != '>' )
01415 {
01416 value += *p;
01417 ++p;
01418 }
01419
01420 if ( !p )
01421 {
01422 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
01423 }
01424 if ( *p == '>' )
01425 return p+1;
01426 return p;
01427 }
01428
01429 #ifdef TIXML_USE_STL
01430 void TiXmlComment::StreamIn( std::istream * in, TIXML_STRING * tag )
01431 {
01432 while ( in->good() )
01433 {
01434 int c = in->get();
01435 if ( c <= 0 )
01436 {
01437 TiXmlDocument* document = GetDocument();
01438 if ( document )
01439 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01440 return;
01441 }
01442
01443 (*tag) += (char) c;
01444
01445 if ( c == '>'
01446 && tag->at( tag->length() - 2 ) == '-'
01447 && tag->at( tag->length() - 3 ) == '-' )
01448 {
01449
01450 return;
01451 }
01452 }
01453 }
01454 #endif
01455
01456
01457 const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01458 {
01459 TiXmlDocument* document = GetDocument();
01460 value = "";
01461
01462 p = SkipWhiteSpace( p, encoding );
01463
01464 if ( data )
01465 {
01466 data->Stamp( p, encoding );
01467 location = data->Cursor();
01468 }
01469 const char* startTag = "<!--";
01470 const char* endTag = "-->";
01471
01472 if ( !StringEqual( p, startTag, false, encoding ) )
01473 {
01474 document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
01475 return 0;
01476 }
01477 p += strlen( startTag );
01478
01479
01480
01481
01482
01483
01484
01485
01486
01487
01488
01489
01490
01491
01492
01493
01494
01495
01496
01497 value = "";
01498
01499 while ( p && *p && !StringEqual( p, endTag, false, encoding ) )
01500 {
01501 value.append( p, 1 );
01502 ++p;
01503 }
01504 if ( p )
01505 p += strlen( endTag );
01506
01507 return p;
01508 }
01509
01510
01511 const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01512 {
01513 p = SkipWhiteSpace( p, encoding );
01514 if ( !p || !*p ) return 0;
01515
01516
01517
01518
01519
01520 if ( data )
01521 {
01522 data->Stamp( p, encoding );
01523 location = data->Cursor();
01524 }
01525
01526 const char* pErr = p;
01527 p = ReadName( p, &name, encoding );
01528 if ( !p || !*p )
01529 {
01530 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
01531 return 0;
01532 }
01533 p = SkipWhiteSpace( p, encoding );
01534 if ( !p || !*p || *p != '=' )
01535 {
01536 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
01537 return 0;
01538 }
01539
01540 ++p;
01541 p = SkipWhiteSpace( p, encoding );
01542 if ( !p || !*p )
01543 {
01544 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
01545 return 0;
01546 }
01547
01548 const char* end;
01549 const char SINGLE_QUOTE = '\'';
01550 const char DOUBLE_QUOTE = '\"';
01551
01552 if ( *p == SINGLE_QUOTE )
01553 {
01554 ++p;
01555 end = "\'";
01556 p = ReadText( p, &value, false, end, false, encoding );
01557 }
01558 else if ( *p == DOUBLE_QUOTE )
01559 {
01560 ++p;
01561 end = "\"";
01562 p = ReadText( p, &value, false, end, false, encoding );
01563 }
01564 else
01565 {
01566
01567
01568
01569 value = "";
01570 while ( p && *p
01571 && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r'
01572 && *p != '/' && *p != '>' )
01573 {
01574 if ( *p == SINGLE_QUOTE || *p == DOUBLE_QUOTE ) {
01575
01576
01577
01578 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
01579 return 0;
01580 }
01581 value += *p;
01582 ++p;
01583 }
01584 }
01585 return p;
01586 }
01587
01588 #ifdef TIXML_USE_STL
01589 void TiXmlText::StreamIn( std::istream * in, TIXML_STRING * tag )
01590 {
01591 while ( in->good() )
01592 {
01593 int c = in->peek();
01594 if ( !cdata && (c == '<' ) )
01595 {
01596 return;
01597 }
01598 if ( c <= 0 )
01599 {
01600 TiXmlDocument* document = GetDocument();
01601 if ( document )
01602 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01603 return;
01604 }
01605
01606 (*tag) += (char) c;
01607 in->get();
01608
01609 if ( cdata && c == '>' && tag->size() >= 3 ) {
01610 size_t len = tag->size();
01611 if ( (*tag)[len-2] == ']' && (*tag)[len-3] == ']' ) {
01612
01613 return;
01614 }
01615 }
01616 }
01617 }
01618 #endif
01619
01620 const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01621 {
01622 value = "";
01623 TiXmlDocument* document = GetDocument();
01624
01625 if ( data )
01626 {
01627 data->Stamp( p, encoding );
01628 location = data->Cursor();
01629 }
01630
01631 const char* const startTag = "<![CDATA[";
01632 const char* const endTag = "]]>";
01633
01634 if ( cdata || StringEqual( p, startTag, false, encoding ) )
01635 {
01636 cdata = true;
01637
01638 if ( !StringEqual( p, startTag, false, encoding ) )
01639 {
01640 document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
01641 return 0;
01642 }
01643 p += strlen( startTag );
01644
01645
01646 while ( p && *p
01647 && !StringEqual( p, endTag, false, encoding )
01648 )
01649 {
01650 value += *p;
01651 ++p;
01652 }
01653
01654 TIXML_STRING dummy;
01655 p = ReadText( p, &dummy, false, endTag, false, encoding );
01656 return p;
01657 }
01658 else
01659 {
01660 bool ignoreWhite = true;
01661
01662 const char* end = "<";
01663 p = ReadText( p, &value, ignoreWhite, end, false, encoding );
01664 if ( p )
01665 return p-1;
01666 return 0;
01667 }
01668 }
01669
01670 #ifdef TIXML_USE_STL
01671 void TiXmlDeclaration::StreamIn( std::istream * in, TIXML_STRING * tag )
01672 {
01673 while ( in->good() )
01674 {
01675 int c = in->get();
01676 if ( c <= 0 )
01677 {
01678 TiXmlDocument* document = GetDocument();
01679 if ( document )
01680 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01681 return;
01682 }
01683 (*tag) += (char) c;
01684
01685 if ( c == '>' )
01686 {
01687
01688 return;
01689 }
01690 }
01691 }
01692 #endif
01693
01694 const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
01695 {
01696 p = SkipWhiteSpace( p, _encoding );
01697
01698
01699 TiXmlDocument* document = GetDocument();
01700 if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
01701 {
01702 if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
01703 return 0;
01704 }
01705 if ( data )
01706 {
01707 data->Stamp( p, _encoding );
01708 location = data->Cursor();
01709 }
01710 p += 5;
01711
01712 version = "";
01713 encoding = "";
01714 standalone = "";
01715
01716 while ( p && *p )
01717 {
01718 if ( *p == '>' )
01719 {
01720 ++p;
01721 return p;
01722 }
01723
01724 p = SkipWhiteSpace( p, _encoding );
01725 if ( StringEqual( p, "version", true, _encoding ) )
01726 {
01727 TiXmlAttribute attrib;
01728 p = attrib.Parse( p, data, _encoding );
01729 version = attrib.Value();
01730 }
01731 else if ( StringEqual( p, "encoding", true, _encoding ) )
01732 {
01733 TiXmlAttribute attrib;
01734 p = attrib.Parse( p, data, _encoding );
01735 encoding = attrib.Value();
01736 }
01737 else if ( StringEqual( p, "standalone", true, _encoding ) )
01738 {
01739 TiXmlAttribute attrib;
01740 p = attrib.Parse( p, data, _encoding );
01741 standalone = attrib.Value();
01742 }
01743 else
01744 {
01745
01746 while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
01747 ++p;
01748 }
01749 }
01750 return 0;
01751 }
01752
01753 bool TiXmlText::Blank() const
01754 {
01755 for ( unsigned i=0; i<value.length(); i++ )
01756 if ( !IsWhiteSpace( value[i] ) )
01757 return false;
01758 return true;
01759 }
01760
01761
01762
01763 bool TiXmlBase::condenseWhiteSpace = true;
01764
01765
01766 FILE* TiXmlFOpen( const char* filename, const char* mode )
01767 {
01768 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
01769 FILE* fp = 0;
01770 errno_t err = fopen_s( &fp, filename, mode );
01771 if ( !err && fp )
01772 return fp;
01773 return 0;
01774 #else
01775 return fopen( filename, mode );
01776 #endif
01777 }
01778
01779 void TiXmlBase::EncodeString( const TIXML_STRING& str, TIXML_STRING* outString )
01780 {
01781 int i=0;
01782
01783 while( i<(int)str.length() )
01784 {
01785 unsigned char c = (unsigned char) str[i];
01786
01787 if ( c == '&'
01788 && i < ( (int)str.length() - 2 )
01789 && str[i+1] == '#'
01790 && str[i+2] == 'x' )
01791 {
01792
01793
01794
01795
01796
01797
01798
01799
01800
01801
01802 while ( i<(int)str.length()-1 )
01803 {
01804 outString->append( str.c_str() + i, 1 );
01805 ++i;
01806 if ( str[i] == ';' )
01807 break;
01808 }
01809 }
01810 else if ( c == '&' )
01811 {
01812 outString->append( entity[0].str, entity[0].strLength );
01813 ++i;
01814 }
01815 else if ( c == '<' )
01816 {
01817 outString->append( entity[1].str, entity[1].strLength );
01818 ++i;
01819 }
01820 else if ( c == '>' )
01821 {
01822 outString->append( entity[2].str, entity[2].strLength );
01823 ++i;
01824 }
01825 else if ( c == '\"' )
01826 {
01827 outString->append( entity[3].str, entity[3].strLength );
01828 ++i;
01829 }
01830 else if ( c == '\'' )
01831 {
01832 outString->append( entity[4].str, entity[4].strLength );
01833 ++i;
01834 }
01835 else if ( c < 32 )
01836 {
01837
01838
01839 char buf[ 32 ];
01840
01841 #if defined(TIXML_SNPRINTF)
01842 TIXML_SNPRINTF( buf, sizeof(buf), "&#x%02X;", (unsigned) ( c & 0xff ) );
01843 #else
01844 sprintf( buf, "&#x%02X;", (unsigned) ( c & 0xff ) );
01845 #endif
01846
01847
01848
01849 outString->append( buf, (int)strlen( buf ) );
01850 ++i;
01851 }
01852 else
01853 {
01854
01855
01856 *outString += (char) c;
01857 ++i;
01858 }
01859 }
01860 }
01861
01862
01863 TiXmlNode::TiXmlNode( NodeType _type ) : TiXmlBase()
01864 {
01865 parent = 0;
01866 type = _type;
01867 firstChild = 0;
01868 lastChild = 0;
01869 prev = 0;
01870 next = 0;
01871 }
01872
01873
01874 TiXmlNode::~TiXmlNode()
01875 {
01876 TiXmlNode* node = firstChild;
01877 TiXmlNode* temp = 0;
01878
01879 while ( node )
01880 {
01881 temp = node;
01882 node = node->next;
01883 delete temp;
01884 }
01885 }
01886
01887
01888 void TiXmlNode::CopyTo( TiXmlNode* target ) const
01889 {
01890 target->SetValue (value.c_str() );
01891 target->userData = userData;
01892 }
01893
01894
01895 void TiXmlNode::Clear()
01896 {
01897 TiXmlNode* node = firstChild;
01898 TiXmlNode* temp = 0;
01899
01900 while ( node )
01901 {
01902 temp = node;
01903 node = node->next;
01904 delete temp;
01905 }
01906
01907 firstChild = 0;
01908 lastChild = 0;
01909 }
01910
01911
01912 TiXmlNode* TiXmlNode::LinkEndChild( TiXmlNode* node )
01913 {
01914 assert( node->parent == 0 || node->parent == this );
01915 assert( node->GetDocument() == 0 || node->GetDocument() == this->GetDocument() );
01916
01917 if ( node->Type() == TiXmlNode::DOCUMENT )
01918 {
01919 delete node;
01920 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
01921 return 0;
01922 }
01923
01924 node->parent = this;
01925
01926 node->prev = lastChild;
01927 node->next = 0;
01928
01929 if ( lastChild )
01930 lastChild->next = node;
01931 else
01932 firstChild = node;
01933
01934 lastChild = node;
01935 return node;
01936 }
01937
01938
01939 TiXmlNode* TiXmlNode::InsertEndChild( const TiXmlNode& addThis )
01940 {
01941 if ( addThis.Type() == TiXmlNode::DOCUMENT )
01942 {
01943 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
01944 return 0;
01945 }
01946 TiXmlNode* node = addThis.Clone();
01947 if ( !node )
01948 return 0;
01949
01950 return LinkEndChild( node );
01951 }
01952
01953
01954 TiXmlNode* TiXmlNode::InsertBeforeChild( TiXmlNode* beforeThis, const TiXmlNode& addThis )
01955 {
01956 if ( !beforeThis || beforeThis->parent != this ) {
01957 return 0;
01958 }
01959 if ( addThis.Type() == TiXmlNode::DOCUMENT )
01960 {
01961 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
01962 return 0;
01963 }
01964
01965 TiXmlNode* node = addThis.Clone();
01966 if ( !node )
01967 return 0;
01968 node->parent = this;
01969
01970 node->next = beforeThis;
01971 node->prev = beforeThis->prev;
01972 if ( beforeThis->prev )
01973 {
01974 beforeThis->prev->next = node;
01975 }
01976 else
01977 {
01978 assert( firstChild == beforeThis );
01979 firstChild = node;
01980 }
01981 beforeThis->prev = node;
01982 return node;
01983 }
01984
01985
01986 TiXmlNode* TiXmlNode::InsertAfterChild( TiXmlNode* afterThis, const TiXmlNode& addThis )
01987 {
01988 if ( !afterThis || afterThis->parent != this ) {
01989 return 0;
01990 }
01991 if ( addThis.Type() == TiXmlNode::DOCUMENT )
01992 {
01993 if ( GetDocument() ) GetDocument()->SetError( TIXML_ERROR_DOCUMENT_TOP_ONLY, 0, 0, TIXML_ENCODING_UNKNOWN );
01994 return 0;
01995 }
01996
01997 TiXmlNode* node = addThis.Clone();
01998 if ( !node )
01999 return 0;
02000 node->parent = this;
02001
02002 node->prev = afterThis;
02003 node->next = afterThis->next;
02004 if ( afterThis->next )
02005 {
02006 afterThis->next->prev = node;
02007 }
02008 else
02009 {
02010 assert( lastChild == afterThis );
02011 lastChild = node;
02012 }
02013 afterThis->next = node;
02014 return node;
02015 }
02016
02017
02018 TiXmlNode* TiXmlNode::ReplaceChild( TiXmlNode* replaceThis, const TiXmlNode& withThis )
02019 {
02020 if ( replaceThis->parent != this )
02021 return 0;
02022
02023 TiXmlNode* node = withThis.Clone();
02024 if ( !node )
02025 return 0;
02026
02027 node->next = replaceThis->next;
02028 node->prev = replaceThis->prev;
02029
02030 if ( replaceThis->next )
02031 replaceThis->next->prev = node;
02032 else
02033 lastChild = node;
02034
02035 if ( replaceThis->prev )
02036 replaceThis->prev->next = node;
02037 else
02038 firstChild = node;
02039
02040 delete replaceThis;
02041 node->parent = this;
02042 return node;
02043 }
02044
02045
02046 bool TiXmlNode::RemoveChild( TiXmlNode* removeThis )
02047 {
02048 if ( removeThis->parent != this )
02049 {
02050 assert( 0 );
02051 return false;
02052 }
02053
02054 if ( removeThis->next )
02055 removeThis->next->prev = removeThis->prev;
02056 else
02057 lastChild = removeThis->prev;
02058
02059 if ( removeThis->prev )
02060 removeThis->prev->next = removeThis->next;
02061 else
02062 firstChild = removeThis->next;
02063
02064 delete removeThis;
02065 return true;
02066 }
02067
02068 const TiXmlNode* TiXmlNode::FirstChild( const char * _value ) const
02069 {
02070 const TiXmlNode* node;
02071 for ( node = firstChild; node; node = node->next )
02072 {
02073 if ( strcmp( node->Value(), _value ) == 0 )
02074 return node;
02075 }
02076 return 0;
02077 }
02078
02079
02080 const TiXmlNode* TiXmlNode::LastChild( const char * _value ) const
02081 {
02082 const TiXmlNode* node;
02083 for ( node = lastChild; node; node = node->prev )
02084 {
02085 if ( strcmp( node->Value(), _value ) == 0 )
02086 return node;
02087 }
02088 return 0;
02089 }
02090
02091
02092 const TiXmlNode* TiXmlNode::IterateChildren( const TiXmlNode* previous ) const
02093 {
02094 if ( !previous )
02095 {
02096 return FirstChild();
02097 }
02098 else
02099 {
02100 assert( previous->parent == this );
02101 return previous->NextSibling();
02102 }
02103 }
02104
02105
02106 const TiXmlNode* TiXmlNode::IterateChildren( const char * val, const TiXmlNode* previous ) const
02107 {
02108 if ( !previous )
02109 {
02110 return FirstChild( val );
02111 }
02112 else
02113 {
02114 assert( previous->parent == this );
02115 return previous->NextSibling( val );
02116 }
02117 }
02118
02119
02120 const TiXmlNode* TiXmlNode::NextSibling( const char * _value ) const
02121 {
02122 const TiXmlNode* node;
02123 for ( node = next; node; node = node->next )
02124 {
02125 if ( strcmp( node->Value(), _value ) == 0 )
02126 return node;
02127 }
02128 return 0;
02129 }
02130
02131
02132 const TiXmlNode* TiXmlNode::PreviousSibling( const char * _value ) const
02133 {
02134 const TiXmlNode* node;
02135 for ( node = prev; node; node = node->prev )
02136 {
02137 if ( strcmp( node->Value(), _value ) == 0 )
02138 return node;
02139 }
02140 return 0;
02141 }
02142
02143
02144 void TiXmlElement::RemoveAttribute( const char * name )
02145 {
02146 #ifdef TIXML_USE_STL
02147 TIXML_STRING str( name );
02148 TiXmlAttribute* node = attributeSet.Find( str );
02149 #else
02150 TiXmlAttribute* node = attributeSet.Find( name );
02151 #endif
02152 if ( node )
02153 {
02154 attributeSet.Remove( node );
02155 delete node;
02156 }
02157 }
02158
02159 const TiXmlElement* TiXmlNode::FirstChildElement() const
02160 {
02161 const TiXmlNode* node;
02162
02163 for ( node = FirstChild();
02164 node;
02165 node = node->NextSibling() )
02166 {
02167 if ( node->ToElement() )
02168 return node->ToElement();
02169 }
02170 return 0;
02171 }
02172
02173
02174 const TiXmlElement* TiXmlNode::FirstChildElement( const char * _value ) const
02175 {
02176 const TiXmlNode* node;
02177
02178 for ( node = FirstChild( _value );
02179 node;
02180 node = node->NextSibling( _value ) )
02181 {
02182 if ( node->ToElement() )
02183 return node->ToElement();
02184 }
02185 return 0;
02186 }
02187
02188
02189 const TiXmlElement* TiXmlNode::NextSiblingElement() const
02190 {
02191 const TiXmlNode* node;
02192
02193 for ( node = NextSibling();
02194 node;
02195 node = node->NextSibling() )
02196 {
02197 if ( node->ToElement() )
02198 return node->ToElement();
02199 }
02200 return 0;
02201 }
02202
02203
02204 const TiXmlElement* TiXmlNode::NextSiblingElement( const char * _value ) const
02205 {
02206 const TiXmlNode* node;
02207
02208 for ( node = NextSibling( _value );
02209 node;
02210 node = node->NextSibling( _value ) )
02211 {
02212 if ( node->ToElement() )
02213 return node->ToElement();
02214 }
02215 return 0;
02216 }
02217
02218
02219 const TiXmlDocument* TiXmlNode::GetDocument() const
02220 {
02221 const TiXmlNode* node;
02222
02223 for( node = this; node; node = node->parent )
02224 {
02225 if ( node->ToDocument() )
02226 return node->ToDocument();
02227 }
02228 return 0;
02229 }
02230
02231
02232 TiXmlElement::TiXmlElement (const char * _value)
02233 : TiXmlNode( TiXmlNode::ELEMENT )
02234 {
02235 firstChild = lastChild = 0;
02236 value = _value;
02237 }
02238
02239
02240 #ifdef TIXML_USE_STL
02241 TiXmlElement::TiXmlElement( const std::string& _value )
02242 : TiXmlNode( TiXmlNode::ELEMENT )
02243 {
02244 firstChild = lastChild = 0;
02245 value = _value;
02246 }
02247 #endif
02248
02249
02250 TiXmlElement::TiXmlElement( const TiXmlElement& copy)
02251 : TiXmlNode( TiXmlNode::ELEMENT )
02252 {
02253 firstChild = lastChild = 0;
02254 copy.CopyTo( this );
02255 }
02256
02257
02258 void TiXmlElement::operator=( const TiXmlElement& base )
02259 {
02260 ClearThis();
02261 base.CopyTo( this );
02262 }
02263
02264
02265 TiXmlElement::~TiXmlElement()
02266 {
02267 ClearThis();
02268 }
02269
02270
02271 void TiXmlElement::ClearThis()
02272 {
02273 Clear();
02274 while( attributeSet.First() )
02275 {
02276 TiXmlAttribute* node = attributeSet.First();
02277 attributeSet.Remove( node );
02278 delete node;
02279 }
02280 }
02281
02282
02283 const char* TiXmlElement::Attribute( const char* name ) const
02284 {
02285 const TiXmlAttribute* node = attributeSet.Find( name );
02286 if ( node )
02287 return node->Value();
02288 return 0;
02289 }
02290
02291
02292 #ifdef TIXML_USE_STL
02293 const std::string* TiXmlElement::Attribute( const std::string& name ) const
02294 {
02295 const TiXmlAttribute* node = attributeSet.Find( name );
02296 if ( node )
02297 return &node->ValueStr();
02298 return 0;
02299 }
02300 #endif
02301
02302
02303 const char* TiXmlElement::Attribute( const char* name, int* i ) const
02304 {
02305 const char* s = Attribute( name );
02306 if ( i )
02307 {
02308 if ( s ) {
02309 *i = atoi( s );
02310 }
02311 else {
02312 *i = 0;
02313 }
02314 }
02315 return s;
02316 }
02317
02318
02319 #ifdef TIXML_USE_STL
02320 const std::string* TiXmlElement::Attribute( const std::string& name, int* i ) const
02321 {
02322 const std::string* s = Attribute( name );
02323 if ( i )
02324 {
02325 if ( s ) {
02326 *i = atoi( s->c_str() );
02327 }
02328 else {
02329 *i = 0;
02330 }
02331 }
02332 return s;
02333 }
02334 #endif
02335
02336
02337 const char* TiXmlElement::Attribute( const char* name, double* d ) const
02338 {
02339 const char* s = Attribute( name );
02340 if ( d )
02341 {
02342 if ( s ) {
02343 *d = atof( s );
02344 }
02345 else {
02346 *d = 0;
02347 }
02348 }
02349 return s;
02350 }
02351
02352
02353 #ifdef TIXML_USE_STL
02354 const std::string* TiXmlElement::Attribute( const std::string& name, double* d ) const
02355 {
02356 const std::string* s = Attribute( name );
02357 if ( d )
02358 {
02359 if ( s ) {
02360 *d = atof( s->c_str() );
02361 }
02362 else {
02363 *d = 0;
02364 }
02365 }
02366 return s;
02367 }
02368 #endif
02369
02370
02371 int TiXmlElement::QueryIntAttribute( const char* name, int* ival ) const
02372 {
02373 const TiXmlAttribute* node = attributeSet.Find( name );
02374 if ( !node )
02375 return TIXML_NO_ATTRIBUTE;
02376 return node->QueryIntValue( ival );
02377 }
02378
02379
02380 #ifdef TIXML_USE_STL
02381 int TiXmlElement::QueryIntAttribute( const std::string& name, int* ival ) const
02382 {
02383 const TiXmlAttribute* node = attributeSet.Find( name );
02384 if ( !node )
02385 return TIXML_NO_ATTRIBUTE;
02386 return node->QueryIntValue( ival );
02387 }
02388 #endif
02389
02390
02391 int TiXmlElement::QueryDoubleAttribute( const char* name, double* dval ) const
02392 {
02393 const TiXmlAttribute* node = attributeSet.Find( name );
02394 if ( !node )
02395 return TIXML_NO_ATTRIBUTE;
02396 return node->QueryDoubleValue( dval );
02397 }
02398
02399
02400 #ifdef TIXML_USE_STL
02401 int TiXmlElement::QueryDoubleAttribute( const std::string& name, double* dval ) const
02402 {
02403 const TiXmlAttribute* node = attributeSet.Find( name );
02404 if ( !node )
02405 return TIXML_NO_ATTRIBUTE;
02406 return node->QueryDoubleValue( dval );
02407 }
02408 #endif
02409
02410
02411 void TiXmlElement::SetAttribute( const char * name, int val )
02412 {
02413 char buf[64];
02414 #if defined(TIXML_SNPRINTF)
02415 TIXML_SNPRINTF( buf, sizeof(buf), "%d", val );
02416 #else
02417 sprintf( buf, "%d", val );
02418 #endif
02419 SetAttribute( name, buf );
02420 }
02421
02422
02423 #ifdef TIXML_USE_STL
02424 void TiXmlElement::SetAttribute( const std::string& name, int val )
02425 {
02426 std::ostringstream oss;
02427 oss << val;
02428 SetAttribute( name, oss.str() );
02429 }
02430 #endif
02431
02432
02433 void TiXmlElement::SetDoubleAttribute( const char * name, double val )
02434 {
02435 char buf[256];
02436 #if defined(TIXML_SNPRINTF)
02437 TIXML_SNPRINTF( buf, sizeof(buf), "%f", val );
02438 #else
02439 sprintf( buf, "%f", val );
02440 #endif
02441 SetAttribute( name, buf );
02442 }
02443
02444
02445 void TiXmlElement::SetAttribute( const char * cname, const char * cvalue )
02446 {
02447 #ifdef TIXML_USE_STL
02448 TIXML_STRING _name( cname );
02449 TIXML_STRING _value( cvalue );
02450 #else
02451 const char* _name = cname;
02452 const char* _value = cvalue;
02453 #endif
02454
02455 TiXmlAttribute* node = attributeSet.Find( _name );
02456 if ( node )
02457 {
02458 node->SetValue( _value );
02459 return;
02460 }
02461
02462 TiXmlAttribute* attrib = new TiXmlAttribute( cname, cvalue );
02463 if ( attrib )
02464 {
02465 attributeSet.Add( attrib );
02466 }
02467 else
02468 {
02469 TiXmlDocument* document = GetDocument();
02470 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
02471 }
02472 }
02473
02474
02475 #ifdef TIXML_USE_STL
02476 void TiXmlElement::SetAttribute( const std::string& name, const std::string& _value )
02477 {
02478 TiXmlAttribute* node = attributeSet.Find( name );
02479 if ( node )
02480 {
02481 node->SetValue( _value );
02482 return;
02483 }
02484
02485 TiXmlAttribute* attrib = new TiXmlAttribute( name, _value );
02486 if ( attrib )
02487 {
02488 attributeSet.Add( attrib );
02489 }
02490 else
02491 {
02492 TiXmlDocument* document = GetDocument();
02493 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
02494 }
02495 }
02496 #endif
02497
02498
02499 void TiXmlElement::Print( FILE* cfile, int depth ) const
02500 {
02501 int i;
02502 assert( cfile );
02503 for ( i=0; i<depth; i++ ) {
02504 fprintf( cfile, " " );
02505 }
02506
02507 fprintf( cfile, "<%s", value.c_str() );
02508
02509 const TiXmlAttribute* attrib;
02510 for ( attrib = attributeSet.First(); attrib; attrib = attrib->Next() )
02511 {
02512 fprintf( cfile, " " );
02513 attrib->Print( cfile, depth );
02514 }
02515
02516
02517
02518
02519
02520 TiXmlNode* node;
02521 if ( !firstChild )
02522 {
02523 fprintf( cfile, " />" );
02524 }
02525 else if ( firstChild == lastChild && firstChild->ToText() )
02526 {
02527 fprintf( cfile, ">" );
02528 firstChild->Print( cfile, depth + 1 );
02529 fprintf( cfile, "</%s>", value.c_str() );
02530 }
02531 else
02532 {
02533 fprintf( cfile, ">" );
02534
02535 for ( node = firstChild; node; node=node->NextSibling() )
02536 {
02537 if ( !node->ToText() )
02538 {
02539 fprintf( cfile, "\n" );
02540 }
02541 node->Print( cfile, depth+1 );
02542 }
02543 fprintf( cfile, "\n" );
02544 for( i=0; i<depth; ++i ) {
02545 fprintf( cfile, " " );
02546 }
02547 fprintf( cfile, "</%s>", value.c_str() );
02548 }
02549 }
02550
02551
02552 void TiXmlElement::CopyTo( TiXmlElement* target ) const
02553 {
02554
02555 TiXmlNode::CopyTo( target );
02556
02557
02558
02559 const TiXmlAttribute* attribute = 0;
02560 for( attribute = attributeSet.First();
02561 attribute;
02562 attribute = attribute->Next() )
02563 {
02564 target->SetAttribute( attribute->Name(), attribute->Value() );
02565 }
02566
02567 TiXmlNode* node = 0;
02568 for ( node = firstChild; node; node = node->NextSibling() )
02569 {
02570 target->LinkEndChild( node->Clone() );
02571 }
02572 }
02573
02574 bool TiXmlElement::Accept( TiXmlVisitor* visitor ) const
02575 {
02576 if ( visitor->VisitEnter( *this, attributeSet.First() ) )
02577 {
02578 for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
02579 {
02580 if ( !node->Accept( visitor ) )
02581 break;
02582 }
02583 }
02584 return visitor->VisitExit( *this );
02585 }
02586
02587
02588 TiXmlNode* TiXmlElement::Clone() const
02589 {
02590 TiXmlElement* clone = new TiXmlElement( Value() );
02591 if ( !clone )
02592 return 0;
02593
02594 CopyTo( clone );
02595 return clone;
02596 }
02597
02598
02599 const char* TiXmlElement::GetText() const
02600 {
02601 const TiXmlNode* child = this->FirstChild();
02602 if ( child ) {
02603 const TiXmlText* childText = child->ToText();
02604 if ( childText ) {
02605 return childText->Value();
02606 }
02607 }
02608 return 0;
02609 }
02610
02611
02612 TiXmlDocument::TiXmlDocument() : TiXmlNode( TiXmlNode::DOCUMENT )
02613 {
02614 tabsize = 4;
02615 useMicrosoftBOM = false;
02616 ClearError();
02617 }
02618
02619 TiXmlDocument::TiXmlDocument( const char * documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
02620 {
02621 tabsize = 4;
02622 useMicrosoftBOM = false;
02623 value = documentName;
02624 ClearError();
02625 }
02626
02627
02628 #ifdef TIXML_USE_STL
02629 TiXmlDocument::TiXmlDocument( const std::string& documentName ) : TiXmlNode( TiXmlNode::DOCUMENT )
02630 {
02631 tabsize = 4;
02632 useMicrosoftBOM = false;
02633 value = documentName;
02634 ClearError();
02635 }
02636 #endif
02637
02638
02639 TiXmlDocument::TiXmlDocument( const TiXmlDocument& copy ) : TiXmlNode( TiXmlNode::DOCUMENT )
02640 {
02641 copy.CopyTo( this );
02642 }
02643
02644
02645 void TiXmlDocument::operator=( const TiXmlDocument& copy )
02646 {
02647 Clear();
02648 copy.CopyTo( this );
02649 }
02650
02651
02652 bool TiXmlDocument::LoadFile( TiXmlEncoding encoding )
02653 {
02654
02655
02656
02657 return LoadFile( Value(), encoding );
02658 }
02659
02660
02661 bool TiXmlDocument::SaveFile() const
02662 {
02663
02664
02665
02666
02667
02668
02669
02670 return SaveFile( Value() );
02671 }
02672
02673 bool TiXmlDocument::LoadFile( const char* _filename, TiXmlEncoding encoding )
02674 {
02675
02676
02677
02678
02679
02680
02681
02682 TIXML_STRING filename( _filename );
02683 value = filename;
02684
02685
02686 FILE* file = TiXmlFOpen( value.c_str (), "rb" );
02687
02688 if ( file )
02689 {
02690 bool result = LoadFile( file, encoding );
02691 fclose( file );
02692 return result;
02693 }
02694 else
02695 {
02696 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
02697 return false;
02698 }
02699 }
02700
02701 bool TiXmlDocument::LoadFile( FILE* file, TiXmlEncoding encoding )
02702 {
02703 if ( !file )
02704 {
02705 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
02706 return false;
02707 }
02708
02709
02710 Clear();
02711 location.Clear();
02712
02713
02714 long length = 0;
02715 fseek( file, 0, SEEK_END );
02716 length = ftell( file );
02717 fseek( file, 0, SEEK_SET );
02718
02719
02720 if ( length <= 0 )
02721 {
02722 SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
02723 return false;
02724 }
02725
02726
02727
02728 TIXML_STRING data;
02729 data.reserve( length );
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743
02744
02745
02746
02747
02748
02749
02750
02751
02752 char* buf = new char[ length+1 ];
02753 buf[0] = 0;
02754
02755 if ( fread( buf, length, 1, file ) != 1 ) {
02756 delete [] buf;
02757 SetError( TIXML_ERROR_OPENING_FILE, 0, 0, TIXML_ENCODING_UNKNOWN );
02758 return false;
02759 }
02760
02761 const char* lastPos = buf;
02762 const char* p = buf;
02763
02764 buf[length] = 0;
02765 while( *p ) {
02766 assert( p < (buf+length) );
02767 if ( *p == 0xa ) {
02768
02769
02770 data.append( lastPos, (p-lastPos+1) );
02771 ++p;
02772 lastPos = p;
02773 assert( p <= (buf+length) );
02774 }
02775 else if ( *p == 0xd ) {
02776
02777
02778 if ( (p-lastPos) > 0 ) {
02779 data.append( lastPos, p-lastPos );
02780 }
02781 data += (char)0xa;
02782
02783 if ( *(p+1) == 0xa ) {
02784
02785 p += 2;
02786 lastPos = p;
02787 assert( p <= (buf+length) );
02788 }
02789 else {
02790
02791 ++p;
02792 lastPos = p;
02793 assert( p <= (buf+length) );
02794 }
02795 }
02796 else {
02797 ++p;
02798 }
02799 }
02800
02801 if ( p-lastPos ) {
02802 data.append( lastPos, p-lastPos );
02803 }
02804 delete [] buf;
02805 buf = 0;
02806
02807 Parse( data.c_str(), 0, encoding );
02808
02809 if ( Error() )
02810 return false;
02811 else
02812 return true;
02813 }
02814
02815
02816 bool TiXmlDocument::SaveFile( const char * filename ) const
02817 {
02818
02819 FILE* fp = TiXmlFOpen( filename, "w" );
02820 if ( fp )
02821 {
02822 bool result = SaveFile( fp );
02823 fclose( fp );
02824 return result;
02825 }
02826 return false;
02827 }
02828
02829
02830 bool TiXmlDocument::SaveFile( FILE* fp ) const
02831 {
02832 if ( useMicrosoftBOM )
02833 {
02834 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
02835 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
02836 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
02837
02838 fputc( TIXML_UTF_LEAD_0, fp );
02839 fputc( TIXML_UTF_LEAD_1, fp );
02840 fputc( TIXML_UTF_LEAD_2, fp );
02841 }
02842 Print( fp, 0 );
02843 return (ferror(fp) == 0);
02844 }
02845
02846
02847 void TiXmlDocument::CopyTo( TiXmlDocument* target ) const
02848 {
02849 TiXmlNode::CopyTo( target );
02850
02851 target->error = error;
02852 target->errorId = errorId;
02853 target->errorDesc = errorDesc;
02854 target->tabsize = tabsize;
02855 target->errorLocation = errorLocation;
02856 target->useMicrosoftBOM = useMicrosoftBOM;
02857
02858 TiXmlNode* node = 0;
02859 for ( node = firstChild; node; node = node->NextSibling() )
02860 {
02861 target->LinkEndChild( node->Clone() );
02862 }
02863 }
02864
02865
02866 TiXmlNode* TiXmlDocument::Clone() const
02867 {
02868 TiXmlDocument* clone = new TiXmlDocument();
02869 if ( !clone )
02870 return 0;
02871
02872 CopyTo( clone );
02873 return clone;
02874 }
02875
02876
02877 void TiXmlDocument::Print( FILE* cfile, int depth ) const
02878 {
02879 assert( cfile );
02880 for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
02881 {
02882 node->Print( cfile, depth );
02883 fprintf( cfile, "\n" );
02884 }
02885 }
02886
02887
02888 bool TiXmlDocument::Accept( TiXmlVisitor* visitor ) const
02889 {
02890 if ( visitor->VisitEnter( *this ) )
02891 {
02892 for ( const TiXmlNode* node=FirstChild(); node; node=node->NextSibling() )
02893 {
02894 if ( !node->Accept( visitor ) )
02895 break;
02896 }
02897 }
02898 return visitor->VisitExit( *this );
02899 }
02900
02901
02902 const TiXmlAttribute* TiXmlAttribute::Next() const
02903 {
02904
02905
02906 if ( next->value.empty() && next->name.empty() )
02907 return 0;
02908 return next;
02909 }
02910
02911
02912
02913
02914
02915
02916
02917
02918
02919
02920
02921
02922 const TiXmlAttribute* TiXmlAttribute::Previous() const
02923 {
02924
02925
02926 if ( prev->value.empty() && prev->name.empty() )
02927 return 0;
02928 return prev;
02929 }
02930
02931
02932
02933
02934
02935
02936
02937
02938
02939
02940
02941
02942 void TiXmlAttribute::Print( FILE* cfile, int , TIXML_STRING* str ) const
02943 {
02944 TIXML_STRING n, v;
02945
02946 EncodeString( name, &n );
02947 EncodeString( value, &v );
02948
02949 if (value.find ('\"') == TIXML_STRING::npos) {
02950 if ( cfile ) {
02951 fprintf (cfile, "%s=\"%s\"", n.c_str(), v.c_str() );
02952 }
02953 if ( str ) {
02954 (*str) += n; (*str) += "=\""; (*str) += v; (*str) += "\"";
02955 }
02956 }
02957 else {
02958 if ( cfile ) {
02959 fprintf (cfile, "%s='%s'", n.c_str(), v.c_str() );
02960 }
02961 if ( str ) {
02962 (*str) += n; (*str) += "='"; (*str) += v; (*str) += "'";
02963 }
02964 }
02965 }
02966
02967
02968 int TiXmlAttribute::QueryIntValue( int* ival ) const
02969 {
02970 if ( TIXML_SSCANF( value.c_str(), "%d", ival ) == 1 )
02971 return TIXML_SUCCESS;
02972 return TIXML_WRONG_TYPE;
02973 }
02974
02975 int TiXmlAttribute::QueryDoubleValue( double* dval ) const
02976 {
02977 if ( TIXML_SSCANF( value.c_str(), "%lf", dval ) == 1 )
02978 return TIXML_SUCCESS;
02979 return TIXML_WRONG_TYPE;
02980 }
02981
02982 void TiXmlAttribute::SetIntValue( int _value )
02983 {
02984 char buf [64];
02985 #if defined(TIXML_SNPRINTF)
02986 TIXML_SNPRINTF(buf, sizeof(buf), "%d", _value);
02987 #else
02988 sprintf (buf, "%d", _value);
02989 #endif
02990 SetValue (buf);
02991 }
02992
02993 void TiXmlAttribute::SetDoubleValue( double _value )
02994 {
02995 char buf [256];
02996 #if defined(TIXML_SNPRINTF)
02997 TIXML_SNPRINTF( buf, sizeof(buf), "%lf", _value);
02998 #else
02999 sprintf (buf, "%lf", _value);
03000 #endif
03001 SetValue (buf);
03002 }
03003
03004 int TiXmlAttribute::IntValue() const
03005 {
03006 return atoi (value.c_str ());
03007 }
03008
03009 double TiXmlAttribute::DoubleValue() const
03010 {
03011 return atof (value.c_str ());
03012 }
03013
03014
03015 TiXmlComment::TiXmlComment( const TiXmlComment& copy ) : TiXmlNode( TiXmlNode::COMMENT )
03016 {
03017 copy.CopyTo( this );
03018 }
03019
03020
03021 void TiXmlComment::operator=( const TiXmlComment& base )
03022 {
03023 Clear();
03024 base.CopyTo( this );
03025 }
03026
03027
03028 void TiXmlComment::Print( FILE* cfile, int depth ) const
03029 {
03030 assert( cfile );
03031 for ( int i=0; i<depth; i++ )
03032 {
03033 fprintf( cfile, " " );
03034 }
03035 fprintf( cfile, "<!--%s-->", value.c_str() );
03036 }
03037
03038
03039 void TiXmlComment::CopyTo( TiXmlComment* target ) const
03040 {
03041 TiXmlNode::CopyTo( target );
03042 }
03043
03044
03045 bool TiXmlComment::Accept( TiXmlVisitor* visitor ) const
03046 {
03047 return visitor->Visit( *this );
03048 }
03049
03050
03051 TiXmlNode* TiXmlComment::Clone() const
03052 {
03053 TiXmlComment* clone = new TiXmlComment();
03054
03055 if ( !clone )
03056 return 0;
03057
03058 CopyTo( clone );
03059 return clone;
03060 }
03061
03062
03063 void TiXmlText::Print( FILE* cfile, int depth ) const
03064 {
03065 assert( cfile );
03066 if ( cdata )
03067 {
03068 int i;
03069 fprintf( cfile, "\n" );
03070 for ( i=0; i<depth; i++ ) {
03071 fprintf( cfile, " " );
03072 }
03073 fprintf( cfile, "<![CDATA[%s]]>\n", value.c_str() );
03074 }
03075 else
03076 {
03077 TIXML_STRING buffer;
03078 EncodeString( value, &buffer );
03079 fprintf( cfile, "%s", buffer.c_str() );
03080 }
03081 }
03082
03083
03084 void TiXmlText::CopyTo( TiXmlText* target ) const
03085 {
03086 TiXmlNode::CopyTo( target );
03087 target->cdata = cdata;
03088 }
03089
03090
03091 bool TiXmlText::Accept( TiXmlVisitor* visitor ) const
03092 {
03093 return visitor->Visit( *this );
03094 }
03095
03096
03097 TiXmlNode* TiXmlText::Clone() const
03098 {
03099 TiXmlText* clone = 0;
03100 clone = new TiXmlText( "" );
03101
03102 if ( !clone )
03103 return 0;
03104
03105 CopyTo( clone );
03106 return clone;
03107 }
03108
03109
03110 TiXmlDeclaration::TiXmlDeclaration( const char * _version,
03111 const char * _encoding,
03112 const char * _standalone )
03113 : TiXmlNode( TiXmlNode::DECLARATION )
03114 {
03115 version = _version;
03116 encoding = _encoding;
03117 standalone = _standalone;
03118 }
03119
03120
03121 #ifdef TIXML_USE_STL
03122 TiXmlDeclaration::TiXmlDeclaration( const std::string& _version,
03123 const std::string& _encoding,
03124 const std::string& _standalone )
03125 : TiXmlNode( TiXmlNode::DECLARATION )
03126 {
03127 version = _version;
03128 encoding = _encoding;
03129 standalone = _standalone;
03130 }
03131 #endif
03132
03133
03134 TiXmlDeclaration::TiXmlDeclaration( const TiXmlDeclaration& copy )
03135 : TiXmlNode( TiXmlNode::DECLARATION )
03136 {
03137 copy.CopyTo( this );
03138 }
03139
03140
03141 void TiXmlDeclaration::operator=( const TiXmlDeclaration& copy )
03142 {
03143 Clear();
03144 copy.CopyTo( this );
03145 }
03146
03147
03148 void TiXmlDeclaration::Print( FILE* cfile, int , TIXML_STRING* str ) const
03149 {
03150 if ( cfile ) fprintf( cfile, "<?xml " );
03151 if ( str ) (*str) += "<?xml ";
03152
03153 if ( !version.empty() ) {
03154 if ( cfile ) fprintf (cfile, "version=\"%s\" ", version.c_str ());
03155 if ( str ) { (*str) += "version=\""; (*str) += version; (*str) += "\" "; }
03156 }
03157 if ( !encoding.empty() ) {
03158 if ( cfile ) fprintf (cfile, "encoding=\"%s\" ", encoding.c_str ());
03159 if ( str ) { (*str) += "encoding=\""; (*str) += encoding; (*str) += "\" "; }
03160 }
03161 if ( !standalone.empty() ) {
03162 if ( cfile ) fprintf (cfile, "standalone=\"%s\" ", standalone.c_str ());
03163 if ( str ) { (*str) += "standalone=\""; (*str) += standalone; (*str) += "\" "; }
03164 }
03165 if ( cfile ) fprintf( cfile, "?>" );
03166 if ( str ) (*str) += "?>";
03167 }
03168
03169
03170 void TiXmlDeclaration::CopyTo( TiXmlDeclaration* target ) const
03171 {
03172 TiXmlNode::CopyTo( target );
03173
03174 target->version = version;
03175 target->encoding = encoding;
03176 target->standalone = standalone;
03177 }
03178
03179
03180 bool TiXmlDeclaration::Accept( TiXmlVisitor* visitor ) const
03181 {
03182 return visitor->Visit( *this );
03183 }
03184
03185
03186 TiXmlNode* TiXmlDeclaration::Clone() const
03187 {
03188 TiXmlDeclaration* clone = new TiXmlDeclaration();
03189
03190 if ( !clone )
03191 return 0;
03192
03193 CopyTo( clone );
03194 return clone;
03195 }
03196
03197
03198 void TiXmlUnknown::Print( FILE* cfile, int depth ) const
03199 {
03200 for ( int i=0; i<depth; i++ )
03201 fprintf( cfile, " " );
03202 fprintf( cfile, "<%s>", value.c_str() );
03203 }
03204
03205
03206 void TiXmlUnknown::CopyTo( TiXmlUnknown* target ) const
03207 {
03208 TiXmlNode::CopyTo( target );
03209 }
03210
03211
03212 bool TiXmlUnknown::Accept( TiXmlVisitor* visitor ) const
03213 {
03214 return visitor->Visit( *this );
03215 }
03216
03217
03218 TiXmlNode* TiXmlUnknown::Clone() const
03219 {
03220 TiXmlUnknown* clone = new TiXmlUnknown();
03221
03222 if ( !clone )
03223 return 0;
03224
03225 CopyTo( clone );
03226 return clone;
03227 }
03228
03229
03230 TiXmlAttributeSet::TiXmlAttributeSet()
03231 {
03232 sentinel.next = &sentinel;
03233 sentinel.prev = &sentinel;
03234 }
03235
03236
03237 TiXmlAttributeSet::~TiXmlAttributeSet()
03238 {
03239 assert( sentinel.next == &sentinel );
03240 assert( sentinel.prev == &sentinel );
03241 }
03242
03243
03244 void TiXmlAttributeSet::Add( TiXmlAttribute* addMe )
03245 {
03246 #ifdef TIXML_USE_STL
03247 assert( !Find( TIXML_STRING( addMe->Name() ) ) );
03248 #else
03249 assert( !Find( addMe->Name() ) );
03250 #endif
03251
03252 addMe->next = &sentinel;
03253 addMe->prev = sentinel.prev;
03254
03255 sentinel.prev->next = addMe;
03256 sentinel.prev = addMe;
03257 }
03258
03259 void TiXmlAttributeSet::Remove( TiXmlAttribute* removeMe )
03260 {
03261 TiXmlAttribute* node;
03262
03263 for( node = sentinel.next; node != &sentinel; node = node->next )
03264 {
03265 if ( node == removeMe )
03266 {
03267 node->prev->next = node->next;
03268 node->next->prev = node->prev;
03269 node->next = 0;
03270 node->prev = 0;
03271 return;
03272 }
03273 }
03274 assert( 0 );
03275 }
03276
03277
03278 #ifdef TIXML_USE_STL
03279 const TiXmlAttribute* TiXmlAttributeSet::Find( const std::string& name ) const
03280 {
03281 for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
03282 {
03283 if ( node->name == name )
03284 return node;
03285 }
03286 return 0;
03287 }
03288
03289
03290
03291
03292
03293
03294
03295
03296
03297
03298
03299
03300 #endif
03301
03302
03303 const TiXmlAttribute* TiXmlAttributeSet::Find( const char* name ) const
03304 {
03305 for( const TiXmlAttribute* node = sentinel.next; node != &sentinel; node = node->next )
03306 {
03307 if ( strcmp( node->name.c_str(), name ) == 0 )
03308 return node;
03309 }
03310 return 0;
03311 }
03312
03313
03314
03315
03316
03317
03318
03319
03320
03321
03322
03323
03324
03325 #ifdef TIXML_USE_STL
03326 std::istream& operator>> (std::istream & in, TiXmlNode & base)
03327 {
03328 TIXML_STRING tag;
03329 tag.reserve( 8 * 1000 );
03330 base.StreamIn( &in, &tag );
03331
03332 base.Parse( tag.c_str(), 0, TIXML_DEFAULT_ENCODING );
03333 return in;
03334 }
03335 #endif
03336
03337
03338 #ifdef TIXML_USE_STL
03339 std::ostream& operator<< (std::ostream & out, const TiXmlNode & base)
03340 {
03341 TiXmlPrinter printer;
03342 printer.SetStreamPrinting();
03343 base.Accept( &printer );
03344 out << printer.Str();
03345
03346 return out;
03347 }
03348
03349
03350 std::string& operator<< (std::string& out, const TiXmlNode& base )
03351 {
03352 TiXmlPrinter printer;
03353 printer.SetStreamPrinting();
03354 base.Accept( &printer );
03355 out.append( printer.Str() );
03356
03357 return out;
03358 }
03359 #endif
03360
03361
03362 TiXmlHandle TiXmlHandle::FirstChild() const
03363 {
03364 if ( node )
03365 {
03366 TiXmlNode* child = node->FirstChild();
03367 if ( child )
03368 return TiXmlHandle( child );
03369 }
03370 return TiXmlHandle( 0 );
03371 }
03372
03373
03374 TiXmlHandle TiXmlHandle::FirstChild( const char * value ) const
03375 {
03376 if ( node )
03377 {
03378 TiXmlNode* child = node->FirstChild( value );
03379 if ( child )
03380 return TiXmlHandle( child );
03381 }
03382 return TiXmlHandle( 0 );
03383 }
03384
03385
03386 TiXmlHandle TiXmlHandle::FirstChildElement() const
03387 {
03388 if ( node )
03389 {
03390 TiXmlElement* child = node->FirstChildElement();
03391 if ( child )
03392 return TiXmlHandle( child );
03393 }
03394 return TiXmlHandle( 0 );
03395 }
03396
03397
03398 TiXmlHandle TiXmlHandle::FirstChildElement( const char * value ) const
03399 {
03400 if ( node )
03401 {
03402 TiXmlElement* child = node->FirstChildElement( value );
03403 if ( child )
03404 return TiXmlHandle( child );
03405 }
03406 return TiXmlHandle( 0 );
03407 }
03408
03409
03410 TiXmlHandle TiXmlHandle::Child( int count ) const
03411 {
03412 if ( node )
03413 {
03414 int i;
03415 TiXmlNode* child = node->FirstChild();
03416 for ( i=0;
03417 child && i<count;
03418 child = child->NextSibling(), ++i )
03419 {
03420
03421 }
03422 if ( child )
03423 return TiXmlHandle( child );
03424 }
03425 return TiXmlHandle( 0 );
03426 }
03427
03428
03429 TiXmlHandle TiXmlHandle::Child( const char* value, int count ) const
03430 {
03431 if ( node )
03432 {
03433 int i;
03434 TiXmlNode* child = node->FirstChild( value );
03435 for ( i=0;
03436 child && i<count;
03437 child = child->NextSibling( value ), ++i )
03438 {
03439
03440 }
03441 if ( child )
03442 return TiXmlHandle( child );
03443 }
03444 return TiXmlHandle( 0 );
03445 }
03446
03447
03448 TiXmlHandle TiXmlHandle::ChildElement( int count ) const
03449 {
03450 if ( node )
03451 {
03452 int i;
03453 TiXmlElement* child = node->FirstChildElement();
03454 for ( i=0;
03455 child && i<count;
03456 child = child->NextSiblingElement(), ++i )
03457 {
03458
03459 }
03460 if ( child )
03461 return TiXmlHandle( child );
03462 }
03463 return TiXmlHandle( 0 );
03464 }
03465
03466
03467 TiXmlHandle TiXmlHandle::ChildElement( const char* value, int count ) const
03468 {
03469 if ( node )
03470 {
03471 int i;
03472 TiXmlElement* child = node->FirstChildElement( value );
03473 for ( i=0;
03474 child && i<count;
03475 child = child->NextSiblingElement( value ), ++i )
03476 {
03477
03478 }
03479 if ( child )
03480 return TiXmlHandle( child );
03481 }
03482 return TiXmlHandle( 0 );
03483 }
03484
03485
03486 bool TiXmlPrinter::VisitEnter( const TiXmlDocument& )
03487 {
03488 return true;
03489 }
03490
03491 bool TiXmlPrinter::VisitExit( const TiXmlDocument& )
03492 {
03493 return true;
03494 }
03495
03496 bool TiXmlPrinter::VisitEnter( const TiXmlElement& element, const TiXmlAttribute* firstAttribute )
03497 {
03498 DoIndent();
03499 buffer += "<";
03500 buffer += element.Value();
03501
03502 for( const TiXmlAttribute* attrib = firstAttribute; attrib; attrib = attrib->Next() )
03503 {
03504 buffer += " ";
03505 attrib->Print( 0, 0, &buffer );
03506 }
03507
03508 if ( !element.FirstChild() )
03509 {
03510 buffer += " />";
03511 DoLineBreak();
03512 }
03513 else
03514 {
03515 buffer += ">";
03516 if ( element.FirstChild()->ToText()
03517 && element.LastChild() == element.FirstChild()
03518 && element.FirstChild()->ToText()->CDATA() == false )
03519 {
03520 simpleTextPrint = true;
03521
03522 }
03523 else
03524 {
03525 DoLineBreak();
03526 }
03527 }
03528 ++depth;
03529 return true;
03530 }
03531
03532
03533 bool TiXmlPrinter::VisitExit( const TiXmlElement& element )
03534 {
03535 --depth;
03536 if ( !element.FirstChild() )
03537 {
03538
03539 }
03540 else
03541 {
03542 if ( simpleTextPrint )
03543 {
03544 simpleTextPrint = false;
03545 }
03546 else
03547 {
03548 DoIndent();
03549 }
03550 buffer += "</";
03551 buffer += element.Value();
03552 buffer += ">";
03553 DoLineBreak();
03554 }
03555 return true;
03556 }
03557
03558
03559 bool TiXmlPrinter::Visit( const TiXmlText& text )
03560 {
03561 if ( text.CDATA() )
03562 {
03563 DoIndent();
03564 buffer += "<![CDATA[";
03565 buffer += text.Value();
03566 buffer += "]]>";
03567 DoLineBreak();
03568 }
03569 else if ( simpleTextPrint )
03570 {
03571 TIXML_STRING str;
03572 TiXmlBase::EncodeString( text.ValueTStr(), &str );
03573 buffer += str;
03574 }
03575 else
03576 {
03577 DoIndent();
03578 TIXML_STRING str;
03579 TiXmlBase::EncodeString( text.ValueTStr(), &str );
03580 buffer += str;
03581 DoLineBreak();
03582 }
03583 return true;
03584 }
03585
03586
03587 bool TiXmlPrinter::Visit( const TiXmlDeclaration& declaration )
03588 {
03589 DoIndent();
03590 declaration.Print( 0, 0, &buffer );
03591 DoLineBreak();
03592 return true;
03593 }
03594
03595
03596 bool TiXmlPrinter::Visit( const TiXmlComment& comment )
03597 {
03598 DoIndent();
03599 buffer += "<!--";
03600 buffer += comment.Value();
03601 buffer += "-->";
03602 DoLineBreak();
03603 return true;
03604 }
03605
03606
03607 bool TiXmlPrinter::Visit( const TiXmlUnknown& unknown )
03608 {
03609 DoIndent();
03610 buffer += "<";
03611 buffer += unknown.Value();
03612 buffer += ">";
03613 DoLineBreak();
03614 return true;
03615 }
03616