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
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051 #include "tinyxml.h"
00052 #include <ctype.h>
00053
00054
00055
00056
00057
00058
00059 TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
00060 {
00061 { "&", 5, '&' },
00062 { "<", 4, '<' },
00063 { ">", 4, '>' },
00064 { """, 6, '\"' },
00065 { "'", 6, '\'' }
00066 };
00067
00068
00069 const char* TiXmlBase::SkipWhiteSpace( const char* p )
00070 {
00071 if ( !p || !*p )
00072 {
00073 return 0;
00074 }
00075 while ( p && *p )
00076 {
00077 if ( isspace( *p ) || *p == '\n' || *p =='\r' )
00078 ++p;
00079 else
00080 break;
00081 }
00082
00083 return p;
00084 }
00085
00086 #ifdef TIXML_USE_STL
00087 bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag )
00088 {
00089 for( ;; )
00090 {
00091 if ( !in->good() ) return false;
00092
00093 int c = in->peek();
00094 if ( !IsWhiteSpace( c ) )
00095 return true;
00096 *tag += in->get();
00097 }
00098 }
00099
00100 bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag )
00101 {
00102 while ( in->good() )
00103 {
00104 int c = in->peek();
00105 if ( c == character )
00106 return true;
00107
00108 in->get();
00109 *tag += c;
00110 }
00111 return false;
00112 }
00113 #endif
00114
00115 const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name )
00116 {
00117 *name = "";
00118 assert( p );
00119
00120
00121
00122
00123
00124 if ( p && *p
00125 && ( isalpha( (unsigned char) *p ) || *p == '_' ) )
00126 {
00127 while( p && *p
00128 && ( isalnum( (unsigned char ) *p )
00129 || *p == '_'
00130 || *p == '-'
00131 || *p == ':' ) )
00132 {
00133 (*name) += *p;
00134 ++p;
00135 }
00136 return p;
00137 }
00138 return 0;
00139 }
00140
00141 const char* TiXmlBase::GetEntity( const char* p, char* value )
00142 {
00143
00144 TIXML_STRING ent;
00145 int i;
00146
00147
00148 if ( strncmp( "&#x", p, 3 ) == 0
00149 && *(p+3)
00150 && *(p+4) )
00151 {
00152 *value = 0;
00153
00154 if ( isalpha( *(p+3) ) ) *value += ( tolower( *(p+3) ) - 'a' + 10 ) * 16;
00155 else *value += ( *(p+3) - '0' ) * 16;
00156
00157 if ( isalpha( *(p+4) ) ) *value += ( tolower( *(p+4) ) - 'a' + 10 );
00158 else *value += ( *(p+4) - '0' );
00159
00160 return p+6;
00161 }
00162
00163
00164 for( i=0; i<NUM_ENTITY; ++i )
00165 {
00166 if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
00167 {
00168 assert( strlen( entity[i].str ) == entity[i].strLength );
00169 *value = entity[i].chr;
00170 return ( p + entity[i].strLength );
00171 }
00172 }
00173
00174
00175 *value = *p;
00176 return p+1;
00177 }
00178
00179
00180 bool TiXmlBase::StringEqual( const char* p,
00181 const char* tag,
00182 bool ignoreCase )
00183 {
00184 assert( p );
00185 if ( !p || !*p )
00186 {
00187 assert( 0 );
00188 return false;
00189 }
00190
00191 if ( tolower( *p ) == tolower( *tag ) )
00192 {
00193 const char* q = p;
00194
00195 if (ignoreCase)
00196 {
00197 while ( *q && *tag && *q == *tag )
00198 {
00199 ++q;
00200 ++tag;
00201 }
00202
00203 if ( *tag == 0 )
00204 {
00205 return true;
00206 }
00207 }
00208 else
00209 {
00210 while ( *q && *tag && tolower( *q ) == tolower( *tag ) )
00211 {
00212 ++q;
00213 ++tag;
00214 }
00215
00216 if ( *tag == 0 )
00217 {
00218 return true;
00219 }
00220 }
00221 }
00222 return false;
00223 }
00224
00225 const char* TiXmlBase::ReadText( const char* p,
00226 TIXML_STRING * text,
00227 bool trimWhiteSpace,
00228 const char* endTag,
00229 bool caseInsensitive )
00230 {
00231 *text = "";
00232 if ( !trimWhiteSpace
00233 || !condenseWhiteSpace )
00234 {
00235
00236 while ( p && *p
00237 && !StringEqual( p, endTag, caseInsensitive )
00238 )
00239 {
00240 char c;
00241 p = GetChar( p, &c );
00242 (* text) += c;
00243 }
00244 }
00245 else
00246 {
00247 bool whitespace = false;
00248
00249
00250 p = SkipWhiteSpace( p );
00251 while ( p && *p
00252 && !StringEqual( p, endTag, caseInsensitive ) )
00253 {
00254 if ( *p == '\r' || *p == '\n' )
00255 {
00256 whitespace = true;
00257 ++p;
00258 }
00259 else if ( isspace( *p ) )
00260 {
00261 whitespace = true;
00262 ++p;
00263 }
00264 else
00265 {
00266
00267
00268 if ( whitespace )
00269 {
00270 (* text) += ' ';
00271 whitespace = false;
00272 }
00273 char c;
00274 p = GetChar( p, &c );
00275 (* text) += c;
00276 }
00277 }
00278 }
00279 return p + strlen( endTag );
00280 }
00281
00282 #ifdef TIXML_USE_STL
00283
00284 void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
00285 {
00286
00287
00288
00289
00290
00291
00292
00293 if ( !StreamTo( in, '<', tag ) )
00294 {
00295 SetError( TIXML_ERROR_PARSING_EMPTY );
00296 return;
00297 }
00298
00299 while ( in->good() )
00300 {
00301 size_t tagIndex = tag->length();
00302 while ( in->good() && in->peek() != '>' )
00303 {
00304 int c = in->get();
00305 (*tag) += (char) c;
00306 }
00307
00308 if ( in->good() )
00309 {
00310
00311
00312
00313 TiXmlNode* node = Identify( tag->c_str() + tagIndex );
00314
00315 if ( node )
00316 {
00317 node->StreamIn( in, tag );
00318 bool isElement = node->ToElement() != 0;
00319 delete node;
00320 node = 0;
00321
00322
00323
00324 if ( isElement )
00325 {
00326 return;
00327 }
00328 }
00329 else
00330 {
00331 SetError( TIXML_ERROR );
00332 return;
00333 }
00334 }
00335 }
00336
00337 SetError( TIXML_ERROR );
00338 }
00339
00340 #endif
00341
00342 const char* TiXmlDocument::Parse( const char* p )
00343 {
00344
00345
00346
00347
00348
00349
00350
00351
00352 if ( !p || !*p )
00353 {
00354 SetError( TIXML_ERROR_DOCUMENT_EMPTY );
00355 return false;
00356 }
00357
00358 p = SkipWhiteSpace( p );
00359 if ( !p )
00360 {
00361 SetError( TIXML_ERROR_DOCUMENT_EMPTY );
00362 return false;
00363 }
00364
00365 while ( p && *p )
00366 {
00367 TiXmlNode* node = Identify( p );
00368 if ( node )
00369 {
00370 p = node->Parse( p );
00371 LinkEndChild( node );
00372 }
00373 else
00374 {
00375 break;
00376 }
00377 p = SkipWhiteSpace( p );
00378 }
00379
00380 return p;
00381 }
00382
00383
00384 TiXmlNode* TiXmlNode::Identify( const char* p )
00385 {
00386 TiXmlNode* returnNode = 0;
00387
00388 p = SkipWhiteSpace( p );
00389 if( !p || !*p || *p != '<' )
00390 {
00391 return 0;
00392 }
00393
00394 TiXmlDocument* doc = GetDocument();
00395 p = SkipWhiteSpace( p );
00396
00397 if ( !p || !*p )
00398 {
00399 return 0;
00400 }
00401
00402
00403
00404
00405
00406
00407
00408
00409 const char* xmlHeader = { "<?xml" };
00410 const char* commentHeader = { "<!--" };
00411
00412 if ( StringEqual( p, xmlHeader, true ) )
00413 {
00414 #ifdef DEBUG_PARSER
00415 TIXML_LOG( "XML parsing Declaration\n" );
00416 #endif
00417 returnNode = new TiXmlDeclaration();
00418 }
00419 else if ( isalpha( *(p+1) )
00420 || *(p+1) == '_' )
00421 {
00422 #ifdef DEBUG_PARSER
00423 TIXML_LOG( "XML parsing Element\n" );
00424 #endif
00425 returnNode = new TiXmlElement( "" );
00426 }
00427 else if ( StringEqual( p, commentHeader, false ) )
00428 {
00429 #ifdef DEBUG_PARSER
00430 TIXML_LOG( "XML parsing Comment\n" );
00431 #endif
00432 returnNode = new TiXmlComment();
00433 }
00434 else
00435 {
00436 #ifdef DEBUG_PARSER
00437 TIXML_LOG( "XML parsing Unknown\n" );
00438 #endif
00439 returnNode = new TiXmlUnknown();
00440 }
00441
00442 if ( returnNode )
00443 {
00444
00445 returnNode->parent = this;
00446
00447 }
00448 else
00449 {
00450 if ( doc )
00451 doc->SetError( TIXML_ERROR_OUT_OF_MEMORY );
00452 }
00453 return returnNode;
00454 }
00455
00456 #ifdef TIXML_USE_STL
00457
00458 void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag)
00459 {
00460
00461
00462 while( in->good() )
00463 {
00464 int c = in->get();
00465 (*tag) += (char) c ;
00466
00467 if ( c == '>' )
00468 break;
00469 }
00470
00471 if ( tag->length() < 3 ) return;
00472
00473
00474
00475
00476 if ( tag->at( tag->length() - 1 ) == '>'
00477 && tag->at( tag->length() - 2 ) == '/' )
00478 {
00479
00480 return;
00481 }
00482 else if ( tag->at( tag->length() - 1 ) == '>' )
00483 {
00484
00485
00486
00487
00488 for ( ;; )
00489 {
00490 StreamWhiteSpace( in, tag );
00491
00492
00493 if ( in->peek() != '<' )
00494 {
00495
00496 TiXmlText text( "" );
00497 text.StreamIn( in, tag );
00498
00499
00500
00501 continue;
00502 }
00503
00504
00505
00506 if ( !in->good() ) return;
00507 assert( in->peek() == '<' );
00508 size_t tagIndex = tag->length();
00509
00510 bool closingTag = false;
00511 bool firstCharFound = false;
00512
00513 for( ;; )
00514 {
00515 if ( !in->good() )
00516 return;
00517
00518 int c = in->peek();
00519
00520 if ( c == '>' )
00521 break;
00522
00523 *tag += c;
00524 in->get();
00525
00526 if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
00527 {
00528 firstCharFound = true;
00529 if ( c == '/' )
00530 closingTag = true;
00531 }
00532 }
00533
00534
00535 if ( closingTag )
00536 {
00537 int c = in->get();
00538 assert( c == '>' );
00539 *tag += c;
00540
00541
00542 return;
00543 }
00544 else
00545 {
00546
00547 const char* tagloc = tag->c_str() + tagIndex;
00548 TiXmlNode* node = Identify( tagloc );
00549 if ( !node )
00550 return;
00551 node->StreamIn( in, tag );
00552 delete node;
00553 node = 0;
00554
00555
00556 }
00557 }
00558 }
00559 }
00560 #endif
00561
00562 const char* TiXmlElement::Parse( const char* p )
00563 {
00564 p = SkipWhiteSpace( p );
00565 TiXmlDocument* document = GetDocument();
00566
00567 if ( !p || !*p || *p != '<' )
00568 {
00569 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
00570 return false;
00571 }
00572
00573 p = SkipWhiteSpace( p+1 );
00574
00575
00576 p = ReadName( p, &value );
00577 if ( !p || !*p )
00578 {
00579 if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME );
00580 return false;
00581 }
00582
00583 TIXML_STRING endTag ("</");
00584 endTag += value;
00585 endTag += ">";
00586
00587
00588
00589 while ( p && *p )
00590 {
00591 p = SkipWhiteSpace( p );
00592 if ( !p || !*p )
00593 {
00594 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
00595 return 0;
00596 }
00597 if ( *p == '/' )
00598 {
00599 ++p;
00600
00601 if ( *p != '>' )
00602 {
00603 if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY );
00604 return 0;
00605 }
00606 return (p+1);
00607 }
00608 else if ( *p == '>' )
00609 {
00610
00611
00612
00613 ++p;
00614 p = ReadValue( p );
00615 if ( !p || !*p )
00616 return 0;
00617
00618
00619 if ( StringEqual( p, endTag.c_str(), false ) )
00620 {
00621 p += endTag.length();
00622 return p;
00623 }
00624 else
00625 {
00626 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG );
00627 return 0;
00628 }
00629 }
00630 else
00631 {
00632
00633 TiXmlAttribute attrib;
00634 attrib.SetDocument( document );
00635 p = attrib.Parse( p );
00636
00637 if ( !p || !*p )
00638 {
00639 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
00640 return 0;
00641 }
00642 SetAttribute( attrib.Name(), attrib.Value() );
00643 }
00644 }
00645 return p;
00646 }
00647
00648
00649 const char* TiXmlElement::ReadValue( const char* p )
00650 {
00651 TiXmlDocument* document = GetDocument();
00652
00653
00654 p = SkipWhiteSpace( p );
00655 while ( p && *p )
00656 {
00657 if ( *p != '<' )
00658 {
00659
00660 TiXmlText* textNode = new TiXmlText( "" );
00661
00662 if ( !textNode )
00663 {
00664 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY );
00665 return 0;
00666 }
00667
00668 p = textNode->Parse( p );
00669
00670 if ( !textNode->Blank() )
00671 LinkEndChild( textNode );
00672 else
00673 delete textNode;
00674 }
00675 else
00676 {
00677
00678
00679 if ( StringEqual( p, "</", false ) )
00680 {
00681 return p;
00682 }
00683 else
00684 {
00685 TiXmlNode* node = Identify( p );
00686 if ( node )
00687 {
00688 p = node->Parse( p );
00689 LinkEndChild( node );
00690 }
00691 else
00692 {
00693 return 0;
00694 }
00695 }
00696 }
00697 p = SkipWhiteSpace( p );
00698 }
00699
00700 if ( !p )
00701 {
00702 if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE );
00703 }
00704 return p;
00705 }
00706
00707
00708 #ifdef TIXML_USE_STL
00709 void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
00710 {
00711 while ( in->good() )
00712 {
00713 int c = in->get();
00714 (*tag) += c;
00715
00716 if ( c == '>' )
00717 {
00718
00719 return;
00720 }
00721 }
00722 }
00723 #endif
00724
00725
00726 const char* TiXmlUnknown::Parse( const char* p )
00727 {
00728 TiXmlDocument* document = GetDocument();
00729 p = SkipWhiteSpace( p );
00730 if ( !p || !*p || *p != '<' )
00731 {
00732 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
00733 return 0;
00734 }
00735 ++p;
00736 value = "";
00737
00738 while ( p && *p && *p != '>' )
00739 {
00740 value += *p;
00741 ++p;
00742 }
00743
00744 if ( !p )
00745 {
00746 if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
00747 }
00748 if ( *p == '>' )
00749 return p+1;
00750 return p;
00751 }
00752
00753 #ifdef TIXML_USE_STL
00754 void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
00755 {
00756 while ( in->good() )
00757 {
00758 int c = in->get();
00759 (*tag) += c;
00760
00761 if ( c == '>'
00762 && tag->at( tag->length() - 2 ) == '-'
00763 && tag->at( tag->length() - 3 ) == '-' )
00764 {
00765
00766 return;
00767 }
00768 }
00769 }
00770 #endif
00771
00772
00773 const char* TiXmlComment::Parse( const char* p )
00774 {
00775 TiXmlDocument* document = GetDocument();
00776 value = "";
00777
00778 p = SkipWhiteSpace( p );
00779 const char* startTag = "<!--";
00780 const char* endTag = "-->";
00781
00782 if ( !StringEqual( p, startTag, false ) )
00783 {
00784 document->SetError( TIXML_ERROR_PARSING_COMMENT );
00785 return 0;
00786 }
00787 p += strlen( startTag );
00788 p = ReadText( p, &value, false, endTag, false );
00789 return p;
00790 }
00791
00792
00793 const char* TiXmlAttribute::Parse( const char* p )
00794 {
00795 p = SkipWhiteSpace( p );
00796 if ( !p || !*p ) return 0;
00797
00798
00799 p = ReadName( p, &name );
00800 if ( !p || !*p )
00801 {
00802 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
00803 return 0;
00804 }
00805 p = SkipWhiteSpace( p );
00806 if ( !p || !*p || *p != '=' )
00807 {
00808 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
00809 return 0;
00810 }
00811
00812 ++p;
00813 p = SkipWhiteSpace( p );
00814 if ( !p || !*p )
00815 {
00816 if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
00817 return 0;
00818 }
00819
00820 const char* end;
00821
00822 if ( *p == '\'' )
00823 {
00824 ++p;
00825 end = "\'";
00826 p = ReadText( p, &value, false, end, false );
00827 }
00828 else if ( *p == '"' )
00829 {
00830 ++p;
00831 end = "\"";
00832 p = ReadText( p, &value, false, end, false );
00833 }
00834 else
00835 {
00836
00837
00838
00839 value = "";
00840 while ( p && *p
00841 && !isspace( *p ) && *p != '\n' && *p != '\r'
00842 && *p != '/' && *p != '>' )
00843 {
00844 value += *p;
00845 ++p;
00846 }
00847 }
00848 return p;
00849 }
00850
00851 #ifdef TIXML_USE_STL
00852 void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
00853 {
00854 while ( in->good() )
00855 {
00856 int c = in->peek();
00857 if ( c == '<' )
00858 return;
00859
00860 (*tag) += c;
00861 in->get();
00862 }
00863 }
00864 #endif
00865
00866 const char* TiXmlText::Parse( const char* p )
00867 {
00868 value = "";
00869
00870
00871 bool ignoreWhite = true;
00872
00873
00874 const char* end = "<";
00875 p = ReadText( p, &value, ignoreWhite, end, false );
00876 if ( p )
00877 return p-1;
00878 return 0;
00879 }
00880
00881 #ifdef TIXML_USE_STL
00882 void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
00883 {
00884 while ( in->good() )
00885 {
00886 int c = in->get();
00887 (*tag) += c;
00888
00889 if ( c == '>' )
00890 {
00891
00892 return;
00893 }
00894 }
00895 }
00896 #endif
00897
00898 const char* TiXmlDeclaration::Parse( const char* p )
00899 {
00900 p = SkipWhiteSpace( p );
00901
00902
00903 TiXmlDocument* document = GetDocument();
00904 if ( !p || !*p || !StringEqual( p, "<?xml", true ) )
00905 {
00906 if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION );
00907 return 0;
00908 }
00909
00910 p += 5;
00911
00912
00913
00914 version = "";
00915 encoding = "";
00916 standalone = "";
00917
00918 while ( p && *p )
00919 {
00920 if ( *p == '>' )
00921 {
00922 ++p;
00923 return p;
00924 }
00925
00926 p = SkipWhiteSpace( p );
00927 if ( StringEqual( p, "version", true ) )
00928 {
00929
00930 TiXmlAttribute attrib;
00931 p = attrib.Parse( p );
00932 version = attrib.Value();
00933 }
00934 else if ( StringEqual( p, "encoding", true ) )
00935 {
00936
00937 TiXmlAttribute attrib;
00938 p = attrib.Parse( p );
00939 encoding = attrib.Value();
00940 }
00941 else if ( StringEqual( p, "standalone", true ) )
00942 {
00943
00944 TiXmlAttribute attrib;
00945 p = attrib.Parse( p );
00946 standalone = attrib.Value();
00947 }
00948 else
00949 {
00950
00951 while( p && *p && *p != '>' && !isspace( *p ) )
00952 ++p;
00953 }
00954 }
00955 return 0;
00956 }
00957
00958 bool TiXmlText::Blank() const
00959 {
00960 for ( unsigned i=0; i<value.length(); i++ )
00961 if ( !isspace( value[i] ) )
00962 return false;
00963 return true;
00964 }
00965