Orocos Real-Time Toolkit  2.6.0
tinyxmlparser.cpp
00001 /***************************************************************************
00002   tag: Peter Soetens  do nov 2 13:06:01 CET 2006  tinyxmlparser.cpp
00003 
00004                         tinyxmlparser.cpp -  description
00005                            -------------------
00006     begin                : do november 02 2006
00007     copyright            : (C) 2006 Peter Soetens
00008     email                : peter.soetens@gmail.com
00009 
00010  ***************************************************************************
00011  *   This library is free software; you can redistribute it and/or         *
00012  *   modify it under the terms of the GNU General Public                   *
00013  *   License as published by the Free Software Foundation;                 *
00014  *   version 2 of the License.                                             *
00015  *                                                                         *
00016  *   As a special exception, you may use this file as part of a free       *
00017  *   software library without restriction.  Specifically, if other files   *
00018  *   instantiate templates or use macros or inline functions from this     *
00019  *   file, or you compile this file and link it with other files to        *
00020  *   produce an executable, this file does not by itself cause the         *
00021  *   resulting executable to be covered by the GNU General Public          *
00022  *   License.  This exception does not however invalidate any other        *
00023  *   reasons why the executable file might be covered by the GNU General   *
00024  *   Public License.                                                       *
00025  *                                                                         *
00026  *   This library is distributed in the hope that it will be useful,       *
00027  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
00028  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU     *
00029  *   Lesser General Public License for more details.                       *
00030  *                                                                         *
00031  *   You should have received a copy of the GNU General Public             *
00032  *   License along with this library; if not, write to the Free Software   *
00033  *   Foundation, Inc., 59 Temple Place,                                    *
00034  *   Suite 330, Boston, MA  02111-1307  USA                                *
00035  *                                                                         *
00036  ***************************************************************************/
00037 
00038 
00039 /*
00040 www.sourceforge.net/projects/tinyxml
00041 Original code (2.0 and earlier )copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
00042 
00043 This software is provided 'as-is', without any express or implied
00044 warranty. In no event will the authors be held liable for any
00045 damages arising from the use of this software.
00046 
00047 Permission is granted to anyone to use this software for any
00048 purpose, including commercial applications, and to alter it and
00049 redistribute it freely, subject to the following restrictions:
00050 
00051 1. The origin of this software must not be misrepresented; you must
00052 not claim that you wrote the original software. If you use this
00053 software in a product, an acknowledgment in the product documentation
00054 would be appreciated but is not required.
00055 
00056 2. Altered source versions must be plainly marked as such, and
00057 must not be misrepresented as being the original software.
00058 
00059 3. This notice may not be removed or altered from any source
00060 distribution.
00061 */
00062 
00063 #include "tinyxml.h"
00064 #include <ctype.h>
00065 #include <stddef.h>
00066 
00067 //#define DEBUG_PARSER
00068 #if defined( DEBUG_PARSER )
00069 #   if defined( DEBUG ) && defined( _MSC_VER )
00070 #       include <windows.h>
00071 #       define TIXML_LOG OutputDebugString
00072 #   else
00073 #       define TIXML_LOG printf
00074 #   endif
00075 #endif
00076 
00077 namespace RTT { namespace marsh {
00078 
00079 // Note tha "PutString" hardcodes the same list. This
00080 // is less flexible than it appears. Changing the entries
00081 // or order will break putstring.
00082 TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] =
00083 {
00084     { "&amp;",  5, '&' },
00085     { "&lt;",   4, '<' },
00086     { "&gt;",   4, '>' },
00087     { "&quot;", 6, '\"' },
00088     { "&apos;", 6, '\'' }
00089 };
00090 
00091 // Bunch of unicode info at:
00092 //      http://www.unicode.org/faq/utf_bom.html
00093 // Including the basic of this table, which determines the #bytes in the
00094 // sequence from the lead byte. 1 placed for invalid sequences --
00095 // although the result will be junk, pass it through as much as possible.
00096 // Beware of the non-characters in UTF-8:
00097 //              ef bb bf (Microsoft "lead bytes")
00098 //              ef bf be
00099 //              ef bf bf
00100 
00101 const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
00102 const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
00103 const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
00104 
00105 const int TiXmlBase::utf8ByteTable[256] =
00106 {
00107     //  0   1   2   3   4   5   6   7   8   9   a   b   c   d   e   f
00108         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x00
00109         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x10
00110         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x20
00111         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x30
00112         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x40
00113         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x50
00114         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x60
00115         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x70 End of ASCII range
00116         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x80 0x80 to 0xc1 invalid
00117         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0x90
00118         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0xa0
00119         1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  // 0xb0
00120         1,  1,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  // 0xc0 0xc2 to 0xdf 2 byte
00121         2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  // 0xd0
00122         3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  // 0xe0 0xe0 to 0xef 3 byte
00123         4,  4,  4,  4,  4,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1,  1   // 0xf0 0xf0 to 0xf4 4 byte, 0xf5 and higher invalid
00124 };
00125 
00126 
00127 void TiXmlBase::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
00128 {
00129     const unsigned long BYTE_MASK = 0xBF;
00130     const unsigned long BYTE_MARK = 0x80;
00131     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
00132 
00133     if (input < 0x80)
00134         *length = 1;
00135     else if ( input < 0x800 )
00136         *length = 2;
00137     else if ( input < 0x10000 )
00138         *length = 3;
00139     else if ( input < 0x200000 )
00140         *length = 4;
00141     else
00142         { *length = 0; return; }    // This code won't covert this correctly anyway.
00143 
00144     output += *length;
00145 
00146     // Scary scary fall throughs.
00147     switch (*length)
00148     {
00149         case 4:
00150             --output;
00151             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00152             input >>= 6;
00153         case 3:
00154             --output;
00155             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00156             input >>= 6;
00157         case 2:
00158             --output;
00159             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00160             input >>= 6;
00161         case 1:
00162             --output;
00163             *output = (char)(input | FIRST_BYTE_MARK[*length]);
00164     }
00165 }
00166 
00167 
00168 /*static*/ int TiXmlBase::IsAlpha( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
00169 {
00170     // This will only work for low-ascii, everything else is assumed to be a valid
00171     // letter. I'm not sure this is the best approach, but it is quite tricky trying
00172     // to figure out alhabetical vs. not across encoding. So take a very
00173     // conservative approach.
00174 
00175 //  if ( encoding == TIXML_ENCODING_UTF8 )
00176 //  {
00177         if ( anyByte < 127 )
00178             return isalpha( anyByte );
00179         else
00180             return 1;   // What else to do? The unicode set is huge...get the english ones right.
00181 //  }
00182 //  else
00183 //  {
00184 //      return isalpha( anyByte );
00185 //  }
00186 }
00187 
00188 
00189 /*static*/ int TiXmlBase::IsAlphaNum( unsigned char anyByte, TiXmlEncoding /*encoding*/ )
00190 {
00191     // This will only work for low-ascii, everything else is assumed to be a valid
00192     // letter. I'm not sure this is the best approach, but it is quite tricky trying
00193     // to figure out alhabetical vs. not across encoding. So take a very
00194     // conservative approach.
00195 
00196 //  if ( encoding == TIXML_ENCODING_UTF8 )
00197 //  {
00198         if ( anyByte < 127 )
00199             return isalnum( anyByte );
00200         else
00201             return 1;   // What else to do? The unicode set is huge...get the english ones right.
00202 //  }
00203 //  else
00204 //  {
00205 //      return isalnum( anyByte );
00206 //  }
00207 }
00208 
00209 
00210 class TiXmlParsingData
00211 {
00212     friend class TiXmlDocument;
00213   public:
00214     void Stamp( const char* now, TiXmlEncoding encoding );
00215 
00216     const TiXmlCursor& Cursor() { return cursor; }
00217 
00218   private:
00219     // Only used by the document!
00220     TiXmlParsingData( const char* start, int _tabsize, int row, int col )
00221     {
00222         assert( start );
00223         stamp = start;
00224         tabsize = _tabsize;
00225         cursor.row = row;
00226         cursor.col = col;
00227     }
00228 
00229     TiXmlCursor     cursor;
00230     const char*     stamp;
00231     int             tabsize;
00232 };
00233 
00234 
00235 void TiXmlParsingData::Stamp( const char* now, TiXmlEncoding encoding )
00236 {
00237     assert( now );
00238 
00239     // Do nothing if the tabsize is 0.
00240     if ( tabsize < 1 )
00241     {
00242         return;
00243     }
00244 
00245     // Get the current row, column.
00246     int row = cursor.row;
00247     int col = cursor.col;
00248     const char* p = stamp;
00249     assert( p );
00250 
00251     while ( p < now )
00252     {
00253         // Treat p as unsigned, so we have a happy compiler.
00254         const unsigned char* pU = (const unsigned char*)p;
00255 
00256         // Code contributed by Fletcher Dunn: (modified by lee)
00257         switch (*pU) {
00258             case 0:
00259                 // We *should* never get here, but in case we do, don't
00260                 // advance past the terminating null character, ever
00261                 return;
00262 
00263             case '\r':
00264                 // bump down to the next line
00265                 ++row;
00266                 col = 0;
00267                 // Eat the character
00268                 ++p;
00269 
00270                 // Check for \r\n sequence, and treat this as a single character
00271                 if (*p == '\n') {
00272                     ++p;
00273                 }
00274                 break;
00275 
00276             case '\n':
00277                 // bump down to the next line
00278                 ++row;
00279                 col = 0;
00280 
00281                 // Eat the character
00282                 ++p;
00283 
00284                 // Check for \n\r sequence, and treat this as a single
00285                 // character.  (Yes, this bizarre thing does occur still
00286                 // on some arcane platforms...)
00287                 if (*p == '\r') {
00288                     ++p;
00289                 }
00290                 break;
00291 
00292             case '\t':
00293                 // Eat the character
00294                 ++p;
00295 
00296                 // Skip to next tab stop
00297                 col = (col / tabsize + 1) * tabsize;
00298                 break;
00299 
00300             case TIXML_UTF_LEAD_0:
00301                 if ( encoding == TIXML_ENCODING_UTF8 )
00302                 {
00303                     if ( *(p+1) && *(p+2) )
00304                     {
00305                         // In these cases, don't advance the column. These are
00306                         // 0-width spaces.
00307                         if ( *(pU+1)==TIXML_UTF_LEAD_1 && *(pU+2)==TIXML_UTF_LEAD_2 )
00308                             p += 3;
00309                         else if ( *(pU+1)==0xbfU && *(pU+2)==0xbeU )
00310                             p += 3;
00311                         else if ( *(pU+1)==0xbfU && *(pU+2)==0xbfU )
00312                             p += 3;
00313                         else
00314                             { p +=3; ++col; }   // A normal character.
00315                     }
00316                 }
00317                 else
00318                 {
00319                     ++p;
00320                     ++col;
00321                 }
00322                 break;
00323 
00324             default:
00325                 if ( encoding == TIXML_ENCODING_UTF8 )
00326                 {
00327                     // Eat the 1 to 4 byte utf8 character.
00328                     int step = TiXmlBase::utf8ByteTable[*((unsigned char*)p)];
00329                     if ( step == 0 )
00330                         step = 1;       // Error case from bad encoding, but handle gracefully.
00331                     p += step;
00332 
00333                     // Just advance one column, of course.
00334                     ++col;
00335                 }
00336                 else
00337                 {
00338                     ++p;
00339                     ++col;
00340                 }
00341                 break;
00342         }
00343     }
00344     cursor.row = row;
00345     cursor.col = col;
00346     assert( cursor.row >= -1 );
00347     assert( cursor.col >= -1 );
00348     stamp = p;
00349     assert( stamp );
00350 }
00351 
00352 
00353 const char* TiXmlBase::SkipWhiteSpace( const char* p, TiXmlEncoding encoding )
00354 {
00355     if ( !p || !*p )
00356     {
00357         return 0;
00358     }
00359     if ( encoding == TIXML_ENCODING_UTF8 )
00360     {
00361         while ( *p )
00362         {
00363             const unsigned char* pU = (const unsigned char*)p;
00364 
00365             // Skip the stupid Microsoft UTF-8 Byte order marks
00366             if (    *(pU+0)==TIXML_UTF_LEAD_0
00367                  && *(pU+1)==TIXML_UTF_LEAD_1
00368                  && *(pU+2)==TIXML_UTF_LEAD_2 )
00369             {
00370                 p += 3;
00371                 continue;
00372             }
00373             else if(*(pU+0)==TIXML_UTF_LEAD_0
00374                  && *(pU+1)==0xbfU
00375                  && *(pU+2)==0xbeU )
00376             {
00377                 p += 3;
00378                 continue;
00379             }
00380             else if(*(pU+0)==TIXML_UTF_LEAD_0
00381                  && *(pU+1)==0xbfU
00382                  && *(pU+2)==0xbfU )
00383             {
00384                 p += 3;
00385                 continue;
00386             }
00387 
00388             if ( IsWhiteSpace( *p ) || *p == '\n' || *p =='\r' )        // Still using old rules for white space.
00389                 ++p;
00390             else
00391                 break;
00392         }
00393     }
00394     else
00395     {
00396         while ( *p && (IsWhiteSpace( *p ) || *p == '\n' || *p =='\r') )
00397             ++p;
00398     }
00399 
00400     return p;
00401 }
00402 
00403 #ifdef TIXML_USE_STL
00404 /*static*/ bool TiXmlBase::StreamWhiteSpace( TIXML_ISTREAM * in, TIXML_STRING * tag )
00405 {
00406     for( ;; )
00407     {
00408         if ( !in->good() ) return false;
00409 
00410         int c = in->peek();
00411         // At this scope, we can't get to a document. So fail silently.
00412         if ( !IsWhiteSpace( c ) || c <= 0 )
00413             return true;
00414 
00415         *tag += (char) in->get();
00416     }
00417 }
00418 
00419 /*static*/ bool TiXmlBase::StreamTo( TIXML_ISTREAM * in, int character, TIXML_STRING * tag )
00420 {
00421     //assert( character > 0 && character < 128 );   // else it won't work in utf-8
00422     while ( in->good() )
00423     {
00424         int c = in->peek();
00425         if ( c == character )
00426             return true;
00427         if ( c <= 0 )       // Silent failure: can't get document at this scope
00428             return false;
00429 
00430         in->get();
00431         *tag += (char) c;
00432     }
00433     return false;
00434 }
00435 #endif
00436 
00437 const char* TiXmlBase::ReadName( const char* p, TIXML_STRING * name, TiXmlEncoding encoding )
00438 {
00439     *name = "";
00440     assert( p );
00441 
00442     // Names start with letters or underscores.
00443     // Of course, in unicode, tinyxml has no idea what a letter *is*. The
00444     // algorithm is generous.
00445     //
00446     // After that, they can be letters, underscores, numbers,
00447     // hyphens, or colons. (Colons are valid ony for namespaces,
00448     // but tinyxml can't tell namespaces from names.)
00449     if (    p && *p
00450          && ( IsAlpha( (unsigned char) *p, encoding ) || *p == '_' ) )
00451     {
00452         while(      p && *p
00453                 &&  (       IsAlphaNum( (unsigned char ) *p, encoding )
00454                          || *p == '_'
00455                          || *p == '-'
00456                          || *p == '.'
00457                          || *p == ':' ) )
00458         {
00459             (*name) += *p;
00460             ++p;
00461         }
00462         return p;
00463     }
00464     return 0;
00465 }
00466 
00467 const char* TiXmlBase::GetEntity( const char* p, char* value, int* length, TiXmlEncoding encoding )
00468 {
00469     // Presume an entity, and pull it out.
00470     TIXML_STRING ent;
00471     int i;
00472     *length = 0;
00473 
00474     if ( *(p+1) && *(p+1) == '#' && *(p+2) )
00475     {
00476         unsigned long ucs = 0;
00477         ptrdiff_t delta = 0;
00478         unsigned mult = 1;
00479 
00480         if ( *(p+2) == 'x' )
00481         {
00482             // Hexadecimal.
00483             if ( !*(p+3) ) return 0;
00484 
00485             const char* q = p+3;
00486             q = strchr( q, ';' );
00487 
00488             if ( !q || !*q ) return 0;
00489 
00490             delta = q-p;
00491             --q;
00492 
00493             while ( *q != 'x' )
00494             {
00495                 if ( *q >= '0' && *q <= '9' )
00496                     ucs += mult * (*q - '0');
00497                 else if ( *q >= 'a' && *q <= 'f' )
00498                     ucs += mult * (*q - 'a' + 10);
00499                 else if ( *q >= 'A' && *q <= 'F' )
00500                     ucs += mult * (*q - 'A' + 10 );
00501                 else
00502                     return 0;
00503                 mult *= 16;
00504                 --q;
00505             }
00506         }
00507         else
00508         {
00509             // Decimal.
00510             if ( !*(p+2) ) return 0;
00511 
00512             const char* q = p+2;
00513             q = strchr( q, ';' );
00514 
00515             if ( !q || !*q ) return 0;
00516 
00517             delta = q-p;
00518             --q;
00519 
00520             while ( *q != '#' )
00521             {
00522                 if ( *q >= '0' && *q <= '9' )
00523                     ucs += mult * (*q - '0');
00524                 else
00525                     return 0;
00526                 mult *= 10;
00527                 --q;
00528             }
00529         }
00530         if ( encoding == TIXML_ENCODING_UTF8 )
00531         {
00532             // convert the UCS to UTF-8
00533             ConvertUTF32ToUTF8( ucs, value, length );
00534         }
00535         else
00536         {
00537             *value = (char)ucs;
00538             *length = 1;
00539         }
00540         return p + delta + 1;
00541     }
00542 
00543     // Now try to match it.
00544     for( i=0; i<NUM_ENTITY; ++i )
00545     {
00546         if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
00547         {
00548             assert( strlen( entity[i].str ) == entity[i].strLength );
00549             *value = entity[i].chr;
00550             *length = 1;
00551             return ( p + entity[i].strLength );
00552         }
00553     }
00554 
00555     // So it wasn't an entity, its unrecognized, or something like that.
00556     *value = *p;    // Don't put back the last one, since we return it!
00557     return p+1;
00558 }
00559 
00560 
00561 bool TiXmlBase::StringEqual( const char* p,
00562                              const char* tag,
00563                              bool ignoreCase,
00564                              TiXmlEncoding encoding )
00565 {
00566     assert( p );
00567     assert( tag );
00568     if ( !p || !*p )
00569     {
00570         assert( 0 );
00571         return false;
00572     }
00573 
00574     const char* q = p;
00575 
00576     if ( ignoreCase )
00577     {
00578         while ( *q && *tag && ToLower( *q, encoding ) == ToLower( *tag, encoding ) )
00579         {
00580             ++q;
00581             ++tag;
00582         }
00583 
00584         if ( *tag == 0 )
00585             return true;
00586     }
00587     else
00588     {
00589         while ( *q && *tag && *q == *tag )
00590         {
00591             ++q;
00592             ++tag;
00593         }
00594 
00595         if ( *tag == 0 )        // Have we found the end of the tag, and everything equal?
00596             return true;
00597     }
00598     return false;
00599 }
00600 
00601 const char* TiXmlBase::ReadText(    const char* p,
00602                                     TIXML_STRING * text,
00603                                     bool trimWhiteSpace,
00604                                     const char* endTag,
00605                                     bool caseInsensitive,
00606                                     TiXmlEncoding encoding )
00607 {
00608     *text = "";
00609     if (    !trimWhiteSpace         // certain tags always keep whitespace
00610          || !condenseWhiteSpace )   // if true, whitespace is always kept
00611     {
00612         // Keep all the white space.
00613         while (    p && *p
00614                 && !StringEqual( p, endTag, caseInsensitive, encoding )
00615               )
00616         {
00617             int len;
00618             char cArr[4] = { 0, 0, 0, 0 };
00619             p = GetChar( p, cArr, &len, encoding );
00620             text->append( cArr, len );
00621         }
00622     }
00623     else
00624     {
00625         bool whitespace = false;
00626 
00627         // Remove leading white space:
00628         p = SkipWhiteSpace( p, encoding );
00629         while (    p && *p
00630                 && !StringEqual( p, endTag, caseInsensitive, encoding ) )
00631         {
00632             if ( *p == '\r' || *p == '\n' )
00633             {
00634                 whitespace = true;
00635                 ++p;
00636             }
00637             else if ( IsWhiteSpace( *p ) )
00638             {
00639                 whitespace = true;
00640                 ++p;
00641             }
00642             else
00643             {
00644                 // If we've found whitespace, add it before the
00645                 // new character. Any whitespace just becomes a space.
00646                 if ( whitespace )
00647                 {
00648                     (*text) += ' ';
00649                     whitespace = false;
00650                 }
00651                 int len;
00652                 char cArr[4] = { 0, 0, 0, 0 };
00653                 p = GetChar( p, cArr, &len, encoding );
00654                 if ( len == 1 )
00655                     (*text) += cArr[0]; // more efficient
00656                 else
00657                     text->append( cArr, len );
00658             }
00659         }
00660     }
00661     return p + strlen( endTag );
00662 }
00663 
00664 #ifdef TIXML_USE_STL
00665 
00666 void TiXmlDocument::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
00667 {
00668     // The basic issue with a document is that we don't know what we're
00669     // streaming. Read something presumed to be a tag (and hope), then
00670     // identify it, and call the appropriate stream method on the tag.
00671     //
00672     // This "pre-streaming" will never read the closing ">" so the
00673     // sub-tag can orient itself.
00674 
00675     if ( !StreamTo( in, '<', tag ) )
00676     {
00677         SetError( TIXML_ERROR_PARSING_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
00678         return;
00679     }
00680 
00681     while ( in->good() )
00682     {
00683         int tagIndex = (int) tag->length();
00684         while ( in->good() && in->peek() != '>' )
00685         {
00686             int c = in->get();
00687             if ( c <= 0 )
00688             {
00689                 SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
00690                 break;
00691             }
00692             (*tag) += (char) c;
00693         }
00694 
00695         if ( in->good() )
00696         {
00697             // We now have something we presume to be a node of
00698             // some sort. Identify it, and call the node to
00699             // continue streaming.
00700             TiXmlNode* node = Identify( tag->c_str() + tagIndex, TIXML_DEFAULT_ENCODING );
00701 
00702             if ( node )
00703             {
00704                 node->StreamIn( in, tag );
00705                 bool isElement = node->ToElement() != 0;
00706                 delete node;
00707                 node = 0;
00708 
00709                 // If this is the root element, we're done. Parsing will be
00710                 // done by the >> operator.
00711                 if ( isElement )
00712                 {
00713                     return;
00714                 }
00715             }
00716             else
00717             {
00718                 SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
00719                 return;
00720             }
00721         }
00722     }
00723     // We should have returned sooner.
00724     SetError( TIXML_ERROR, 0, 0, TIXML_ENCODING_UNKNOWN );
00725 }
00726 
00727 #endif
00728 
00729 const char* TiXmlDocument::Parse( const char* p, TiXmlParsingData* prevData, TiXmlEncoding encoding )
00730 {
00731     ClearError();
00732 
00733     // Parse away, at the document level. Since a document
00734     // contains nothing but other tags, most of what happens
00735     // here is skipping white space.
00736     if ( !p || !*p )
00737     {
00738         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
00739         return 0;
00740     }
00741 
00742     // Note that, for a document, this needs to come
00743     // before the while space skip, so that parsing
00744     // starts from the pointer we are given.
00745     location.Clear();
00746     if ( prevData )
00747     {
00748         location.row = prevData->cursor.row;
00749         location.col = prevData->cursor.col;
00750     }
00751     else
00752     {
00753         location.row = 0;
00754         location.col = 0;
00755     }
00756     TiXmlParsingData data( p, TabSize(), location.row, location.col );
00757     location = data.Cursor();
00758 
00759     if ( encoding == TIXML_ENCODING_UNKNOWN )
00760     {
00761         // Check for the Microsoft UTF-8 lead bytes.
00762         const unsigned char* pU = (const unsigned char*)p;
00763         if (    *(pU+0) && *(pU+0) == TIXML_UTF_LEAD_0
00764              && *(pU+1) && *(pU+1) == TIXML_UTF_LEAD_1
00765              && *(pU+2) && *(pU+2) == TIXML_UTF_LEAD_2 )
00766         {
00767             encoding = TIXML_ENCODING_UTF8;
00768             useMicrosoftBOM = true;
00769         }
00770     }
00771 
00772     p = SkipWhiteSpace( p, encoding );
00773     if ( !p )
00774     {
00775         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, TIXML_ENCODING_UNKNOWN );
00776         return 0;
00777     }
00778 
00779     while ( p && *p )
00780     {
00781         TiXmlNode* node = Identify( p, encoding );
00782         if ( node )
00783         {
00784             p = node->Parse( p, &data, encoding );
00785             LinkEndChild( node );
00786         }
00787         else
00788         {
00789             break;
00790         }
00791 
00792         // Did we get encoding info?
00793         if (    encoding == TIXML_ENCODING_UNKNOWN
00794              && node->ToDeclaration() )
00795         {
00796             TiXmlDeclaration* dec = node->ToDeclaration();
00797             const char* enc = dec->Encoding();
00798             assert( enc );
00799 
00800             if ( *enc == 0 )
00801                 encoding = TIXML_ENCODING_UTF8;
00802             else if ( StringEqual( enc, "UTF-8", true, TIXML_ENCODING_UNKNOWN ) )
00803                 encoding = TIXML_ENCODING_UTF8;
00804             else if ( StringEqual( enc, "UTF8", true, TIXML_ENCODING_UNKNOWN ) )
00805                 encoding = TIXML_ENCODING_UTF8; // incorrect, but be nice
00806             else
00807                 encoding = TIXML_ENCODING_LEGACY;
00808         }
00809 
00810         p = SkipWhiteSpace( p, encoding );
00811     }
00812 
00813     // Was this empty?
00814     if ( !firstChild ) {
00815         SetError( TIXML_ERROR_DOCUMENT_EMPTY, 0, 0, encoding );
00816         return 0;
00817     }
00818 
00819     // All is well.
00820     return p;
00821 }
00822 
00823 void TiXmlDocument::SetError( int err, const char* pError, TiXmlParsingData* data, TiXmlEncoding encoding )
00824 {
00825     // The first error in a chain is more accurate - don't set again!
00826     if ( error )
00827         return;
00828 
00829     assert( err > 0 && err < TIXML_ERROR_STRING_COUNT );
00830     error   = true;
00831     errorId = err;
00832     errorDesc = errorString[ errorId ];
00833 
00834     errorLocation.Clear();
00835     if ( pError && data )
00836     {
00837         data->Stamp( pError, encoding );
00838         errorLocation = data->Cursor();
00839     }
00840 }
00841 
00842 
00843 TiXmlNode* TiXmlNode::Identify( const char* p, TiXmlEncoding encoding )
00844 {
00845     TiXmlNode* returnNode = 0;
00846 
00847     p = SkipWhiteSpace( p, encoding );
00848     if( !p || !*p || *p != '<' )
00849     {
00850         return 0;
00851     }
00852 
00853     TiXmlDocument* doc = GetDocument();
00854     p = SkipWhiteSpace( p, encoding );
00855 
00856     if ( !p || !*p )
00857     {
00858         return 0;
00859     }
00860 
00861     // What is this thing?
00862     // - Elements start with a letter or underscore, but xml is reserved.
00863     // - Comments: <!--
00864     // - Decleration: <?xml
00865     // - Everthing else is unknown to tinyxml.
00866     //
00867 
00868     const char* xmlHeader = { "<?xml" };
00869     const char* commentHeader = { "<!--" };
00870     const char* dtdHeader = { "<!" };
00871     const char* cdataHeader = { "<![CDATA[" };
00872 
00873     if ( StringEqual( p, xmlHeader, true, encoding ) )
00874     {
00875         #ifdef DEBUG_PARSER
00876             TIXML_LOG( "XML parsing Declaration\n" );
00877         #endif
00878         returnNode = new TiXmlDeclaration();
00879     }
00880     else if ( StringEqual( p, commentHeader, false, encoding ) )
00881     {
00882         #ifdef DEBUG_PARSER
00883             TIXML_LOG( "XML parsing Comment\n" );
00884         #endif
00885         returnNode = new TiXmlComment();
00886     }
00887     else if ( StringEqual( p, cdataHeader, false, encoding ) )
00888     {
00889         #ifdef DEBUG_PARSER
00890             TIXML_LOG( "XML parsing CDATA\n" );
00891         #endif
00892         TiXmlText* text = new TiXmlText( "" );
00893         text->SetCDATA( true );
00894         returnNode = text;
00895     }
00896     else if ( StringEqual( p, dtdHeader, false, encoding ) )
00897     {
00898         #ifdef DEBUG_PARSER
00899             TIXML_LOG( "XML parsing Unknown(1)\n" );
00900         #endif
00901         returnNode = new TiXmlUnknown();
00902     }
00903     else if (    IsAlpha( *(p+1), encoding )
00904               || *(p+1) == '_' )
00905     {
00906         #ifdef DEBUG_PARSER
00907             TIXML_LOG( "XML parsing Element\n" );
00908         #endif
00909         returnNode = new TiXmlElement( "" );
00910     }
00911     else
00912     {
00913         #ifdef DEBUG_PARSER
00914             TIXML_LOG( "XML parsing Unknown(2)\n" );
00915         #endif
00916         returnNode = new TiXmlUnknown();
00917     }
00918 
00919     if ( returnNode )
00920     {
00921         // Set the parent, so it can report errors
00922         returnNode->parent = this;
00923     }
00924     else
00925     {
00926         if ( doc )
00927             doc->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, TIXML_ENCODING_UNKNOWN );
00928     }
00929     return returnNode;
00930 }
00931 
00932 #ifdef TIXML_USE_STL
00933 
00934 void TiXmlElement::StreamIn (TIXML_ISTREAM * in, TIXML_STRING * tag)
00935 {
00936     // We're called with some amount of pre-parsing. That is, some of "this"
00937     // element is in "tag". Go ahead and stream to the closing ">"
00938     while( in->good() )
00939     {
00940         int c = in->get();
00941         if ( c <= 0 )
00942         {
00943             TiXmlDocument* document = GetDocument();
00944             if ( document )
00945                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
00946             return;
00947         }
00948         (*tag) += (char) c ;
00949 
00950         if ( c == '>' )
00951             break;
00952     }
00953 
00954     if ( tag->length() < 3 ) return;
00955 
00956     // Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
00957     // If not, identify and stream.
00958 
00959     if (    tag->at( tag->length() - 1 ) == '>'
00960          && tag->at( tag->length() - 2 ) == '/' )
00961     {
00962         // All good!
00963         return;
00964     }
00965     else if ( tag->at( tag->length() - 1 ) == '>' )
00966     {
00967         // There is more. Could be:
00968         //      text
00969         //      closing tag
00970         //      another node.
00971         for ( ;; )
00972         {
00973             StreamWhiteSpace( in, tag );
00974 
00975             // Do we have text?
00976             if ( in->good() && in->peek() != '<' )
00977             {
00978                 // Yep, text.
00979                 TiXmlText text( "" );
00980                 text.StreamIn( in, tag );
00981 
00982                 // What follows text is a closing tag or another node.
00983                 // Go around again and figure it out.
00984                 continue;
00985             }
00986 
00987             // We now have either a closing tag...or another node.
00988             // We should be at a "<", regardless.
00989             if ( !in->good() ) return;
00990             assert( in->peek() == '<' );
00991             int tagIndex = (int) tag->length();
00992 
00993             bool closingTag = false;
00994             bool firstCharFound = false;
00995 
00996             for( ;; )
00997             {
00998                 if ( !in->good() )
00999                     return;
01000 
01001                 int c = in->peek();
01002                 if ( c <= 0 )
01003                 {
01004                     TiXmlDocument* document = GetDocument();
01005                     if ( document )
01006                         document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01007                     return;
01008                 }
01009 
01010                 if ( c == '>' )
01011                     break;
01012 
01013                 *tag += (char) c;
01014                 in->get();
01015 
01016                 if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
01017                 {
01018                     firstCharFound = true;
01019                     if ( c == '/' )
01020                         closingTag = true;
01021                 }
01022             }
01023             // If it was a closing tag, then read in the closing '>' to clean up the input stream.
01024             // If it was not, the streaming will be done by the tag.
01025             if ( closingTag )
01026             {
01027                 if ( !in->good() )
01028                     return;
01029 
01030                 int c = in->get();
01031                 if ( c <= 0 )
01032                 {
01033                     TiXmlDocument* document = GetDocument();
01034                     if ( document )
01035                         document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01036                     return;
01037                 }
01038                 assert( c == '>' );
01039                 *tag += (char) c;
01040 
01041                 // We are done, once we've found our closing tag.
01042                 return;
01043             }
01044             else
01045             {
01046                 // If not a closing tag, id it, and stream.
01047                 const char* tagloc = tag->c_str() + tagIndex;
01048                 TiXmlNode* node = Identify( tagloc, TIXML_DEFAULT_ENCODING );
01049                 if ( !node )
01050                     return;
01051                 node->StreamIn( in, tag );
01052                 delete node;
01053                 node = 0;
01054 
01055                 // No return: go around from the beginning: text, closing tag, or node.
01056             }
01057         }
01058     }
01059 }
01060 #endif
01061 
01062 const char* TiXmlElement::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01063 {
01064     p = SkipWhiteSpace( p, encoding );
01065     TiXmlDocument* document = GetDocument();
01066 
01067     if ( !p || !*p )
01068     {
01069         if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, 0, 0, encoding );
01070         return 0;
01071     }
01072 
01073     if ( data )
01074     {
01075         data->Stamp( p, encoding );
01076         location = data->Cursor();
01077     }
01078 
01079     if ( *p != '<' )
01080     {
01081         if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, p, data, encoding );
01082         return 0;
01083     }
01084 
01085     p = SkipWhiteSpace( p+1, encoding );
01086 
01087     // Read the name.
01088     const char* pErr = p;
01089 
01090     p = ReadName( p, &value, encoding );
01091     if ( !p || !*p )
01092     {
01093         if ( document ) document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME, pErr, data, encoding );
01094         return 0;
01095     }
01096 
01097     TIXML_STRING endTag ("</");
01098     endTag += value;
01099     endTag += ">";
01100 
01101     // Check for and read attributes. Also look for an empty
01102     // tag or an end tag.
01103     while ( p && *p )
01104     {
01105         pErr = p;
01106         p = SkipWhiteSpace( p, encoding );
01107         if ( !p || !*p )
01108         {
01109             if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
01110             return 0;
01111         }
01112         if ( *p == '/' )
01113         {
01114             ++p;
01115             // Empty tag.
01116             if ( *p  != '>' )
01117             {
01118                 if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY, p, data, encoding );
01119                 return 0;
01120             }
01121             return (p+1);
01122         }
01123         else if ( *p == '>' )
01124         {
01125             // Done with attributes (if there were any.)
01126             // Read the value -- which can include other
01127             // elements -- read the end tag, and return.
01128             ++p;
01129             p = ReadValue( p, data, encoding );     // Note this is an Element method, and will set the error if one happens.
01130             if ( !p || !*p )
01131                 return 0;
01132 
01133             // We should find the end tag now
01134             if ( StringEqual( p, endTag.c_str(), false, encoding ) )
01135             {
01136                 p += endTag.length();
01137                 return p;
01138             }
01139             else
01140             {
01141                 if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG, p, data, encoding );
01142                 return 0;
01143             }
01144         }
01145         else
01146         {
01147             // Try to read an attribute:
01148             TiXmlAttribute* attrib = new TiXmlAttribute();
01149             if ( !attrib )
01150             {
01151                 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, pErr, data, encoding );
01152                 return 0;
01153             }
01154 
01155             attrib->SetDocument( document );
01156             const char* pErr = p;
01157             p = attrib->Parse( p, data, encoding );
01158 
01159             if ( !p || !*p )
01160             {
01161                 if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT, pErr, data, encoding );
01162                 delete attrib;
01163                 return 0;
01164             }
01165 
01166             // Handle the strange case of double attributes:
01167             TiXmlAttribute* node = attributeSet.Find( attrib->NameTStr() );
01168             if ( node )
01169             {
01170                 node->SetValue( attrib->Value() );
01171                 delete attrib;
01172                 return 0;
01173             }
01174 
01175             attributeSet.Add( attrib );
01176         }
01177     }
01178     return p;
01179 }
01180 
01181 
01182 const char* TiXmlElement::ReadValue( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01183 {
01184     TiXmlDocument* document = GetDocument();
01185 
01186     // Read in text and elements in any order.
01187     const char* pWithWhiteSpace = p;
01188     p = SkipWhiteSpace( p, encoding );
01189 
01190     while ( p && *p )
01191     {
01192         if ( *p != '<' )
01193         {
01194             // Take what we have, make a text element.
01195             TiXmlText* textNode = new TiXmlText( "" );
01196 
01197             if ( !textNode )
01198             {
01199                 if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY, 0, 0, encoding );
01200                     return 0;
01201             }
01202 
01203             if ( TiXmlBase::IsWhiteSpaceCondensed() )
01204             {
01205                 p = textNode->Parse( p, data, encoding );
01206             }
01207             else
01208             {
01209                 // Special case: we want to keep the white space
01210                 // so that leading spaces aren't removed.
01211                 p = textNode->Parse( pWithWhiteSpace, data, encoding );
01212             }
01213 
01214             if ( !textNode->Blank() )
01215                 LinkEndChild( textNode );
01216             else
01217                 delete textNode;
01218         }
01219         else
01220         {
01221             // We hit a '<'
01222             // Have we hit a new element or an end tag? This could also be
01223             // a TiXmlText in the "CDATA" style.
01224             if ( StringEqual( p, "</", false, encoding ) )
01225             {
01226                 return p;
01227             }
01228             else
01229             {
01230                 TiXmlNode* node = Identify( p, encoding );
01231                 if ( node )
01232                 {
01233                     p = node->Parse( p, data, encoding );
01234                     LinkEndChild( node );
01235                 }
01236                 else
01237                 {
01238                     return 0;
01239                 }
01240             }
01241         }
01242         pWithWhiteSpace = p;
01243         p = SkipWhiteSpace( p, encoding );
01244     }
01245 
01246     if ( !p )
01247     {
01248         if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE, 0, 0, encoding );
01249     }
01250     return p;
01251 }
01252 
01253 
01254 #ifdef TIXML_USE_STL
01255 void TiXmlUnknown::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
01256 {
01257     while ( in->good() )
01258     {
01259         int c = in->get();
01260         if ( c <= 0 )
01261         {
01262             TiXmlDocument* document = GetDocument();
01263             if ( document )
01264                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01265             return;
01266         }
01267         (*tag) += (char) c;
01268 
01269         if ( c == '>' )
01270         {
01271             // All is well.
01272             return;
01273         }
01274     }
01275 }
01276 #endif
01277 
01278 
01279 const char* TiXmlUnknown::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01280 {
01281     TiXmlDocument* document = GetDocument();
01282     p = SkipWhiteSpace( p, encoding );
01283 
01284     if ( data )
01285     {
01286         data->Stamp( p, encoding );
01287         location = data->Cursor();
01288     }
01289     if ( !p || !*p || *p != '<' )
01290     {
01291         if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, p, data, encoding );
01292         return 0;
01293     }
01294     ++p;
01295     value = "";
01296 
01297     while ( p && *p && *p != '>' )
01298     {
01299         value += *p;
01300         ++p;
01301     }
01302 
01303     if ( !p )
01304     {
01305         if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN, 0, 0, encoding );
01306     }
01307     if ( *p == '>' )
01308         return p+1;
01309     return p;
01310 }
01311 
01312 #ifdef TIXML_USE_STL
01313 void TiXmlComment::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
01314 {
01315     while ( in->good() )
01316     {
01317         int c = in->get();
01318         if ( c <= 0 )
01319         {
01320             TiXmlDocument* document = GetDocument();
01321             if ( document )
01322                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01323             return;
01324         }
01325 
01326         (*tag) += (char) c;
01327 
01328         if ( c == '>'
01329              && tag->at( tag->length() - 2 ) == '-'
01330              && tag->at( tag->length() - 3 ) == '-' )
01331         {
01332             // All is well.
01333             return;
01334         }
01335     }
01336 }
01337 #endif
01338 
01339 
01340 const char* TiXmlComment::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01341 {
01342     TiXmlDocument* document = GetDocument();
01343     value = "";
01344 
01345     p = SkipWhiteSpace( p, encoding );
01346 
01347     if ( data )
01348     {
01349         data->Stamp( p, encoding );
01350         location = data->Cursor();
01351     }
01352     const char* startTag = "<!--";
01353     const char* endTag   = "-->";
01354 
01355     if ( !StringEqual( p, startTag, false, encoding ) )
01356     {
01357         document->SetError( TIXML_ERROR_PARSING_COMMENT, p, data, encoding );
01358         return 0;
01359     }
01360     p += strlen( startTag );
01361     p = ReadText( p, &value, false, endTag, false, encoding );
01362     return p;
01363 }
01364 
01365 
01366 const char* TiXmlAttribute::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01367 {
01368     p = SkipWhiteSpace( p, encoding );
01369     if ( !p || !*p ) return 0;
01370 
01371     int tabsize = 4;
01372     if ( document )
01373         tabsize = document->TabSize();
01374 
01375     if ( data )
01376     {
01377         data->Stamp( p, encoding );
01378         location = data->Cursor();
01379     }
01380     // Read the name, the '=' and the value.
01381     const char* pErr = p;
01382     p = ReadName( p, &name, encoding );
01383     if ( !p || !*p )
01384     {
01385         if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, pErr, data, encoding );
01386         return 0;
01387     }
01388     p = SkipWhiteSpace( p, encoding );
01389     if ( !p || !*p || *p != '=' )
01390     {
01391         if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
01392         return 0;
01393     }
01394 
01395     ++p;    // skip '='
01396     p = SkipWhiteSpace( p, encoding );
01397     if ( !p || !*p )
01398     {
01399         if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES, p, data, encoding );
01400         return 0;
01401     }
01402 
01403     const char* end;
01404 
01405     if ( *p == '\'' )
01406     {
01407         ++p;
01408         end = "\'";
01409         p = ReadText( p, &value, false, end, false, encoding );
01410     }
01411     else if ( *p == '"' )
01412     {
01413         ++p;
01414         end = "\"";
01415         p = ReadText( p, &value, false, end, false, encoding );
01416     }
01417     else
01418     {
01419         // All attribute values should be in single or double quotes.
01420         // But this is such a common error that the parser will try
01421         // its best, even without them.
01422         value = "";
01423         while (    p && *p                                      // existence
01424                 && !IsWhiteSpace( *p ) && *p != '\n' && *p != '\r'  // whitespace
01425                 && *p != '/' && *p != '>' )                     // tag end
01426         {
01427             value += *p;
01428             ++p;
01429         }
01430     }
01431     return p;
01432 }
01433 
01434 #ifdef TIXML_USE_STL
01435 void TiXmlText::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
01436 {
01437     if ( cdata )
01438     {
01439         int c = in->get();
01440         if ( c <= 0 )
01441         {
01442             TiXmlDocument* document = GetDocument();
01443             if ( document )
01444                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01445             return;
01446         }
01447 
01448         (*tag) += (char) c;
01449 
01450         if ( c == '>'
01451              && tag->at( tag->length() - 2 ) == ']'
01452              && tag->at( tag->length() - 3 ) == ']' )
01453         {
01454             // All is well.
01455             return;
01456         }
01457     }
01458     else
01459     {
01460         while ( in->good() )
01461         {
01462             int c = in->peek();
01463             if ( c == '<' )
01464                 return;
01465             if ( c <= 0 )
01466             {
01467                 TiXmlDocument* document = GetDocument();
01468                 if ( document )
01469                     document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01470                 return;
01471             }
01472 
01473             (*tag) += (char) c;
01474             in->get();
01475         }
01476     }
01477 }
01478 #endif
01479 
01480 const char* TiXmlText::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding encoding )
01481 {
01482     value = "";
01483     TiXmlDocument* document = GetDocument();
01484 
01485     if ( data )
01486     {
01487         data->Stamp( p, encoding );
01488         location = data->Cursor();
01489     }
01490 
01491     const char* const startTag = "<![CDATA[";
01492     const char* const endTag   = "]]>";
01493 
01494     if ( cdata || StringEqual( p, startTag, false, encoding ) )
01495     {
01496         cdata = true;
01497 
01498         if ( !StringEqual( p, startTag, false, encoding ) )
01499         {
01500             document->SetError( TIXML_ERROR_PARSING_CDATA, p, data, encoding );
01501             return 0;
01502         }
01503         p += strlen( startTag );
01504 
01505         // Keep all the white space, ignore the encoding, etc.
01506         while (    p && *p
01507                 && !StringEqual( p, endTag, false, encoding )
01508               )
01509         {
01510             value += *p;
01511             ++p;
01512         }
01513 
01514         TIXML_STRING dummy;
01515         p = ReadText( p, &dummy, false, endTag, false, encoding );
01516         return p;
01517     }
01518     else
01519     {
01520         bool ignoreWhite = true;
01521 
01522         const char* end = "<";
01523         p = ReadText( p, &value, ignoreWhite, end, false, encoding );
01524         if ( p )
01525             return p-1; // don't truncate the '<'
01526         return 0;
01527     }
01528 }
01529 
01530 #ifdef TIXML_USE_STL
01531 void TiXmlDeclaration::StreamIn( TIXML_ISTREAM * in, TIXML_STRING * tag )
01532 {
01533     while ( in->good() )
01534     {
01535         int c = in->get();
01536         if ( c <= 0 )
01537         {
01538             TiXmlDocument* document = GetDocument();
01539             if ( document )
01540                 document->SetError( TIXML_ERROR_EMBEDDED_NULL, 0, 0, TIXML_ENCODING_UNKNOWN );
01541             return;
01542         }
01543         (*tag) += (char) c;
01544 
01545         if ( c == '>' )
01546         {
01547             // All is well.
01548             return;
01549         }
01550     }
01551 }
01552 #endif
01553 
01554 const char* TiXmlDeclaration::Parse( const char* p, TiXmlParsingData* data, TiXmlEncoding _encoding )
01555 {
01556     p = SkipWhiteSpace( p, _encoding );
01557     // Find the beginning, find the end, and look for
01558     // the stuff in-between.
01559     TiXmlDocument* document = GetDocument();
01560     if ( !p || !*p || !StringEqual( p, "<?xml", true, _encoding ) )
01561     {
01562         if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION, 0, 0, _encoding );
01563         return 0;
01564     }
01565     if ( data )
01566     {
01567         data->Stamp( p, _encoding );
01568         location = data->Cursor();
01569     }
01570     p += 5;
01571 
01572     version = "";
01573     encoding = "";
01574     standalone = "";
01575 
01576     while ( p && *p )
01577     {
01578         if ( *p == '>' )
01579         {
01580             ++p;
01581             return p;
01582         }
01583 
01584         p = SkipWhiteSpace( p, _encoding );
01585         if ( StringEqual( p, "version", true, _encoding ) )
01586         {
01587             TiXmlAttribute attrib;
01588             p = attrib.Parse( p, data, _encoding );
01589             version = attrib.Value();
01590         }
01591         else if ( StringEqual( p, "encoding", true, _encoding ) )
01592         {
01593             TiXmlAttribute attrib;
01594             p = attrib.Parse( p, data, _encoding );
01595             encoding = attrib.Value();
01596         }
01597         else if ( StringEqual( p, "standalone", true, _encoding ) )
01598         {
01599             TiXmlAttribute attrib;
01600             p = attrib.Parse( p, data, _encoding );
01601             standalone = attrib.Value();
01602         }
01603         else
01604         {
01605             // Read over whatever it is.
01606             while( p && *p && *p != '>' && !IsWhiteSpace( *p ) )
01607                 ++p;
01608         }
01609     }
01610     return 0;
01611 }
01612 
01613 bool TiXmlText::Blank() const
01614 {
01615     for ( unsigned i=0; i<value.length(); i++ )
01616         if ( !IsWhiteSpace( value[i] ) )
01617             return false;
01618     return true;
01619 }
01620 
01621 }}