tinyxmlparser.cpp

Go to the documentation of this file.
00001 /******************************************************************************
00002 *       SOFA, Simulation Open-Framework Architecture, version 1.0 beta 3      *
00003 *                (c) 2006-2008 MGH, INRIA, USTL, UJF, CNRS                    *
00004 *                                                                             *
00005 * This program is free software; you can redistribute it and/or modify it     *
00006 * under the terms of the GNU General Public License as published by the Free  *
00007 * Software Foundation; either version 2 of the License, or (at your option)   *
00008 * any later version.                                                          *
00009 *                                                                             *
00010 * This program is distributed in the hope that it will be useful, but WITHOUT *
00011 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or       *
00012 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for    *
00013 * more details.                                                               *
00014 *                                                                             *
00015 * You should have received a copy of the GNU General Public License along     *
00016 * with this program; if not, write to the Free Software Foundation, Inc., 51  *
00017 * Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
00018 *******************************************************************************
00019 *                            SOFA :: Applications                             *
00020 *                                                                             *
00021 * Authors: M. Adam, J. Allard, B. Andre, P-J. Bensoussan, S. Cotin, C. Duriez,*
00022 * H. Delingette, F. Falipou, F. Faure, S. Fonteneau, L. Heigeas, C. Mendoza,  *
00023 * M. Nesme, P. Neumann, J-P. de la Plata Alcade, F. Poyer and F. Roy          *
00024 *                                                                             *
00025 * Contact information: contact@sofa-framework.org                             *
00026 ******************************************************************************/
00027 /*
00028 www.sourceforge.net/projects/tinyxml
00029 Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
00030 
00031 This software is provided 'as-is', without any express or implied 
00032 warranty. In no event will the authors be held liable for any 
00033 damages arising from the use of this software.
00034 
00035 Permission is granted to anyone to use this software for any 
00036 purpose, including commercial applications, and to alter it and 
00037 redistribute it freely, subject to the following restrictions:
00038 
00039 1. The origin of this software must not be misrepresented; you must 
00040 not claim that you wrote the original software. If you use this
00041 software in a product, an acknowledgment in the product documentation
00042 would be appreciated but is not required.
00043 
00044 2. Altered source versions must be plainly marked as such, and 
00045 must not be misrepresented as being the original software.
00046 
00047 3. This notice may not be removed or altered from any source 
00048 distribution.
00049 */
00050 
00051 #include "tinyxml.h"
00052 #include <ctype.h>
00053 
00054 //#define DEBUG_PARSER
00055 
00056 // Note tha "PutString" hardcodes the same list. This
00057 // is less flexible than it appears. Changing the entries
00058 // or order will break putstring.   
00059 TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = 
00060 {
00061     { "&amp;",  5, '&' },
00062     { "&lt;",   4, '<' },
00063     { "&gt;",   4, '>' },
00064     { "&quot;", 6, '\"' },
00065     { "&apos;", 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' )     // Still using old rules for white space.
00078             ++p;
00079         else
00080             break;
00081     }
00082 
00083     return p;
00084 }
00085 
00086 #ifdef TIXML_USE_STL
00087 /*static*/ 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 /*static*/ 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     // Names start with letters or underscores.
00121     // After that, they can be letters, underscores, numbers,
00122     // hyphens, or colons. (Colons are valid ony for namespaces,
00123     // but tinyxml can't tell namespaces from names.)
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     // Presume an entity, and pull it out.
00144     TIXML_STRING ent;
00145     int i;
00146 
00147     // Ignore the &#x entities.
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     // Now try to match it.
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     // So it wasn't an entity, its unrecognized, or something like that.
00175     *value = *p;    // Don't put back the last one, since we return it!
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 )        // Have we found the end of the tag, and everything equal?
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         // certain tags always keep whitespace
00233          || !condenseWhiteSpace )   // if true, whitespace is always kept
00234     {
00235         // Keep all the white space.
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         // Remove leading white space:
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                 // If we've found whitespace, add it before the
00267                 // new character. Any whitespace just becomes a space.
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     // The basic issue with a document is that we don't know what we're
00287     // streaming. Read something presumed to be a tag (and hope), then
00288     // identify it, and call the appropriate stream method on the tag.
00289     //
00290     // This "pre-streaming" will never read the closing ">" so the
00291     // sub-tag can orient itself.
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             // We now have something we presume to be a node of 
00311             // some sort. Identify it, and call the node to
00312             // continue streaming.
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                 // If this is the root element, we're done. Parsing will be
00323                 // done by the >> operator.
00324                 if ( isElement )
00325                 {
00326                     return;
00327                 }
00328             }
00329             else
00330             {
00331                 SetError( TIXML_ERROR );
00332                 return;
00333             }
00334         }
00335     }
00336     // We should have returned sooner.
00337     SetError( TIXML_ERROR );
00338 }
00339 
00340 #endif
00341 
00342 const char* TiXmlDocument::Parse( const char* p )
00343 {
00344     // Parse away, at the document level. Since a document
00345     // contains nothing but other tags, most of what happens
00346     // here is skipping white space.
00347     //
00348     // In this variant (as opposed to stream and Parse) we
00349     // read everything we can.
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     // All is well.
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     // What is this thing? 
00403     // - Elements start with a letter or underscore, but xml is reserved.
00404     // - Comments: <!--
00405     // - Decleration: <?xml
00406     // - Everthing else is unknown to tinyxml.
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         // Set the parent, so it can report errors
00445         returnNode->parent = this;
00446         //p = returnNode->Parse( p );
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     // We're called with some amount of pre-parsing. That is, some of "this"
00461     // element is in "tag". Go ahead and stream to the closing ">"
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     // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
00474     // If not, identify and stream.
00475 
00476     if (    tag->at( tag->length() - 1 ) == '>' 
00477          && tag->at( tag->length() - 2 ) == '/' )
00478     {
00479         // All good!
00480         return;
00481     }
00482     else if ( tag->at( tag->length() - 1 ) == '>' )
00483     {
00484         // There is more. Could be:
00485         //      text
00486         //      closing tag
00487         //      another node.
00488         for ( ;; )
00489         {
00490             StreamWhiteSpace( in, tag );
00491 
00492             // Do we have text?
00493             if ( in->peek() != '<' )
00494             {
00495                 // Yep, text.
00496                 TiXmlText text( "" );
00497                 text.StreamIn( in, tag );
00498 
00499                 // What follows text is a closing tag or another node.
00500                 // Go around again and figure it out.
00501                 continue;
00502             }
00503 
00504             // We now have either a closing tag...or another node.
00505             // We should be at a "<", regardless.
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             // If it was a closing tag, then read in the closing '>' to clean up the input stream.
00534             // If it was not, the streaming will be done by the tag.
00535             if ( closingTag )
00536             {
00537                 int c = in->get();
00538                 assert( c == '>' );
00539                 *tag += c;
00540 
00541                 // We are done, once we've found our closing tag.
00542                 return;
00543             }
00544             else
00545             {
00546                 // If not a closing tag, id it, and stream.
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                 // No return: go around from the beginning: text, closing tag, or node.
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     // Read the name.
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     // Check for and read attributes. Also look for an empty
00588     // tag or an end tag.
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             // Empty tag.
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             // Done with attributes (if there were any.)
00611             // Read the value -- which can include other
00612             // elements -- read the end tag, and return.
00613             ++p;
00614             p = ReadValue( p );     // Note this is an Element method, and will set the error if one happens.
00615             if ( !p || !*p )
00616                 return 0;
00617 
00618             // We should find the end tag now
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             // Try to read an element:
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     // Read in text and elements in any order.
00654     p = SkipWhiteSpace( p );
00655     while ( p && *p )
00656     {
00657         if ( *p != '<' )
00658         {
00659             // Take what we have, make a text element.
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             // We hit a '<'
00678             // Have we hit a new element or an end tag?
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             // All is well.
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             // All is well.
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     // Read the name, the '=' and the value.
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;    // skip '='
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         // All attribute values should be in single or double quotes.
00837         // But this is such a common error that the parser will try
00838         // its best, even without them.
00839         value = "";
00840         while (    p && *p                                      // existence
00841                 && !isspace( *p ) && *p != '\n' && *p != '\r'   // whitespace
00842                 && *p != '/' && *p != '>' )                     // tag end
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     //TiXmlDocument* doc = GetDocument();
00871     bool ignoreWhite = true;
00872 //  if ( doc && !doc->IgnoreWhiteSpace() ) ignoreWhite = false;
00873 
00874     const char* end = "<";
00875     p = ReadText( p, &value, ignoreWhite, end, false );
00876     if ( p )
00877         return p-1; // don't truncate the '<'
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             // All is well.
00892             return;
00893         }
00894     }
00895 }
00896 #endif
00897 
00898 const char* TiXmlDeclaration::Parse( const char* p )
00899 {
00900     p = SkipWhiteSpace( p );
00901     // Find the beginning, find the end, and look for
00902     // the stuff in-between.
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 //  const char* start = p+5;
00912 //  const char* end  = strstr( start, "?>" );
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 //          p += 7;
00930             TiXmlAttribute attrib;
00931             p = attrib.Parse( p );      
00932             version = attrib.Value();
00933         }
00934         else if ( StringEqual( p, "encoding", true ) )
00935         {
00936 //          p += 8;
00937             TiXmlAttribute attrib;
00938             p = attrib.Parse( p );      
00939             encoding = attrib.Value();
00940         }
00941         else if ( StringEqual( p, "standalone", true ) )
00942         {
00943 //          p += 10;
00944             TiXmlAttribute attrib;
00945             p = attrib.Parse( p );      
00946             standalone = attrib.Value();
00947         }
00948         else
00949         {
00950             // Read over whatever it is.
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 

Generated on Sun Nov 23 02:28:38 2008 for Sofa by  doxygen 1.5.7.1