tinyxml2.cpp
Go to the documentation of this file.
00001 /*
00002 Original code by Lee Thomason (www.grinninglizard.com)
00003 
00004 This software is provided 'as-is', without any express or implied
00005 warranty. In no event will the authors be held liable for any
00006 damages arising from the use of this software.
00007 
00008 Permission is granted to anyone to use this software for any
00009 purpose, including commercial applications, and to alter it and
00010 redistribute it freely, subject to the following restrictions:
00011 
00012 1. The origin of this software must not be misrepresented; you must
00013 not claim that you wrote the original software. If you use this
00014 software in a product, an acknowledgment in the product documentation
00015 would be appreciated but is not required.
00016 
00017 2. Altered source versions must be plainly marked as such, and
00018 must not be misrepresented as being the original software.
00019 
00020 3. This notice may not be removed or altered from any source
00021 distribution.
00022 */
00023 
00024 #include "tinyxml2.h"
00025 
00026 #include <new>          // yes, this one new style header, is in the Android SDK.
00027 #   ifdef ANDROID_NDK
00028 #   include <stddef.h>
00029 #else
00030 #   include <cstddef>
00031 #endif
00032 
00033 static const char LINE_FEED                             = (char)0x0a;                   // all line endings are normalized to LF
00034 static const char LF = LINE_FEED;
00035 static const char CARRIAGE_RETURN               = (char)0x0d;                   // CR gets filtered out
00036 static const char CR = CARRIAGE_RETURN;
00037 static const char SINGLE_QUOTE                  = '\'';
00038 static const char DOUBLE_QUOTE                  = '\"';
00039 
00040 // Bunch of unicode info at:
00041 //              http://www.unicode.org/faq/utf_bom.html
00042 //      ef bb bf (Microsoft "lead bytes") - designates UTF-8
00043 
00044 static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
00045 static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
00046 static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
00047 
00048 
00049 #define DELETE_NODE( node )     {                       \
00050         if ( node ) {                                           \
00051             MemPool* pool = node->_memPool;     \
00052             node->~XMLNode();                           \
00053             pool->Free( node );                         \
00054         }                                                                       \
00055     }
00056 #define DELETE_ATTRIBUTE( attrib ) {            \
00057         if ( attrib ) {                                                 \
00058             MemPool* pool = attrib->_memPool;   \
00059             attrib->~XMLAttribute();                    \
00060             pool->Free( attrib );                               \
00061         }                                                                               \
00062     }
00063 
00064 namespace tinyxml2
00065 {
00066 
00067 struct Entity {
00068     const char* pattern;
00069     int length;
00070     char value;
00071 };
00072 
00073 static const int NUM_ENTITIES = 5;
00074 static const Entity entities[NUM_ENTITIES] = {
00075     { "quot", 4,        DOUBLE_QUOTE },
00076     { "amp", 3,         '&'  },
00077     { "apos", 4,        SINGLE_QUOTE },
00078     { "lt",     2,              '<'      },
00079     { "gt",     2,              '>'      }
00080 };
00081 
00082 
00083 StrPair::~StrPair()
00084 {
00085     Reset();
00086 }
00087 
00088 
00089 void StrPair::Reset()
00090 {
00091     if ( _flags & NEEDS_DELETE ) {
00092         delete [] _start;
00093     }
00094     _flags = 0;
00095     _start = 0;
00096     _end = 0;
00097 }
00098 
00099 
00100 void StrPair::SetStr( const char* str, int flags )
00101 {
00102     Reset();
00103     size_t len = strlen( str );
00104     _start = new char[ len+1 ];
00105     memcpy( _start, str, len+1 );
00106     _end = _start + len;
00107     _flags = flags | NEEDS_DELETE;
00108 }
00109 
00110 
00111 char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
00112 {
00113     TIXMLASSERT( endTag && *endTag );
00114 
00115     char* start = p;    // fixme: hides a member
00116     char  endChar = *endTag;
00117     size_t length = strlen( endTag );
00118 
00119     // Inner loop of text parsing.
00120     while ( *p ) {
00121         if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
00122             Set( start, p, strFlags );
00123             return p + length;
00124         }
00125         ++p;
00126     }
00127     return 0;
00128 }
00129 
00130 
00131 char* StrPair::ParseName( char* p )
00132 {
00133     char* start = p;
00134 
00135     if ( !start || !(*start) ) {
00136         return 0;
00137     }
00138 
00139     while( *p && (
00140                 XMLUtil::IsAlphaNum( (unsigned char) *p )
00141                 || *p == '_'
00142                 || *p == ':'
00143                 || (*p == '-' && p>start )              // can be in a name, but not lead it.
00144                 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
00145         ++p;
00146     }
00147 
00148     if ( p > start ) {
00149         Set( start, p, 0 );
00150         return p;
00151     }
00152     return 0;
00153 }
00154 
00155 
00156 void StrPair::CollapseWhitespace()
00157 {
00158     // Trim leading space.
00159     _start = XMLUtil::SkipWhiteSpace( _start );
00160 
00161     if ( _start && *_start ) {
00162         char* p = _start;       // the read pointer
00163         char* q = _start;       // the write pointer
00164 
00165         while( *p ) {
00166             if ( XMLUtil::IsWhiteSpace( *p )) {
00167                 p = XMLUtil::SkipWhiteSpace( p );
00168                 if ( *p == 0 ) {
00169                     break;    // don't write to q; this trims the trailing space.
00170                 }
00171                 *q = ' ';
00172                 ++q;
00173             }
00174             *q = *p;
00175             ++q;
00176             ++p;
00177         }
00178         *q = 0;
00179     }
00180 }
00181 
00182 
00183 const char* StrPair::GetStr()
00184 {
00185     if ( _flags & NEEDS_FLUSH ) {
00186         *_end = 0;
00187         _flags ^= NEEDS_FLUSH;
00188 
00189         if ( _flags ) {
00190             char* p = _start;   // the read pointer
00191             char* q = _start;   // the write pointer
00192 
00193             while( p < _end ) {
00194                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
00195                     // CR-LF pair becomes LF
00196                     // CR alone becomes LF
00197                     // LF-CR becomes LF
00198                     if ( *(p+1) == LF ) {
00199                         p += 2;
00200                     }
00201                     else {
00202                         ++p;
00203                     }
00204                     *q++ = LF;
00205                 }
00206                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
00207                     if ( *(p+1) == CR ) {
00208                         p += 2;
00209                     }
00210                     else {
00211                         ++p;
00212                     }
00213                     *q++ = LF;
00214                 }
00215                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
00216                     // Entities handled by tinyXML2:
00217                     // - special entities in the entity table [in/out]
00218                     // - numeric character reference [in]
00219                     //   &#20013; or &#x4e2d;
00220 
00221                     if ( *(p+1) == '#' ) {
00222                         char buf[10] = { 0 };
00223                         int len;
00224                         p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
00225                         for( int i=0; i<len; ++i ) {
00226                             *q++ = buf[i];
00227                         }
00228                         TIXMLASSERT( q <= p );
00229                     }
00230                     else {
00231                         int i=0;
00232                         for(; i<NUM_ENTITIES; ++i ) {
00233                             if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
00234                                     && *(p+entities[i].length+1) == ';' ) {
00235                                 // Found an entity convert;
00236                                 *q = entities[i].value;
00237                                 ++q;
00238                                 p += entities[i].length + 2;
00239                                 break;
00240                             }
00241                         }
00242                         if ( i == NUM_ENTITIES ) {
00243                             // fixme: treat as error?
00244                             ++p;
00245                             ++q;
00246                         }
00247                     }
00248                 }
00249                 else {
00250                     *q = *p;
00251                     ++p;
00252                     ++q;
00253                 }
00254             }
00255             *q = 0;
00256         }
00257         // The loop below has plenty going on, and this
00258         // is a less useful mode. Break it out.
00259         if ( _flags & COLLAPSE_WHITESPACE ) {
00260             CollapseWhitespace();
00261         }
00262         _flags = (_flags & NEEDS_DELETE);
00263     }
00264     return _start;
00265 }
00266 
00267 
00268 
00269 
00270 // --------- XMLUtil ----------- //
00271 
00272 const char* XMLUtil::ReadBOM( const char* p, bool* bom )
00273 {
00274     *bom = false;
00275     const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
00276     // Check for BOM:
00277     if (    *(pu+0) == TIXML_UTF_LEAD_0
00278             && *(pu+1) == TIXML_UTF_LEAD_1
00279             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
00280         *bom = true;
00281         p += 3;
00282     }
00283     return p;
00284 }
00285 
00286 
00287 void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
00288 {
00289     const unsigned long BYTE_MASK = 0xBF;
00290     const unsigned long BYTE_MARK = 0x80;
00291     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
00292 
00293     if (input < 0x80) {
00294         *length = 1;
00295     }
00296     else if ( input < 0x800 ) {
00297         *length = 2;
00298     }
00299     else if ( input < 0x10000 ) {
00300         *length = 3;
00301     }
00302     else if ( input < 0x200000 ) {
00303         *length = 4;
00304     }
00305     else {
00306         *length = 0;    // This code won't covert this correctly anyway.
00307         return;
00308     }
00309 
00310     output += *length;
00311 
00312     // Scary scary fall throughs.
00313     switch (*length) {
00314         case 4:
00315             --output;
00316             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00317             input >>= 6;
00318         case 3:
00319             --output;
00320             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00321             input >>= 6;
00322         case 2:
00323             --output;
00324             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
00325             input >>= 6;
00326         case 1:
00327             --output;
00328             *output = (char)(input | FIRST_BYTE_MARK[*length]);
00329         default:
00330             break;
00331     }
00332 }
00333 
00334 
00335 const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
00336 {
00337     // Presume an entity, and pull it out.
00338     *length = 0;
00339 
00340     if ( *(p+1) == '#' && *(p+2) ) {
00341         unsigned long ucs = 0;
00342         ptrdiff_t delta = 0;
00343         unsigned mult = 1;
00344 
00345         if ( *(p+2) == 'x' ) {
00346             // Hexadecimal.
00347             if ( !*(p+3) ) {
00348                 return 0;
00349             }
00350 
00351             const char* q = p+3;
00352             q = strchr( q, ';' );
00353 
00354             if ( !q || !*q ) {
00355                 return 0;
00356             }
00357 
00358             delta = q-p;
00359             --q;
00360 
00361             while ( *q != 'x' ) {
00362                 if ( *q >= '0' && *q <= '9' ) {
00363                     ucs += mult * (*q - '0');
00364                 }
00365                 else if ( *q >= 'a' && *q <= 'f' ) {
00366                     ucs += mult * (*q - 'a' + 10);
00367                 }
00368                 else if ( *q >= 'A' && *q <= 'F' ) {
00369                     ucs += mult * (*q - 'A' + 10 );
00370                 }
00371                 else {
00372                     return 0;
00373                 }
00374                 mult *= 16;
00375                 --q;
00376             }
00377         }
00378         else {
00379             // Decimal.
00380             if ( !*(p+2) ) {
00381                 return 0;
00382             }
00383 
00384             const char* q = p+2;
00385             q = strchr( q, ';' );
00386 
00387             if ( !q || !*q ) {
00388                 return 0;
00389             }
00390 
00391             delta = q-p;
00392             --q;
00393 
00394             while ( *q != '#' ) {
00395                 if ( *q >= '0' && *q <= '9' ) {
00396                     ucs += mult * (*q - '0');
00397                 }
00398                 else {
00399                     return 0;
00400                 }
00401                 mult *= 10;
00402                 --q;
00403             }
00404         }
00405         // convert the UCS to UTF-8
00406         ConvertUTF32ToUTF8( ucs, value, length );
00407         return p + delta + 1;
00408     }
00409     return p+1;
00410 }
00411 
00412 
00413 void XMLUtil::ToStr( int v, char* buffer, int bufferSize )
00414 {
00415     TIXML_SNPRINTF( buffer, bufferSize, "%d", v );
00416 }
00417 
00418 
00419 void XMLUtil::ToStr( unsigned v, char* buffer, int bufferSize )
00420 {
00421     TIXML_SNPRINTF( buffer, bufferSize, "%u", v );
00422 }
00423 
00424 
00425 void XMLUtil::ToStr( bool v, char* buffer, int bufferSize )
00426 {
00427     TIXML_SNPRINTF( buffer, bufferSize, "%d", v ? 1 : 0 );
00428 }
00429 
00430 
00431 void XMLUtil::ToStr( float v, char* buffer, int bufferSize )
00432 {
00433     TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
00434 }
00435 
00436 
00437 void XMLUtil::ToStr( double v, char* buffer, int bufferSize )
00438 {
00439     TIXML_SNPRINTF( buffer, bufferSize, "%g", v );
00440 }
00441 
00442 
00443 bool XMLUtil::ToInt( const char* str, int* value )
00444 {
00445     if ( TIXML_SSCANF( str, "%d", value ) == 1 ) {
00446         return true;
00447     }
00448     return false;
00449 }
00450 
00451 bool XMLUtil::ToUnsigned( const char* str, unsigned *value )
00452 {
00453     if ( TIXML_SSCANF( str, "%u", value ) == 1 ) {
00454         return true;
00455     }
00456     return false;
00457 }
00458 
00459 bool XMLUtil::ToBool( const char* str, bool* value )
00460 {
00461     int ival = 0;
00462     if ( ToInt( str, &ival )) {
00463         *value = (ival==0) ? false : true;
00464         return true;
00465     }
00466     if ( StringEqual( str, "true" ) ) {
00467         *value = true;
00468         return true;
00469     }
00470     else if ( StringEqual( str, "false" ) ) {
00471         *value = false;
00472         return true;
00473     }
00474     return false;
00475 }
00476 
00477 
00478 bool XMLUtil::ToFloat( const char* str, float* value )
00479 {
00480     if ( TIXML_SSCANF( str, "%f", value ) == 1 ) {
00481         return true;
00482     }
00483     return false;
00484 }
00485 
00486 bool XMLUtil::ToDouble( const char* str, double* value )
00487 {
00488     if ( TIXML_SSCANF( str, "%lf", value ) == 1 ) {
00489         return true;
00490     }
00491     return false;
00492 }
00493 
00494 
00495 char* XMLDocument::Identify( char* p, XMLNode** node )
00496 {
00497     XMLNode* returnNode = 0;
00498     char* start = p;
00499     p = XMLUtil::SkipWhiteSpace( p );
00500     if( !p || !*p ) {
00501         return p;
00502     }
00503 
00504     // What is this thing?
00505     // - Elements start with a letter or underscore, but xml is reserved.
00506     // - Comments: <!--
00507     // - Decleration: <?
00508     // - Everthing else is unknown to tinyxml.
00509     //
00510 
00511     static const char* xmlHeader                = { "<?" };
00512     static const char* commentHeader    = { "<!--" };
00513     static const char* dtdHeader                = { "<!" };
00514     static const char* cdataHeader              = { "<![CDATA[" };
00515     static const char* elementHeader    = { "<" };      // and a header for everything else; check last.
00516 
00517     static const int xmlHeaderLen               = 2;
00518     static const int commentHeaderLen   = 4;
00519     static const int dtdHeaderLen               = 2;
00520     static const int cdataHeaderLen             = 9;
00521     static const int elementHeaderLen   = 1;
00522 
00523 #if defined(_MSC_VER)
00524 #pragma warning ( push )
00525 #pragma warning ( disable : 4127 )
00526 #endif
00527     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );                // use same memory pool
00528     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
00529 #if defined(_MSC_VER)
00530 #pragma warning (pop)
00531 #endif
00532     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
00533         returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
00534         returnNode->_memPool = &_commentPool;
00535         p += xmlHeaderLen;
00536     }
00537     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
00538         returnNode = new (_commentPool.Alloc()) XMLComment( this );
00539         returnNode->_memPool = &_commentPool;
00540         p += commentHeaderLen;
00541     }
00542     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
00543         XMLText* text = new (_textPool.Alloc()) XMLText( this );
00544         returnNode = text;
00545         returnNode->_memPool = &_textPool;
00546         p += cdataHeaderLen;
00547         text->SetCData( true );
00548     }
00549     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
00550         returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
00551         returnNode->_memPool = &_commentPool;
00552         p += dtdHeaderLen;
00553     }
00554     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
00555         returnNode = new (_elementPool.Alloc()) XMLElement( this );
00556         returnNode->_memPool = &_elementPool;
00557         p += elementHeaderLen;
00558     }
00559     else {
00560         returnNode = new (_textPool.Alloc()) XMLText( this );
00561         returnNode->_memPool = &_textPool;
00562         p = start;      // Back it up, all the text counts.
00563     }
00564 
00565     *node = returnNode;
00566     return p;
00567 }
00568 
00569 
00570 bool XMLDocument::Accept( XMLVisitor* visitor ) const
00571 {
00572     if ( visitor->VisitEnter( *this ) ) {
00573         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
00574             if ( !node->Accept( visitor ) ) {
00575                 break;
00576             }
00577         }
00578     }
00579     return visitor->VisitExit( *this );
00580 }
00581 
00582 
00583 // --------- XMLNode ----------- //
00584 
00585 XMLNode::XMLNode( XMLDocument* doc ) :
00586     _document( doc ),
00587     _parent( 0 ),
00588     _firstChild( 0 ), _lastChild( 0 ),
00589     _prev( 0 ), _next( 0 )
00590 {
00591 }
00592 
00593 
00594 XMLNode::~XMLNode()
00595 {
00596     DeleteChildren();
00597     if ( _parent ) {
00598         _parent->Unlink( this );
00599     }
00600 }
00601 
00602 
00603 void XMLNode::SetValue( const char* str, bool staticMem )
00604 {
00605     if ( staticMem ) {
00606         _value.SetInternedStr( str );
00607     }
00608     else {
00609         _value.SetStr( str );
00610     }
00611 }
00612 
00613 
00614 void XMLNode::DeleteChildren()
00615 {
00616     while( _firstChild ) {
00617         XMLNode* node = _firstChild;
00618         Unlink( node );
00619 
00620         DELETE_NODE( node );
00621     }
00622     _firstChild = _lastChild = 0;
00623 }
00624 
00625 
00626 void XMLNode::Unlink( XMLNode* child )
00627 {
00628     TIXMLASSERT( child->_parent == this );
00629     if ( child == _firstChild ) {
00630         _firstChild = _firstChild->_next;
00631     }
00632     if ( child == _lastChild ) {
00633         _lastChild = _lastChild->_prev;
00634     }
00635 
00636     if ( child->_prev ) {
00637         child->_prev->_next = child->_next;
00638     }
00639     if ( child->_next ) {
00640         child->_next->_prev = child->_prev;
00641     }
00642     child->_parent = 0;
00643 }
00644 
00645 
00646 void XMLNode::DeleteChild( XMLNode* node )
00647 {
00648     TIXMLASSERT( node->_parent == this );
00649     DELETE_NODE( node );
00650 }
00651 
00652 
00653 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
00654 {
00655     if ( _lastChild ) {
00656         TIXMLASSERT( _firstChild );
00657         TIXMLASSERT( _lastChild->_next == 0 );
00658         _lastChild->_next = addThis;
00659         addThis->_prev = _lastChild;
00660         _lastChild = addThis;
00661 
00662         addThis->_next = 0;
00663     }
00664     else {
00665         TIXMLASSERT( _firstChild == 0 );
00666         _firstChild = _lastChild = addThis;
00667 
00668         addThis->_prev = 0;
00669         addThis->_next = 0;
00670     }
00671     addThis->_parent = this;
00672     addThis->_memPool->SetTracked();
00673     return addThis;
00674 }
00675 
00676 
00677 XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
00678 {
00679     if ( _firstChild ) {
00680         TIXMLASSERT( _lastChild );
00681         TIXMLASSERT( _firstChild->_prev == 0 );
00682 
00683         _firstChild->_prev = addThis;
00684         addThis->_next = _firstChild;
00685         _firstChild = addThis;
00686 
00687         addThis->_prev = 0;
00688     }
00689     else {
00690         TIXMLASSERT( _lastChild == 0 );
00691         _firstChild = _lastChild = addThis;
00692 
00693         addThis->_prev = 0;
00694         addThis->_next = 0;
00695     }
00696     addThis->_parent = this;
00697     addThis->_memPool->SetTracked();
00698     return addThis;
00699 }
00700 
00701 
00702 XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
00703 {
00704     TIXMLASSERT( afterThis->_parent == this );
00705     if ( afterThis->_parent != this ) {
00706         return 0;
00707     }
00708 
00709     if ( afterThis->_next == 0 ) {
00710         // The last node or the only node.
00711         return InsertEndChild( addThis );
00712     }
00713     addThis->_prev = afterThis;
00714     addThis->_next = afterThis->_next;
00715     afterThis->_next->_prev = addThis;
00716     afterThis->_next = addThis;
00717     addThis->_parent = this;
00718     addThis->_memPool->SetTracked();
00719     return addThis;
00720 }
00721 
00722 
00723 
00724 
00725 const XMLElement* XMLNode::FirstChildElement( const char* value ) const
00726 {
00727     for( XMLNode* node=_firstChild; node; node=node->_next ) {
00728         XMLElement* element = node->ToElement();
00729         if ( element ) {
00730             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
00731                 return element;
00732             }
00733         }
00734     }
00735     return 0;
00736 }
00737 
00738 
00739 const XMLElement* XMLNode::LastChildElement( const char* value ) const
00740 {
00741     for( XMLNode* node=_lastChild; node; node=node->_prev ) {
00742         XMLElement* element = node->ToElement();
00743         if ( element ) {
00744             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
00745                 return element;
00746             }
00747         }
00748     }
00749     return 0;
00750 }
00751 
00752 
00753 const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
00754 {
00755     for( XMLNode* element=this->_next; element; element = element->_next ) {
00756         if (    element->ToElement()
00757                 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
00758             return element->ToElement();
00759         }
00760     }
00761     return 0;
00762 }
00763 
00764 
00765 const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
00766 {
00767     for( XMLNode* element=_prev; element; element = element->_prev ) {
00768         if (    element->ToElement()
00769                 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
00770             return element->ToElement();
00771         }
00772     }
00773     return 0;
00774 }
00775 
00776 
00777 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
00778 {
00779     // This is a recursive method, but thinking about it "at the current level"
00780     // it is a pretty simple flat list:
00781     //          <foo/>
00782     //          <!-- comment -->
00783     //
00784     // With a special case:
00785     //          <foo>
00786     //          </foo>
00787     //          <!-- comment -->
00788     //
00789     // Where the closing element (/foo) *must* be the next thing after the opening
00790     // element, and the names must match. BUT the tricky bit is that the closing
00791     // element will be read by the child.
00792     //
00793     // 'endTag' is the end tag for this node, it is returned by a call to a child.
00794     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
00795 
00796     while( p && *p ) {
00797         XMLNode* node = 0;
00798 
00799         p = _document->Identify( p, &node );
00800         if ( p == 0 || node == 0 ) {
00801             break;
00802         }
00803 
00804         StrPair endTag;
00805         p = node->ParseDeep( p, &endTag );
00806         if ( !p ) {
00807             DELETE_NODE( node );
00808             node = 0;
00809             if ( !_document->Error() ) {
00810                 _document->SetError( XML_ERROR_PARSING, 0, 0 );
00811             }
00812             break;
00813         }
00814 
00815         // We read the end tag. Return it to the parent.
00816         if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
00817             if ( parentEnd ) {
00818                 *parentEnd = static_cast<XMLElement*>(node)->_value;
00819             }
00820                         node->_memPool->SetTracked();   // created and then immediately deleted.
00821             DELETE_NODE( node );
00822             return p;
00823         }
00824 
00825         // Handle an end tag returned to this level.
00826         // And handle a bunch of annoying errors.
00827         XMLElement* ele = node->ToElement();
00828         if ( ele ) {
00829             if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
00830                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
00831                 p = 0;
00832             }
00833             else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
00834                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
00835                 p = 0;
00836             }
00837             else if ( !endTag.Empty() ) {
00838                 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
00839                     _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
00840                     p = 0;
00841                 }
00842             }
00843         }
00844         if ( p == 0 ) {
00845             DELETE_NODE( node );
00846             node = 0;
00847         }
00848         if ( node ) {
00849             this->InsertEndChild( node );
00850         }
00851     }
00852     return 0;
00853 }
00854 
00855 // --------- XMLText ---------- //
00856 char* XMLText::ParseDeep( char* p, StrPair* )
00857 {
00858     const char* start = p;
00859     if ( this->CData() ) {
00860         p = _value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
00861         if ( !p ) {
00862             _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
00863         }
00864         return p;
00865     }
00866     else {
00867         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
00868         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
00869             flags |= StrPair::COLLAPSE_WHITESPACE;
00870         }
00871 
00872         p = _value.ParseText( p, "<", flags );
00873         if ( !p ) {
00874             _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
00875         }
00876         if ( p && *p ) {
00877             return p-1;
00878         }
00879     }
00880     return 0;
00881 }
00882 
00883 
00884 XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
00885 {
00886     if ( !doc ) {
00887         doc = _document;
00888     }
00889     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
00890     text->SetCData( this->CData() );
00891     return text;
00892 }
00893 
00894 
00895 bool XMLText::ShallowEqual( const XMLNode* compare ) const
00896 {
00897     return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
00898 }
00899 
00900 
00901 bool XMLText::Accept( XMLVisitor* visitor ) const
00902 {
00903     return visitor->Visit( *this );
00904 }
00905 
00906 
00907 // --------- XMLComment ---------- //
00908 
00909 XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
00910 {
00911 }
00912 
00913 
00914 XMLComment::~XMLComment()
00915 {
00916 }
00917 
00918 
00919 char* XMLComment::ParseDeep( char* p, StrPair* )
00920 {
00921     // Comment parses as text.
00922     const char* start = p;
00923     p = _value.ParseText( p, "-->", StrPair::COMMENT );
00924     if ( p == 0 ) {
00925         _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
00926     }
00927     return p;
00928 }
00929 
00930 
00931 XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
00932 {
00933     if ( !doc ) {
00934         doc = _document;
00935     }
00936     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?
00937     return comment;
00938 }
00939 
00940 
00941 bool XMLComment::ShallowEqual( const XMLNode* compare ) const
00942 {
00943     return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
00944 }
00945 
00946 
00947 bool XMLComment::Accept( XMLVisitor* visitor ) const
00948 {
00949     return visitor->Visit( *this );
00950 }
00951 
00952 
00953 // --------- XMLDeclaration ---------- //
00954 
00955 XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
00956 {
00957 }
00958 
00959 
00960 XMLDeclaration::~XMLDeclaration()
00961 {
00962     //printf( "~XMLDeclaration\n" );
00963 }
00964 
00965 
00966 char* XMLDeclaration::ParseDeep( char* p, StrPair* )
00967 {
00968     // Declaration parses as text.
00969     const char* start = p;
00970     p = _value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
00971     if ( p == 0 ) {
00972         _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
00973     }
00974     return p;
00975 }
00976 
00977 
00978 XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
00979 {
00980     if ( !doc ) {
00981         doc = _document;
00982     }
00983     XMLDeclaration* dec = doc->NewDeclaration( Value() );       // fixme: this will always allocate memory. Intern?
00984     return dec;
00985 }
00986 
00987 
00988 bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
00989 {
00990     return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
00991 }
00992 
00993 
00994 
00995 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
00996 {
00997     return visitor->Visit( *this );
00998 }
00999 
01000 // --------- XMLUnknown ---------- //
01001 
01002 XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
01003 {
01004 }
01005 
01006 
01007 XMLUnknown::~XMLUnknown()
01008 {
01009 }
01010 
01011 
01012 char* XMLUnknown::ParseDeep( char* p, StrPair* )
01013 {
01014     // Unknown parses as text.
01015     const char* start = p;
01016 
01017     p = _value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
01018     if ( !p ) {
01019         _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
01020     }
01021     return p;
01022 }
01023 
01024 
01025 XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
01026 {
01027     if ( !doc ) {
01028         doc = _document;
01029     }
01030     XMLUnknown* text = doc->NewUnknown( Value() );      // fixme: this will always allocate memory. Intern?
01031     return text;
01032 }
01033 
01034 
01035 bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
01036 {
01037     return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
01038 }
01039 
01040 
01041 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
01042 {
01043     return visitor->Visit( *this );
01044 }
01045 
01046 // --------- XMLAttribute ---------- //
01047 char* XMLAttribute::ParseDeep( char* p, bool processEntities )
01048 {
01049     // Parse using the name rules: bug fix, was using ParseText before
01050     p = _name.ParseName( p );
01051     if ( !p || !*p ) {
01052         return 0;
01053     }
01054 
01055     // Skip white space before =
01056     p = XMLUtil::SkipWhiteSpace( p );
01057     if ( !p || *p != '=' ) {
01058         return 0;
01059     }
01060 
01061     ++p;        // move up to opening quote
01062     p = XMLUtil::SkipWhiteSpace( p );
01063     if ( *p != '\"' && *p != '\'' ) {
01064         return 0;
01065     }
01066 
01067     char endTag[2] = { *p, 0 };
01068     ++p;        // move past opening quote
01069 
01070     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
01071     return p;
01072 }
01073 
01074 
01075 void XMLAttribute::SetName( const char* n )
01076 {
01077     _name.SetStr( n );
01078 }
01079 
01080 
01081 XMLError XMLAttribute::QueryIntValue( int* value ) const
01082 {
01083     if ( XMLUtil::ToInt( Value(), value )) {
01084         return XML_NO_ERROR;
01085     }
01086     return XML_WRONG_ATTRIBUTE_TYPE;
01087 }
01088 
01089 
01090 XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
01091 {
01092     if ( XMLUtil::ToUnsigned( Value(), value )) {
01093         return XML_NO_ERROR;
01094     }
01095     return XML_WRONG_ATTRIBUTE_TYPE;
01096 }
01097 
01098 
01099 XMLError XMLAttribute::QueryBoolValue( bool* value ) const
01100 {
01101     if ( XMLUtil::ToBool( Value(), value )) {
01102         return XML_NO_ERROR;
01103     }
01104     return XML_WRONG_ATTRIBUTE_TYPE;
01105 }
01106 
01107 
01108 XMLError XMLAttribute::QueryFloatValue( float* value ) const
01109 {
01110     if ( XMLUtil::ToFloat( Value(), value )) {
01111         return XML_NO_ERROR;
01112     }
01113     return XML_WRONG_ATTRIBUTE_TYPE;
01114 }
01115 
01116 
01117 XMLError XMLAttribute::QueryDoubleValue( double* value ) const
01118 {
01119     if ( XMLUtil::ToDouble( Value(), value )) {
01120         return XML_NO_ERROR;
01121     }
01122     return XML_WRONG_ATTRIBUTE_TYPE;
01123 }
01124 
01125 
01126 void XMLAttribute::SetAttribute( const char* v )
01127 {
01128     _value.SetStr( v );
01129 }
01130 
01131 
01132 void XMLAttribute::SetAttribute( int v )
01133 {
01134     char buf[BUF_SIZE];
01135     XMLUtil::ToStr( v, buf, BUF_SIZE );
01136     _value.SetStr( buf );
01137 }
01138 
01139 
01140 void XMLAttribute::SetAttribute( unsigned v )
01141 {
01142     char buf[BUF_SIZE];
01143     XMLUtil::ToStr( v, buf, BUF_SIZE );
01144     _value.SetStr( buf );
01145 }
01146 
01147 
01148 void XMLAttribute::SetAttribute( bool v )
01149 {
01150     char buf[BUF_SIZE];
01151     XMLUtil::ToStr( v, buf, BUF_SIZE );
01152     _value.SetStr( buf );
01153 }
01154 
01155 void XMLAttribute::SetAttribute( double v )
01156 {
01157     char buf[BUF_SIZE];
01158     XMLUtil::ToStr( v, buf, BUF_SIZE );
01159     _value.SetStr( buf );
01160 }
01161 
01162 void XMLAttribute::SetAttribute( float v )
01163 {
01164     char buf[BUF_SIZE];
01165     XMLUtil::ToStr( v, buf, BUF_SIZE );
01166     _value.SetStr( buf );
01167 }
01168 
01169 
01170 // --------- XMLElement ---------- //
01171 XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
01172     _closingType( 0 ),
01173     _rootAttribute( 0 )
01174 {
01175 }
01176 
01177 
01178 XMLElement::~XMLElement()
01179 {
01180     while( _rootAttribute ) {
01181         XMLAttribute* next = _rootAttribute->_next;
01182         DELETE_ATTRIBUTE( _rootAttribute );
01183         _rootAttribute = next;
01184     }
01185 }
01186 
01187 
01188 XMLAttribute* XMLElement::FindAttribute( const char* name )
01189 {
01190     XMLAttribute* a = 0;
01191     for( a=_rootAttribute; a; a = a->_next ) {
01192         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
01193             return a;
01194         }
01195     }
01196     return 0;
01197 }
01198 
01199 
01200 const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
01201 {
01202     XMLAttribute* a = 0;
01203     for( a=_rootAttribute; a; a = a->_next ) {
01204         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
01205             return a;
01206         }
01207     }
01208     return 0;
01209 }
01210 
01211 
01212 const char* XMLElement::Attribute( const char* name, const char* value ) const
01213 {
01214     const XMLAttribute* a = FindAttribute( name );
01215     if ( !a ) {
01216         return 0;
01217     }
01218     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
01219         return a->Value();
01220     }
01221     return 0;
01222 }
01223 
01224 
01225 const char* XMLElement::GetText() const
01226 {
01227     if ( FirstChild() && FirstChild()->ToText() ) {
01228         return FirstChild()->ToText()->Value();
01229     }
01230     return 0;
01231 }
01232 
01233 
01234 XMLError XMLElement::QueryIntText( int* ival ) const
01235 {
01236     if ( FirstChild() && FirstChild()->ToText() ) {
01237         const char* t = FirstChild()->ToText()->Value();
01238         if ( XMLUtil::ToInt( t, ival ) ) {
01239             return XML_SUCCESS;
01240         }
01241         return XML_CAN_NOT_CONVERT_TEXT;
01242     }
01243     return XML_NO_TEXT_NODE;
01244 }
01245 
01246 
01247 XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
01248 {
01249     if ( FirstChild() && FirstChild()->ToText() ) {
01250         const char* t = FirstChild()->ToText()->Value();
01251         if ( XMLUtil::ToUnsigned( t, uval ) ) {
01252             return XML_SUCCESS;
01253         }
01254         return XML_CAN_NOT_CONVERT_TEXT;
01255     }
01256     return XML_NO_TEXT_NODE;
01257 }
01258 
01259 
01260 XMLError XMLElement::QueryBoolText( bool* bval ) const
01261 {
01262     if ( FirstChild() && FirstChild()->ToText() ) {
01263         const char* t = FirstChild()->ToText()->Value();
01264         if ( XMLUtil::ToBool( t, bval ) ) {
01265             return XML_SUCCESS;
01266         }
01267         return XML_CAN_NOT_CONVERT_TEXT;
01268     }
01269     return XML_NO_TEXT_NODE;
01270 }
01271 
01272 
01273 XMLError XMLElement::QueryDoubleText( double* dval ) const
01274 {
01275     if ( FirstChild() && FirstChild()->ToText() ) {
01276         const char* t = FirstChild()->ToText()->Value();
01277         if ( XMLUtil::ToDouble( t, dval ) ) {
01278             return XML_SUCCESS;
01279         }
01280         return XML_CAN_NOT_CONVERT_TEXT;
01281     }
01282     return XML_NO_TEXT_NODE;
01283 }
01284 
01285 
01286 XMLError XMLElement::QueryFloatText( float* fval ) const
01287 {
01288     if ( FirstChild() && FirstChild()->ToText() ) {
01289         const char* t = FirstChild()->ToText()->Value();
01290         if ( XMLUtil::ToFloat( t, fval ) ) {
01291             return XML_SUCCESS;
01292         }
01293         return XML_CAN_NOT_CONVERT_TEXT;
01294     }
01295     return XML_NO_TEXT_NODE;
01296 }
01297 
01298 
01299 
01300 XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
01301 {
01302     XMLAttribute* last = 0;
01303     XMLAttribute* attrib = 0;
01304     for( attrib = _rootAttribute;
01305             attrib;
01306             last = attrib, attrib = attrib->_next ) {
01307         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
01308             break;
01309         }
01310     }
01311     if ( !attrib ) {
01312         attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
01313         attrib->_memPool = &_document->_attributePool;
01314         if ( last ) {
01315             last->_next = attrib;
01316         }
01317         else {
01318             _rootAttribute = attrib;
01319         }
01320         attrib->SetName( name );
01321         attrib->_memPool->SetTracked(); // always created and linked.
01322     }
01323     return attrib;
01324 }
01325 
01326 
01327 void XMLElement::DeleteAttribute( const char* name )
01328 {
01329     XMLAttribute* prev = 0;
01330     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
01331         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
01332             if ( prev ) {
01333                 prev->_next = a->_next;
01334             }
01335             else {
01336                 _rootAttribute = a->_next;
01337             }
01338             DELETE_ATTRIBUTE( a );
01339             break;
01340         }
01341         prev = a;
01342     }
01343 }
01344 
01345 
01346 char* XMLElement::ParseAttributes( char* p )
01347 {
01348     const char* start = p;
01349     XMLAttribute* prevAttribute = 0;
01350 
01351     // Read the attributes.
01352     while( p ) {
01353         p = XMLUtil::SkipWhiteSpace( p );
01354         if ( !p || !(*p) ) {
01355             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
01356             return 0;
01357         }
01358 
01359         // attribute.
01360         if ( XMLUtil::IsAlpha( *p ) ) {
01361             XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
01362             attrib->_memPool = &_document->_attributePool;
01363                         attrib->_memPool->SetTracked();
01364 
01365             p = attrib->ParseDeep( p, _document->ProcessEntities() );
01366             if ( !p || Attribute( attrib->Name() ) ) {
01367                 DELETE_ATTRIBUTE( attrib );
01368                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
01369                 return 0;
01370             }
01371             // There is a minor bug here: if the attribute in the source xml
01372             // document is duplicated, it will not be detected and the
01373             // attribute will be doubly added. However, tracking the 'prevAttribute'
01374             // avoids re-scanning the attribute list. Preferring performance for
01375             // now, may reconsider in the future.
01376             if ( prevAttribute ) {
01377                 prevAttribute->_next = attrib;
01378             }
01379             else {
01380                 _rootAttribute = attrib;
01381             }
01382             prevAttribute = attrib;
01383         }
01384         // end of the tag
01385         else if ( *p == '/' && *(p+1) == '>' ) {
01386             _closingType = CLOSED;
01387             return p+2; // done; sealed element.
01388         }
01389         // end of the tag
01390         else if ( *p == '>' ) {
01391             ++p;
01392             break;
01393         }
01394         else {
01395             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
01396             return 0;
01397         }
01398     }
01399     return p;
01400 }
01401 
01402 
01403 //
01404 //      <ele></ele>
01405 //      <ele>foo<b>bar</b></ele>
01406 //
01407 char* XMLElement::ParseDeep( char* p, StrPair* strPair )
01408 {
01409     // Read the element name.
01410     p = XMLUtil::SkipWhiteSpace( p );
01411     if ( !p ) {
01412         return 0;
01413     }
01414 
01415     // The closing element is the </element> form. It is
01416     // parsed just like a regular element then deleted from
01417     // the DOM.
01418     if ( *p == '/' ) {
01419         _closingType = CLOSING;
01420         ++p;
01421     }
01422 
01423     p = _value.ParseName( p );
01424     if ( _value.Empty() ) {
01425         return 0;
01426     }
01427 
01428     p = ParseAttributes( p );
01429     if ( !p || !*p || _closingType ) {
01430         return p;
01431     }
01432 
01433     p = XMLNode::ParseDeep( p, strPair );
01434     return p;
01435 }
01436 
01437 
01438 
01439 XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
01440 {
01441     if ( !doc ) {
01442         doc = _document;
01443     }
01444     XMLElement* element = doc->NewElement( Value() );                                   // fixme: this will always allocate memory. Intern?
01445     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
01446         element->SetAttribute( a->Name(), a->Value() );                                 // fixme: this will always allocate memory. Intern?
01447     }
01448     return element;
01449 }
01450 
01451 
01452 bool XMLElement::ShallowEqual( const XMLNode* compare ) const
01453 {
01454     const XMLElement* other = compare->ToElement();
01455     if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
01456 
01457         const XMLAttribute* a=FirstAttribute();
01458         const XMLAttribute* b=other->FirstAttribute();
01459 
01460         while ( a && b ) {
01461             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
01462                 return false;
01463             }
01464             a = a->Next();
01465             b = b->Next();
01466         }
01467         if ( a || b ) {
01468             // different count
01469             return false;
01470         }
01471         return true;
01472     }
01473     return false;
01474 }
01475 
01476 
01477 bool XMLElement::Accept( XMLVisitor* visitor ) const
01478 {
01479     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
01480         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
01481             if ( !node->Accept( visitor ) ) {
01482                 break;
01483             }
01484         }
01485     }
01486     return visitor->VisitExit( *this );
01487 }
01488 
01489 
01490 // --------- XMLDocument ----------- //
01491 XMLDocument::XMLDocument( bool processEntities, Whitespace whitespace ) :
01492     XMLNode( 0 ),
01493     _writeBOM( false ),
01494     _processEntities( processEntities ),
01495     _errorID( XML_NO_ERROR ),
01496     _whitespace( whitespace ),
01497     _errorStr1( 0 ),
01498     _errorStr2( 0 ),
01499     _charBuffer( 0 )
01500 {
01501     _document = this;   // avoid warning about 'this' in initializer list
01502 }
01503 
01504 
01505 XMLDocument::~XMLDocument()
01506 {
01507     DeleteChildren();
01508     delete [] _charBuffer;
01509 
01510 #if 0
01511     textPool.Trace( "text" );
01512     elementPool.Trace( "element" );
01513     commentPool.Trace( "comment" );
01514     attributePool.Trace( "attribute" );
01515 #endif
01516 
01517 #ifdef DEBUG
01518         if ( Error() == false ) {
01519                 TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
01520                 TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
01521                 TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
01522                 TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
01523         }
01524 #endif
01525 }
01526 
01527 
01528 void XMLDocument::InitDocument()
01529 {
01530     _errorID = XML_NO_ERROR;
01531     _errorStr1 = 0;
01532     _errorStr2 = 0;
01533 
01534     delete [] _charBuffer;
01535     _charBuffer = 0;
01536 }
01537 
01538 
01539 XMLElement* XMLDocument::NewElement( const char* name )
01540 {
01541     XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
01542     ele->_memPool = &_elementPool;
01543     ele->SetName( name );
01544     return ele;
01545 }
01546 
01547 
01548 XMLComment* XMLDocument::NewComment( const char* str )
01549 {
01550     XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
01551     comment->_memPool = &_commentPool;
01552     comment->SetValue( str );
01553     return comment;
01554 }
01555 
01556 
01557 XMLText* XMLDocument::NewText( const char* str )
01558 {
01559     XMLText* text = new (_textPool.Alloc()) XMLText( this );
01560     text->_memPool = &_textPool;
01561     text->SetValue( str );
01562     return text;
01563 }
01564 
01565 
01566 XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
01567 {
01568     XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
01569     dec->_memPool = &_commentPool;
01570     dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
01571     return dec;
01572 }
01573 
01574 
01575 XMLUnknown* XMLDocument::NewUnknown( const char* str )
01576 {
01577     XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
01578     unk->_memPool = &_commentPool;
01579     unk->SetValue( str );
01580     return unk;
01581 }
01582 
01583 
01584 XMLError XMLDocument::LoadFile( const char* filename )
01585 {
01586     DeleteChildren();
01587     InitDocument();
01588     FILE* fp = 0;
01589 
01590 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
01591     errno_t err = fopen_s(&fp, filename, "rb" );
01592     if ( !fp || err) {
01593 #else
01594     fp = fopen( filename, "rb" );
01595     if ( !fp) {
01596 #endif
01597         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
01598         return _errorID;
01599     }
01600     LoadFile( fp );
01601     fclose( fp );
01602     return _errorID;
01603 }
01604 
01605 
01606 XMLError XMLDocument::LoadFile( FILE* fp )
01607 {
01608     DeleteChildren();
01609     InitDocument();
01610 
01611     fseek( fp, 0, SEEK_END );
01612     size_t size = ftell( fp );
01613     fseek( fp, 0, SEEK_SET );
01614 
01615     if ( size == 0 ) {
01616         return _errorID;
01617     }
01618 
01619     _charBuffer = new char[size+1];
01620     size_t read = fread( _charBuffer, 1, size, fp );
01621     if ( read != size ) {
01622         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
01623         return _errorID;
01624     }
01625 
01626     _charBuffer[size] = 0;
01627 
01628     const char* p = _charBuffer;
01629     p = XMLUtil::SkipWhiteSpace( p );
01630     p = XMLUtil::ReadBOM( p, &_writeBOM );
01631     if ( !p || !*p ) {
01632         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
01633         return _errorID;
01634     }
01635 
01636     ParseDeep( _charBuffer + (p-_charBuffer), 0 );
01637     return _errorID;
01638 }
01639 
01640 
01641 XMLError XMLDocument::SaveFile( const char* filename, bool compact )
01642 {
01643     FILE* fp = 0;
01644 #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
01645     errno_t err = fopen_s(&fp, filename, "w" );
01646     if ( !fp || err) {
01647 #else
01648     fp = fopen( filename, "w" );
01649     if ( !fp) {
01650 #endif
01651         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
01652         return _errorID;
01653     }
01654     SaveFile(fp, compact);
01655     fclose( fp );
01656     return _errorID;
01657 }
01658 
01659 
01660 XMLError XMLDocument::SaveFile( FILE* fp, bool compact )
01661 {
01662     XMLPrinter stream( fp, compact );
01663     Print( &stream );
01664     return _errorID;
01665 }
01666 
01667 
01668 XMLError XMLDocument::Parse( const char* p, size_t len )
01669 {
01670     DeleteChildren();
01671     InitDocument();
01672 
01673     if ( !p || !*p ) {
01674         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
01675         return _errorID;
01676     }
01677     if ( len == (size_t)(-1) ) {
01678         len = strlen( p );
01679     }
01680     _charBuffer = new char[ len+1 ];
01681     memcpy( _charBuffer, p, len );
01682     _charBuffer[len] = 0;
01683 
01684     p = XMLUtil::SkipWhiteSpace( p );
01685     p = XMLUtil::ReadBOM( p, &_writeBOM );
01686     if ( !p || !*p ) {
01687         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
01688         return _errorID;
01689     }
01690 
01691     ParseDeep( _charBuffer, 0 );
01692     return _errorID;
01693 }
01694 
01695 
01696 void XMLDocument::Print( XMLPrinter* streamer )
01697 {
01698     XMLPrinter stdStreamer( stdout );
01699     if ( !streamer ) {
01700         streamer = &stdStreamer;
01701     }
01702     Accept( streamer );
01703 }
01704 
01705 
01706 void XMLDocument::SetError( XMLError error, const char* str1, const char* str2 )
01707 {
01708     _errorID = error;
01709     _errorStr1 = str1;
01710     _errorStr2 = str2;
01711 }
01712 
01713 
01714 void XMLDocument::PrintError() const
01715 {
01716     if ( _errorID ) {
01717         static const int LEN = 20;
01718         char buf1[LEN] = { 0 };
01719         char buf2[LEN] = { 0 };
01720 
01721         if ( _errorStr1 ) {
01722             TIXML_SNPRINTF( buf1, LEN, "%s", _errorStr1 );
01723         }
01724         if ( _errorStr2 ) {
01725             TIXML_SNPRINTF( buf2, LEN, "%s", _errorStr2 );
01726         }
01727 
01728         printf( "XMLDocument error id=%d str1=%s str2=%s\n",
01729                 _errorID, buf1, buf2 );
01730     }
01731 }
01732 
01733 
01734 XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
01735     _elementJustOpened( false ),
01736     _firstElement( true ),
01737     _fp( file ),
01738     _depth( 0 ),
01739     _textDepth( -1 ),
01740     _processEntities( true ),
01741     _compactMode( compact )
01742 {
01743     for( int i=0; i<ENTITY_RANGE; ++i ) {
01744         _entityFlag[i] = false;
01745         _restrictedEntityFlag[i] = false;
01746     }
01747     for( int i=0; i<NUM_ENTITIES; ++i ) {
01748         TIXMLASSERT( entities[i].value < ENTITY_RANGE );
01749         if ( entities[i].value < ENTITY_RANGE ) {
01750             _entityFlag[ (int)entities[i].value ] = true;
01751         }
01752     }
01753     _restrictedEntityFlag[(int)'&'] = true;
01754     _restrictedEntityFlag[(int)'<'] = true;
01755     _restrictedEntityFlag[(int)'>'] = true;     // not required, but consistency is nice
01756     _buffer.Push( 0 );
01757 }
01758 
01759 
01760 void XMLPrinter::Print( const char* format, ... )
01761 {
01762     va_list     va;
01763     va_start( va, format );
01764 
01765     if ( _fp ) {
01766         vfprintf( _fp, format, va );
01767     }
01768     else {
01769         // This seems brutally complex. Haven't figured out a better
01770         // way on windows.
01771 #ifdef _MSC_VER
01772         int len = -1;
01773         int expand = 1000;
01774         while ( len < 0 ) {
01775             len = vsnprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
01776             if ( len < 0 ) {
01777                 expand *= 3/2;
01778                 _accumulator.PushArr( expand );
01779             }
01780         }
01781         char* p = _buffer.PushArr( len ) - 1;
01782         memcpy( p, _accumulator.Mem(), len+1 );
01783 #else
01784         int len = vsnprintf( 0, 0, format, va );
01785         // Close out and re-start the va-args
01786         va_end( va );
01787         va_start( va, format );
01788         char* p = _buffer.PushArr( len ) - 1;
01789         vsnprintf( p, len+1, format, va );
01790 #endif
01791     }
01792     va_end( va );
01793 }
01794 
01795 
01796 void XMLPrinter::PrintSpace( int depth )
01797 {
01798     for( int i=0; i<depth; ++i ) {
01799         Print( "    " );
01800     }
01801 }
01802 
01803 
01804 void XMLPrinter::PrintString( const char* p, bool restricted )
01805 {
01806     // Look for runs of bytes between entities to print.
01807     const char* q = p;
01808     const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
01809 
01810     if ( _processEntities ) {
01811         while ( *q ) {
01812             // Remember, char is sometimes signed. (How many times has that bitten me?)
01813             if ( *q > 0 && *q < ENTITY_RANGE ) {
01814                 // Check for entities. If one is found, flush
01815                 // the stream up until the entity, write the
01816                 // entity, and keep looking.
01817                 if ( flag[(unsigned)(*q)] ) {
01818                     while ( p < q ) {
01819                         Print( "%c", *p );
01820                         ++p;
01821                     }
01822                     for( int i=0; i<NUM_ENTITIES; ++i ) {
01823                         if ( entities[i].value == *q ) {
01824                             Print( "&%s;", entities[i].pattern );
01825                             break;
01826                         }
01827                     }
01828                     ++p;
01829                 }
01830             }
01831             ++q;
01832         }
01833     }
01834     // Flush the remaining string. This will be the entire
01835     // string if an entity wasn't found.
01836     if ( !_processEntities || (q-p > 0) ) {
01837         Print( "%s", p );
01838     }
01839 }
01840 
01841 
01842 void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
01843 {
01844     static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
01845     if ( writeBOM ) {
01846         Print( "%s", bom );
01847     }
01848     if ( writeDec ) {
01849         PushDeclaration( "xml version=\"1.0\"" );
01850     }
01851 }
01852 
01853 
01854 void XMLPrinter::OpenElement( const char* name )
01855 {
01856     if ( _elementJustOpened ) {
01857         SealElement();
01858     }
01859     _stack.Push( name );
01860 
01861     if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
01862         Print( "\n" );
01863         PrintSpace( _depth );
01864     }
01865 
01866     Print( "<%s", name );
01867     _elementJustOpened = true;
01868     _firstElement = false;
01869     ++_depth;
01870 }
01871 
01872 
01873 void XMLPrinter::PushAttribute( const char* name, const char* value )
01874 {
01875     TIXMLASSERT( _elementJustOpened );
01876     Print( " %s=\"", name );
01877     PrintString( value, false );
01878     Print( "\"" );
01879 }
01880 
01881 
01882 void XMLPrinter::PushAttribute( const char* name, int v )
01883 {
01884     char buf[BUF_SIZE];
01885     XMLUtil::ToStr( v, buf, BUF_SIZE );
01886     PushAttribute( name, buf );
01887 }
01888 
01889 
01890 void XMLPrinter::PushAttribute( const char* name, unsigned v )
01891 {
01892     char buf[BUF_SIZE];
01893     XMLUtil::ToStr( v, buf, BUF_SIZE );
01894     PushAttribute( name, buf );
01895 }
01896 
01897 
01898 void XMLPrinter::PushAttribute( const char* name, bool v )
01899 {
01900     char buf[BUF_SIZE];
01901     XMLUtil::ToStr( v, buf, BUF_SIZE );
01902     PushAttribute( name, buf );
01903 }
01904 
01905 
01906 void XMLPrinter::PushAttribute( const char* name, double v )
01907 {
01908     char buf[BUF_SIZE];
01909     XMLUtil::ToStr( v, buf, BUF_SIZE );
01910     PushAttribute( name, buf );
01911 }
01912 
01913 
01914 void XMLPrinter::CloseElement()
01915 {
01916     --_depth;
01917     const char* name = _stack.Pop();
01918 
01919     if ( _elementJustOpened ) {
01920         Print( "/>" );
01921     }
01922     else {
01923         if ( _textDepth < 0 && !_compactMode) {
01924             Print( "\n" );
01925             PrintSpace( _depth );
01926         }
01927         Print( "</%s>", name );
01928     }
01929 
01930     if ( _textDepth == _depth ) {
01931         _textDepth = -1;
01932     }
01933     if ( _depth == 0 && !_compactMode) {
01934         Print( "\n" );
01935     }
01936     _elementJustOpened = false;
01937 }
01938 
01939 
01940 void XMLPrinter::SealElement()
01941 {
01942     _elementJustOpened = false;
01943     Print( ">" );
01944 }
01945 
01946 
01947 void XMLPrinter::PushText( const char* text, bool cdata )
01948 {
01949     _textDepth = _depth-1;
01950 
01951     if ( _elementJustOpened ) {
01952         SealElement();
01953     }
01954     if ( cdata ) {
01955         Print( "<![CDATA[" );
01956         Print( "%s", text );
01957         Print( "]]>" );
01958     }
01959     else {
01960         PrintString( text, true );
01961     }
01962 }
01963 
01964 void XMLPrinter::PushText( int value )
01965 {
01966     char buf[BUF_SIZE];
01967     XMLUtil::ToStr( value, buf, BUF_SIZE );
01968     PushText( buf, false );
01969 }
01970 
01971 
01972 void XMLPrinter::PushText( unsigned value )
01973 {
01974     char buf[BUF_SIZE];
01975     XMLUtil::ToStr( value, buf, BUF_SIZE );
01976     PushText( buf, false );
01977 }
01978 
01979 
01980 void XMLPrinter::PushText( bool value )
01981 {
01982     char buf[BUF_SIZE];
01983     XMLUtil::ToStr( value, buf, BUF_SIZE );
01984     PushText( buf, false );
01985 }
01986 
01987 
01988 void XMLPrinter::PushText( float value )
01989 {
01990     char buf[BUF_SIZE];
01991     XMLUtil::ToStr( value, buf, BUF_SIZE );
01992     PushText( buf, false );
01993 }
01994 
01995 
01996 void XMLPrinter::PushText( double value )
01997 {
01998     char buf[BUF_SIZE];
01999     XMLUtil::ToStr( value, buf, BUF_SIZE );
02000     PushText( buf, false );
02001 }
02002 
02003 
02004 void XMLPrinter::PushComment( const char* comment )
02005 {
02006     if ( _elementJustOpened ) {
02007         SealElement();
02008     }
02009     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02010         Print( "\n" );
02011         PrintSpace( _depth );
02012     }
02013     _firstElement = false;
02014     Print( "<!--%s-->", comment );
02015 }
02016 
02017 
02018 void XMLPrinter::PushDeclaration( const char* value )
02019 {
02020     if ( _elementJustOpened ) {
02021         SealElement();
02022     }
02023     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02024         Print( "\n" );
02025         PrintSpace( _depth );
02026     }
02027     _firstElement = false;
02028     Print( "<?%s?>", value );
02029 }
02030 
02031 
02032 void XMLPrinter::PushUnknown( const char* value )
02033 {
02034     if ( _elementJustOpened ) {
02035         SealElement();
02036     }
02037     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
02038         Print( "\n" );
02039         PrintSpace( _depth );
02040     }
02041     _firstElement = false;
02042     Print( "<!%s>", value );
02043 }
02044 
02045 
02046 bool XMLPrinter::VisitEnter( const XMLDocument& doc )
02047 {
02048     _processEntities = doc.ProcessEntities();
02049     if ( doc.HasBOM() ) {
02050         PushHeader( true, false );
02051     }
02052     return true;
02053 }
02054 
02055 
02056 bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
02057 {
02058     OpenElement( element.Name() );
02059     while ( attribute ) {
02060         PushAttribute( attribute->Name(), attribute->Value() );
02061         attribute = attribute->Next();
02062     }
02063     return true;
02064 }
02065 
02066 
02067 bool XMLPrinter::VisitExit( const XMLElement& )
02068 {
02069     CloseElement();
02070     return true;
02071 }
02072 
02073 
02074 bool XMLPrinter::Visit( const XMLText& text )
02075 {
02076     PushText( text.Value(), text.CData() );
02077     return true;
02078 }
02079 
02080 
02081 bool XMLPrinter::Visit( const XMLComment& comment )
02082 {
02083     PushComment( comment.Value() );
02084     return true;
02085 }
02086 
02087 bool XMLPrinter::Visit( const XMLDeclaration& declaration )
02088 {
02089     PushDeclaration( declaration.Value() );
02090     return true;
02091 }
02092 
02093 
02094 bool XMLPrinter::Visit( const XMLUnknown& unknown )
02095 {
02096     PushUnknown( unknown.Value() );
02097     return true;
02098 }
02099 
02100 }   // namespace tinyxml2
02101 


oculus_sdk
Author(s): Tully Foote
autogenerated on Thu Jun 6 2019 20:13:49