Guest User

tinyxml2 unicode wchar_t version

a guest
Jan 20th, 2013
1,826
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 52.56 KB | None | 0 0
  1. #include "stdafx.h"
  2. /*
  3. Original code by Lee Thomason (www.grinninglizard.com)
  4. wchar_t port by dUkk
  5.  
  6.  
  7. This software is provided 'as-is', without any express or implied
  8. warranty. In no event will the authors be held liable for any
  9. damages arising from the use of this software.
  10.  
  11. Permission is granted to anyone to use this software for any
  12. purpose, including commercial applications, and to alter it and
  13. redistribute it freely, subject to the following restrictions:
  14.  
  15. 1. The origin of this software must not be misrepresented; you must
  16. not claim that you wrote the original software. If you use this
  17. software in a product, an acknowledgment in the product documentation
  18. would be appreciated but is not required.
  19.  
  20. 2. Altered source versions must be plainly marked as such, and
  21. must not be misrepresented as being the original software.
  22.  
  23. 3. This notice may not be removed or altered from any source
  24. distribution.
  25. */
  26.  
  27. #include "tinyxml2.h"
  28.  
  29. #include <new>      // yes, this one new style header, is in the Android SDK.
  30. #   ifdef ANDROID_NDK
  31. #   include <stddef.h>
  32. #else
  33. #   include <cstddef>
  34. #endif
  35.  
  36. static const char LINE_FEED             = (char)0x0a;           // all line endings are normalized to LF
  37. static const char LF = LINE_FEED;
  38. static const char CARRIAGE_RETURN       = (char)0x0d;           // CR gets filtered out
  39. static const char CR = CARRIAGE_RETURN;
  40. static const char SINGLE_QUOTE          = '\'';
  41. static const char DOUBLE_QUOTE          = '\"';
  42.  
  43. // Bunch of unicode info at:
  44. //      http://www.unicode.org/faq/utf_bom.html
  45. //  ef bb bf (Microsoft "lead bytes") - designates UTF-8
  46.  
  47. static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
  48. static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
  49. static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
  50.  
  51.  
  52. #define DELETE_NODE( node ) {           \
  53.         if ( node ) {                       \
  54.             MemPool* pool = node->_memPool; \
  55.             node->~XMLNode();               \
  56.             pool->Free( node );             \
  57.         }                                   \
  58.     }
  59. #define DELETE_ATTRIBUTE( attrib ) {        \
  60.         if ( attrib ) {                         \
  61.             MemPool* pool = attrib->_memPool;   \
  62.             attrib->~XMLAttribute();            \
  63.             pool->Free( attrib );               \
  64.         }                                       \
  65.     }
  66.  
  67. namespace tinyxml2
  68. {
  69.  
  70. struct Entity {
  71.     const wchar_t* pattern;
  72.     int length;
  73.     wchar_t value;
  74. };
  75.  
  76. static const int NUM_ENTITIES = 5;
  77. static const Entity entities[NUM_ENTITIES] = {
  78.     { L"quot", 4,   DOUBLE_QUOTE },
  79.     { L"amp", 3,        '&'  },
  80.     { L"apos", 4,   SINGLE_QUOTE },
  81.     { L"lt",    2,      '<'  },
  82.     { L"gt",    2,      '>'  }
  83. };
  84.  
  85.  
  86. StrPair::~StrPair()
  87. {
  88.     Reset();
  89. }
  90.  
  91.  
  92. void StrPair::Reset()
  93. {
  94.     if ( _flags & NEEDS_DELETE ) {
  95.         delete [] _start;
  96.     }
  97.     _flags = 0;
  98.     _start = 0;
  99.     _end = 0;
  100. }
  101.  
  102.  
  103. void StrPair::SetStr( const wchar_t* str, int flags )
  104. {
  105.     Reset();
  106.     size_t len = wcslen( str );
  107.     _start = new wchar_t[ len+1 ];
  108.     wmemcpy( _start, str, len+1 );
  109.     _end = _start + len;
  110.     _flags = flags | NEEDS_DELETE;
  111. }
  112.  
  113.  
  114. wchar_t* StrPair::ParseText( wchar_t* p, const wchar_t* endTag, int strFlags )
  115. {
  116.     TIXMLASSERT( endTag && *endTag );
  117.  
  118.     wchar_t* start = p; // fixme: hides a member
  119.     wchar_t  endChar = *endTag;
  120.     size_t length = wcslen( endTag );
  121.  
  122.     // Inner loop of text parsing.
  123.     while ( *p ) {
  124.         if ( *p == endChar && wcsncmp( p, endTag, length ) == 0 ) {
  125.             Set( start, p, strFlags );
  126.             return p + length;
  127.         }
  128.         ++p;
  129.     }
  130.     return 0;
  131. }
  132.  
  133.  
  134. wchar_t* StrPair::ParseName( wchar_t* p )
  135. {
  136.     wchar_t* start = p;
  137.  
  138.     if ( !start || !(*start) ) {
  139.         return 0;
  140.     }
  141.  
  142.     while( *p && (
  143.                 XMLUtil::IsAlphaNum( (unsigned char) *p )
  144.                 || *p == '_'
  145.                 || *p == ':'
  146.                 || (*p == '-' && p>start )      // can be in a name, but not lead it.
  147.                 || (*p == '.' && p>start ) )) { // can be in a name, but not lead it.
  148.         ++p;
  149.     }
  150.  
  151.     if ( p > start ) {
  152.         Set( start, p, 0 );
  153.         return p;
  154.     }
  155.     return 0;
  156. }
  157.  
  158.  
  159. void StrPair::CollapseWhitespace()
  160. {
  161.     // Trim leading space.
  162.     _start = XMLUtil::SkipWhiteSpace( _start );
  163.  
  164.     if ( _start && *_start ) {
  165.         wchar_t* p = _start;    // the read pointer
  166.         wchar_t* q = _start;    // the write pointer
  167.  
  168.         while( *p ) {
  169.             if ( XMLUtil::IsWhiteSpace( *p )) {
  170.                 p = XMLUtil::SkipWhiteSpace( p );
  171.                 if ( *p == 0 ) {
  172.                     break;    // don't write to q; this trims the trailing space.
  173.                 }
  174.                 *q = ' ';
  175.                 ++q;
  176.             }
  177.             *q = *p;
  178.             ++q;
  179.             ++p;
  180.         }
  181.         *q = 0;
  182.     }
  183. }
  184.  
  185. const wchar_t* StrPair::GetStr()
  186. {
  187.     if ( _flags & NEEDS_FLUSH ) {
  188.         *_end = 0;
  189.         _flags ^= NEEDS_FLUSH;
  190.  
  191.         if ( _flags ) {
  192.             wchar_t* p = _start;    // the read pointer
  193.             wchar_t* q = _start;    // the write pointer
  194.  
  195.             while( p < _end ) {
  196.                 if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
  197.                     // CR-LF pair becomes LF
  198.                     // CR alone becomes LF
  199.                     // LF-CR becomes LF
  200.                     if ( *(p+1) == LF ) {
  201.                         p += 2;
  202.                     }
  203.                     else {
  204.                         ++p;
  205.                     }
  206.                     *q++ = LF;
  207.                 }
  208.                 else if ( (_flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
  209.                     if ( *(p+1) == CR ) {
  210.                         p += 2;
  211.                     }
  212.                     else {
  213.                         ++p;
  214.                     }
  215.                     *q++ = LF;
  216.                 }
  217.                 else if ( (_flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
  218.                     // Entities handled by tinyXML2:
  219.                     // - special entities in the entity table [in/out]
  220.                     // - numeric character reference [in]
  221.                     //   &#20013; or &#x4e2d;
  222.  
  223.                     if ( *(p+1) == '#' ) {
  224.                         wchar_t buf[10] = { 0 };
  225.                         int len;
  226.                         p = const_cast<wchar_t*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
  227.                         for( int i=0; i<len; ++i ) {
  228.                             *q++ = buf[i];
  229.                         }
  230.                         TIXMLASSERT( q <= p );
  231.                     }
  232.                     else {
  233.                         int i=0;
  234.                         for(; i<NUM_ENTITIES; ++i ) {
  235.                             if (    wcsncmp( p+1, entities[i].pattern, entities[i].length ) == 0
  236.                                     && *(p+entities[i].length+1) == ';' ) {
  237.                                 // Found an entity convert;
  238.                                 *q = entities[i].value;
  239.                                 ++q;
  240.                                 p += entities[i].length + 2;
  241.                                 break;
  242.                             }
  243.                         }
  244.                         if ( i == NUM_ENTITIES ) {
  245.                             // fixme: treat as error?
  246.                             ++p;
  247.                             ++q;
  248.                         }
  249.                     }
  250.                 }
  251.                 else {
  252.                     *q = *p;
  253.                     ++p;
  254.                     ++q;
  255.                 }
  256.             }
  257.             *q = 0;
  258.         }
  259.         // The loop below has plenty going on, and this
  260.         // is a less useful mode. Break it out.
  261.         if ( _flags & COLLAPSE_WHITESPACE ) {
  262.             CollapseWhitespace();
  263.         }
  264.         _flags = (_flags & NEEDS_DELETE);
  265.     }
  266.     return _start;
  267. }
  268.  
  269.  
  270.  
  271.  
  272. // --------- XMLUtil ----------- //
  273.  
  274. const wchar_t* XMLUtil::ReadBOM( const wchar_t* p, bool* bom )
  275. {
  276.     *bom = false;
  277.     const wchar_t* pu = p;
  278.     // Check for BOM:
  279.     if (    *(pu+0) == TIXML_UTF_LEAD_0
  280.             && *(pu+1) == TIXML_UTF_LEAD_1
  281.             && *(pu+2) == TIXML_UTF_LEAD_2 ) {
  282.         *bom = true;
  283.         p += 3;
  284.     }
  285.     return p;
  286. }
  287.  
  288.  
  289. void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, wchar_t* output, int* length )
  290. {
  291.     const unsigned long BYTE_MASK = 0xBF;
  292.     const unsigned long BYTE_MARK = 0x80;
  293.     const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
  294.  
  295.     if (input < 0x80) {
  296.         *length = 1;
  297.     }
  298.     else if ( input < 0x800 ) {
  299.         *length = 2;
  300.     }
  301.     else if ( input < 0x10000 ) {
  302.         *length = 3;
  303.     }
  304.     else if ( input < 0x200000 ) {
  305.         *length = 4;
  306.     }
  307.     else {
  308.         *length = 0;    // This code won't covert this correctly anyway.
  309.         return;
  310.     }
  311.  
  312.     output += *length;
  313.  
  314.     // Scary scary fall throughs.
  315.     switch (*length) {
  316.         case 4:
  317.             --output;
  318.             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
  319.             input >>= 6;
  320.         case 3:
  321.             --output;
  322.             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
  323.             input >>= 6;
  324.         case 2:
  325.             --output;
  326.             *output = (char)((input | BYTE_MARK) & BYTE_MASK);
  327.             input >>= 6;
  328.         case 1:
  329.             --output;
  330.             *output = (char)(input | FIRST_BYTE_MARK[*length]);
  331.         default:
  332.             break;
  333.     }
  334. }
  335.  
  336.  
  337. const wchar_t* XMLUtil::GetCharacterRef( const wchar_t* p, wchar_t* value, int* length )
  338. {
  339.     // Presume an entity, and pull it out.
  340.     *length = 0;
  341.  
  342.     if ( *(p+1) == '#' && *(p+2) ) {
  343.         unsigned long ucs = 0;
  344.         ptrdiff_t delta = 0;
  345.         unsigned mult = 1;
  346.  
  347.         if ( *(p+2) == 'x' ) {
  348.             // Hexadecimal.
  349.             if ( !*(p+3) ) {
  350.                 return 0;
  351.             }
  352.  
  353.             const wchar_t* q = p+3;
  354.             q = wcschr( q, ';' );
  355.  
  356.             if ( !q || !*q ) {
  357.                 return 0;
  358.             }
  359.  
  360.             delta = q-p;
  361.             --q;
  362.  
  363.             while ( *q != 'x' ) {
  364.                 if ( *q >= '0' && *q <= '9' ) {
  365.                     ucs += mult * (*q - '0');
  366.                 }
  367.                 else if ( *q >= 'a' && *q <= 'f' ) {
  368.                     ucs += mult * (*q - 'a' + 10);
  369.                 }
  370.                 else if ( *q >= 'A' && *q <= 'F' ) {
  371.                     ucs += mult * (*q - 'A' + 10 );
  372.                 }
  373.                 else {
  374.                     return 0;
  375.                 }
  376.                 mult *= 16;
  377.                 --q;
  378.             }
  379.         }
  380.         else {
  381.             // Decimal.
  382.             if ( !*(p+2) ) {
  383.                 return 0;
  384.             }
  385.  
  386.             const wchar_t* q = p+2;
  387.             q = wcschr( q, ';' );
  388.  
  389.             if ( !q || !*q ) {
  390.                 return 0;
  391.             }
  392.  
  393.             delta = q-p;
  394.             --q;
  395.  
  396.             while ( *q != '#' ) {
  397.                 if ( *q >= '0' && *q <= '9' ) {
  398.                     ucs += mult * (*q - '0');
  399.                 }
  400.                 else {
  401.                     return 0;
  402.                 }
  403.                 mult *= 10;
  404.                 --q;
  405.             }
  406.         }
  407.         // convert the UCS to UTF-8
  408.         ConvertUTF32ToUTF8( ucs, value, length );
  409.         return p + delta + 1;
  410.     }
  411.     return p+1;
  412. }
  413.  
  414.  
  415. void XMLUtil::ToStr( int v, wchar_t* buffer, int bufferSize )
  416. {
  417.     TIXML_SNPRINTF( buffer, bufferSize, L"%d", v );
  418. }
  419.  
  420.  
  421. void XMLUtil::ToStr( unsigned v, wchar_t* buffer, int bufferSize )
  422. {
  423.     TIXML_SNPRINTF( buffer, bufferSize, L"%u", v );
  424. }
  425.  
  426.  
  427. void XMLUtil::ToStr( bool v, wchar_t* buffer, int bufferSize )
  428. {
  429.     TIXML_SNPRINTF( buffer, bufferSize, L"%d", v ? 1 : 0 );
  430. }
  431.  
  432.  
  433. void XMLUtil::ToStr( float v, wchar_t* buffer, int bufferSize )
  434. {
  435.     TIXML_SNPRINTF( buffer, bufferSize, L"%g", v );
  436. }
  437.  
  438.  
  439. void XMLUtil::ToStr( double v, wchar_t* buffer, int bufferSize )
  440. {
  441.     TIXML_SNPRINTF( buffer, bufferSize, L"%g", v );
  442. }
  443.  
  444. void XMLUtil::ToStr( __int64 v, wchar_t* buffer, int bufferSize )
  445. {
  446.     TIXML_SNPRINTF( buffer, bufferSize, L"%I64d", v );
  447. }
  448.  
  449. bool XMLUtil::ToInt( const wchar_t* str, int* value )
  450. {
  451.     if ( TIXML_SSCANF( str, L"%d", value ) == 1 ) {
  452.         return true;
  453.     }
  454.     return false;
  455. }
  456.  
  457. bool XMLUtil::ToUnsigned( const wchar_t* str, unsigned *value )
  458. {
  459.     if ( TIXML_SSCANF( str, L"%u", value ) == 1 ) {
  460.         return true;
  461.     }
  462.     return false;
  463. }
  464.  
  465. bool XMLUtil::ToBool( const wchar_t* str, bool* value )
  466. {
  467.     int ival = 0;
  468.     if ( ToInt( str, &ival )) {
  469.         *value = (ival==0) ? false : true;
  470.         return true;
  471.     }
  472.     if ( StringEqual( str, L"true" ) ) {
  473.         *value = true;
  474.         return true;
  475.     }
  476.     else if ( StringEqual( str, L"false" ) ) {
  477.         *value = false;
  478.         return true;
  479.     }
  480.     return false;
  481. }
  482.  
  483.  
  484. bool XMLUtil::ToFloat( const wchar_t* str, float* value )
  485. {
  486.     if ( TIXML_SSCANF( str, L"%f", value ) == 1 ) {
  487.         return true;
  488.     }
  489.     return false;
  490. }
  491.  
  492. bool XMLUtil::ToDouble( const wchar_t* str, double* value )
  493. {
  494.     if ( TIXML_SSCANF( str, L"%lf", value ) == 1 ) {
  495.         return true;
  496.     }
  497.     return false;
  498. }
  499.  
  500.  
  501. wchar_t* TiXMLDocument::Identify( wchar_t* p, XMLNode** node )
  502. {
  503.     XMLNode* returnNode = 0;
  504.     wchar_t* start = p;
  505.     p = XMLUtil::SkipWhiteSpace( p );
  506.     if( !p || !*p ) {
  507.         return p;
  508.     }
  509.  
  510.     // What is this thing?
  511.     // - Elements start with a letter or underscore, but xml is reserved.
  512.     // - Comments: <!--
  513.     // - Decleration: <?
  514.     // - Everthing else is unknown to tinyxml.
  515.     //
  516.  
  517.     static const wchar_t* xmlHeader     = { L"<?" };
  518.     static const wchar_t* commentHeader = { L"<!--" };
  519.     static const wchar_t* dtdHeader     = { L"<!" };
  520.     static const wchar_t* cdataHeader       = { L"<![CDATA[" };
  521.     static const wchar_t* elementHeader = { L"<" }; // and a header for everything else; check last.
  522.  
  523.     static const int xmlHeaderLen       = 2;
  524.     static const int commentHeaderLen   = 4;
  525.     static const int dtdHeaderLen       = 2;
  526.     static const int cdataHeaderLen     = 9;
  527.     static const int elementHeaderLen   = 1;
  528.  
  529. #if defined(_MSC_VER)
  530. #pragma warning ( push )
  531. #pragma warning ( disable : 4127 )
  532. #endif
  533.     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );        // use same memory pool
  534.     TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );    // use same memory pool
  535. #if defined(_MSC_VER)
  536. #pragma warning (pop)
  537. #endif
  538.     if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
  539.         returnNode = new (_commentPool.Alloc()) XMLDeclaration( this );
  540.         returnNode->_memPool = &_commentPool;
  541.         p += xmlHeaderLen;
  542.     }
  543.     else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
  544.         returnNode = new (_commentPool.Alloc()) XMLComment( this );
  545.         returnNode->_memPool = &_commentPool;
  546.         p += commentHeaderLen;
  547.     }
  548.     else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
  549.         XMLText* text = new (_textPool.Alloc()) XMLText( this );
  550.         returnNode = text;
  551.         returnNode->_memPool = &_textPool;
  552.         p += cdataHeaderLen;
  553.         text->SetCData( true );
  554.     }
  555.     else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
  556.         returnNode = new (_commentPool.Alloc()) XMLUnknown( this );
  557.         returnNode->_memPool = &_commentPool;
  558.         p += dtdHeaderLen;
  559.     }
  560.     else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
  561.         returnNode = new (_elementPool.Alloc()) XMLElement( this );
  562.         returnNode->_memPool = &_elementPool;
  563.         p += elementHeaderLen;
  564.     }
  565.     else {
  566.         returnNode = new (_textPool.Alloc()) XMLText( this );
  567.         returnNode->_memPool = &_textPool;
  568.         p = start;  // Back it up, all the text counts.
  569.     }
  570.  
  571.     *node = returnNode;
  572.     return p;
  573. }
  574.  
  575.  
  576. bool TiXMLDocument::Accept( XMLVisitor* visitor ) const
  577. {
  578.     if ( visitor->VisitEnter( *this ) ) {
  579.         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
  580.             if ( !node->Accept( visitor ) ) {
  581.                 break;
  582.             }
  583.         }
  584.     }
  585.     return visitor->VisitExit( *this );
  586. }
  587.  
  588.  
  589. // --------- XMLNode ----------- //
  590.  
  591. XMLNode::XMLNode( TiXMLDocument* doc ) :
  592.     _document( doc ),
  593.     _parent( 0 ),
  594.     _firstChild( 0 ), _lastChild( 0 ),
  595.     _prev( 0 ), _next( 0 )
  596. {
  597. }
  598.  
  599.  
  600. XMLNode::~XMLNode()
  601. {
  602.     DeleteChildren();
  603.     if ( _parent ) {
  604.         _parent->Unlink( this );
  605.     }
  606. }
  607.  
  608.  
  609. void XMLNode::SetValue( const wchar_t* str, bool staticMem )
  610. {
  611.     if ( staticMem ) {
  612.         _value.SetInternedStr( str );
  613.     }
  614.     else {
  615.         _value.SetStr( str );
  616.     }
  617. }
  618.  
  619.  
  620. void XMLNode::DeleteChildren()
  621. {
  622.     while( _firstChild ) {
  623.         XMLNode* node = _firstChild;
  624.         Unlink( node );
  625.  
  626.         DELETE_NODE( node );
  627.     }
  628.     _firstChild = _lastChild = 0;
  629. }
  630.  
  631.  
  632. void XMLNode::Unlink( XMLNode* child )
  633. {
  634.     TIXMLASSERT( child->_parent == this );
  635.     if ( child == _firstChild ) {
  636.         _firstChild = _firstChild->_next;
  637.     }
  638.     if ( child == _lastChild ) {
  639.         _lastChild = _lastChild->_prev;
  640.     }
  641.  
  642.     if ( child->_prev ) {
  643.         child->_prev->_next = child->_next;
  644.     }
  645.     if ( child->_next ) {
  646.         child->_next->_prev = child->_prev;
  647.     }
  648.     child->_parent = 0;
  649. }
  650.  
  651.  
  652. void XMLNode::DeleteChild( XMLNode* node )
  653. {
  654.     TIXMLASSERT( node->_parent == this );
  655.     DELETE_NODE( node );
  656. }
  657.  
  658.  
  659. XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
  660. {
  661.     if ( _lastChild ) {
  662.         TIXMLASSERT( _firstChild );
  663.         TIXMLASSERT( _lastChild->_next == 0 );
  664.         _lastChild->_next = addThis;
  665.         addThis->_prev = _lastChild;
  666.         _lastChild = addThis;
  667.  
  668.         addThis->_next = 0;
  669.     }
  670.     else {
  671.         TIXMLASSERT( _firstChild == 0 );
  672.         _firstChild = _lastChild = addThis;
  673.  
  674.         addThis->_prev = 0;
  675.         addThis->_next = 0;
  676.     }
  677.     addThis->_parent = this;
  678.     addThis->_memPool->SetTracked();
  679.     return addThis;
  680. }
  681.  
  682.  
  683. XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
  684. {
  685.     if ( _firstChild ) {
  686.         TIXMLASSERT( _lastChild );
  687.         TIXMLASSERT( _firstChild->_prev == 0 );
  688.  
  689.         _firstChild->_prev = addThis;
  690.         addThis->_next = _firstChild;
  691.         _firstChild = addThis;
  692.  
  693.         addThis->_prev = 0;
  694.     }
  695.     else {
  696.         TIXMLASSERT( _lastChild == 0 );
  697.         _firstChild = _lastChild = addThis;
  698.  
  699.         addThis->_prev = 0;
  700.         addThis->_next = 0;
  701.     }
  702.     addThis->_parent = this;
  703.     addThis->_memPool->SetTracked();
  704.     return addThis;
  705. }
  706.  
  707.  
  708. XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
  709. {
  710.     TIXMLASSERT( afterThis->_parent == this );
  711.     if ( afterThis->_parent != this ) {
  712.         return 0;
  713.     }
  714.  
  715.     if ( afterThis->_next == 0 ) {
  716.         // The last node or the only node.
  717.         return InsertEndChild( addThis );
  718.     }
  719.     addThis->_prev = afterThis;
  720.     addThis->_next = afterThis->_next;
  721.     afterThis->_next->_prev = addThis;
  722.     afterThis->_next = addThis;
  723.     addThis->_parent = this;
  724.     addThis->_memPool->SetTracked();
  725.     return addThis;
  726. }
  727.  
  728.  
  729.  
  730.  
  731. const XMLElement* XMLNode::FirstChildElement( const wchar_t* value ) const
  732. {
  733.     for( XMLNode* node=_firstChild; node; node=node->_next ) {
  734.         XMLElement* element = node->ToElement();
  735.         if ( element ) {
  736.             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
  737.                 return element;
  738.             }
  739.         }
  740.     }
  741.     return 0;
  742. }
  743.  
  744.  
  745. const XMLElement* XMLNode::LastChildElement( const wchar_t* value ) const
  746. {
  747.     for( XMLNode* node=_lastChild; node; node=node->_prev ) {
  748.         XMLElement* element = node->ToElement();
  749.         if ( element ) {
  750.             if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
  751.                 return element;
  752.             }
  753.         }
  754.     }
  755.     return 0;
  756. }
  757.  
  758.  
  759. const XMLElement* XMLNode::NextSiblingElement( const wchar_t* value ) const
  760. {
  761.     for( XMLNode* element=this->_next; element; element = element->_next ) {
  762.         if (    element->ToElement()
  763.                 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
  764.             return element->ToElement();
  765.         }
  766.     }
  767.     return 0;
  768. }
  769.  
  770.  
  771. const XMLElement* XMLNode::PreviousSiblingElement( const wchar_t* value ) const
  772. {
  773.     for( XMLNode* element=_prev; element; element = element->_prev ) {
  774.         if (    element->ToElement()
  775.                 && (!value || XMLUtil::StringEqual( value, element->Value() ))) {
  776.             return element->ToElement();
  777.         }
  778.     }
  779.     return 0;
  780. }
  781.  
  782.  
  783. wchar_t* XMLNode::ParseDeep( wchar_t* p, StrPair* parentEnd )
  784. {
  785.     // This is a recursive method, but thinking about it "at the current level"
  786.     // it is a pretty simple flat list:
  787.     //      <foo/>
  788.     //      <!-- comment -->
  789.     //
  790.     // With a special case:
  791.     //      <foo>
  792.     //      </foo>
  793.     //      <!-- comment -->
  794.     //
  795.     // Where the closing element (/foo) *must* be the next thing after the opening
  796.     // element, and the names must match. BUT the tricky bit is that the closing
  797.     // element will be read by the child.
  798.     //
  799.     // 'endTag' is the end tag for this node, it is returned by a call to a child.
  800.     // 'parentEnd' is the end tag for the parent, which is filled in and returned.
  801.  
  802.     while( p && *p ) {
  803.         XMLNode* node = 0;
  804.  
  805.         p = _document->Identify( p, &node );
  806.         if ( p == 0 || node == 0 ) {
  807.             break;
  808.         }
  809.  
  810.         StrPair endTag;
  811.         p = node->ParseDeep( p, &endTag );
  812.         if ( !p ) {
  813.             DELETE_NODE( node );
  814.             node = 0;
  815.             if ( !_document->Error() ) {
  816.                 _document->SetError( XML_ERROR_PARSING, 0, 0 );
  817.             }
  818.             break;
  819.         }
  820.  
  821.         // We read the end tag. Return it to the parent.
  822.         if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
  823.             if ( parentEnd ) {
  824.                 *parentEnd = static_cast<XMLElement*>(node)->_value;
  825.             }
  826.             node->_memPool->SetTracked();   // created and then immediately deleted.
  827.             DELETE_NODE( node );
  828.             return p;
  829.         }
  830.  
  831.         // Handle an end tag returned to this level.
  832.         // And handle a bunch of annoying errors.
  833.         XMLElement* ele = node->ToElement();
  834.         if ( ele ) {
  835.             if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
  836.                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
  837.                 p = 0;
  838.             }
  839.             else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
  840.                 _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
  841.                 p = 0;
  842.             }
  843.             else if ( !endTag.Empty() ) {
  844.                 if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) {
  845.                     _document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
  846.                     p = 0;
  847.                 }
  848.             }
  849.         }
  850.         if ( p == 0 ) {
  851.             DELETE_NODE( node );
  852.             node = 0;
  853.         }
  854.         if ( node ) {
  855.             this->InsertEndChild( node );
  856.         }
  857.     }
  858.     return 0;
  859. }
  860.  
  861. // --------- XMLText ---------- //
  862. wchar_t* XMLText::ParseDeep( wchar_t* p, StrPair* )
  863. {
  864.     const wchar_t* start = p;
  865.     if ( this->CData() ) {
  866.         p = _value.ParseText( p, L"]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
  867.         if ( !p ) {
  868.             _document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
  869.         }
  870.         return p;
  871.     }
  872.     else {
  873.         int flags = _document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES;
  874.         if ( _document->WhitespaceMode() == COLLAPSE_WHITESPACE ) {
  875.             flags |= StrPair::COLLAPSE_WHITESPACE;
  876.         }
  877.  
  878.         p = _value.ParseText( p, L"<", flags );
  879.         if ( !p ) {
  880.             _document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
  881.         }
  882.         if ( p && *p ) {
  883.             return p-1;
  884.         }
  885.     }
  886.     return 0;
  887. }
  888.  
  889.  
  890. XMLNode* XMLText::ShallowClone( TiXMLDocument* doc ) const
  891. {
  892.     if ( !doc ) {
  893.         doc = _document;
  894.     }
  895.     XMLText* text = doc->NewText( Value() );    // fixme: this will always allocate memory. Intern?
  896.     text->SetCData( this->CData() );
  897.     return text;
  898. }
  899.  
  900.  
  901. bool XMLText::ShallowEqual( const XMLNode* compare ) const
  902. {
  903.     return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
  904. }
  905.  
  906.  
  907. bool XMLText::Accept( XMLVisitor* visitor ) const
  908. {
  909.     return visitor->Visit( *this );
  910. }
  911.  
  912.  
  913. // --------- XMLComment ---------- //
  914.  
  915. XMLComment::XMLComment( TiXMLDocument* doc ) : XMLNode( doc )
  916. {
  917. }
  918.  
  919.  
  920. XMLComment::~XMLComment()
  921. {
  922. }
  923.  
  924.  
  925. wchar_t* XMLComment::ParseDeep( wchar_t* p, StrPair* )
  926. {
  927.     // Comment parses as text.
  928.     const wchar_t* start = p;
  929.     p = _value.ParseText( p, L"-->", StrPair::COMMENT );
  930.     if ( p == 0 ) {
  931.         _document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
  932.     }
  933.     return p;
  934. }
  935.  
  936.  
  937. XMLNode* XMLComment::ShallowClone( TiXMLDocument* doc ) const
  938. {
  939.     if ( !doc ) {
  940.         doc = _document;
  941.     }
  942.     XMLComment* comment = doc->NewComment( Value() );   // fixme: this will always allocate memory. Intern?
  943.     return comment;
  944. }
  945.  
  946.  
  947. bool XMLComment::ShallowEqual( const XMLNode* compare ) const
  948. {
  949.     return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
  950. }
  951.  
  952.  
  953. bool XMLComment::Accept( XMLVisitor* visitor ) const
  954. {
  955.     return visitor->Visit( *this );
  956. }
  957.  
  958.  
  959. // --------- XMLDeclaration ---------- //
  960.  
  961. XMLDeclaration::XMLDeclaration( TiXMLDocument* doc ) : XMLNode( doc )
  962. {
  963. }
  964.  
  965.  
  966. XMLDeclaration::~XMLDeclaration()
  967. {
  968.     //printf( "~XMLDeclaration\n" );
  969. }
  970.  
  971.  
  972. wchar_t* XMLDeclaration::ParseDeep( wchar_t* p, StrPair* )
  973. {
  974.     // Declaration parses as text.
  975.     const wchar_t* start = p;
  976.     p = _value.ParseText( p, L"?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
  977.     if ( p == 0 ) {
  978.         _document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
  979.     }
  980.     return p;
  981. }
  982.  
  983.  
  984. XMLNode* XMLDeclaration::ShallowClone( TiXMLDocument* doc ) const
  985. {
  986.     if ( !doc ) {
  987.         doc = _document;
  988.     }
  989.     XMLDeclaration* dec = doc->NewDeclaration( Value() );   // fixme: this will always allocate memory. Intern?
  990.     return dec;
  991. }
  992.  
  993.  
  994. bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
  995. {
  996.     return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
  997. }
  998.  
  999.  
  1000.  
  1001. bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
  1002. {
  1003.     return visitor->Visit( *this );
  1004. }
  1005.  
  1006. // --------- XMLUnknown ---------- //
  1007.  
  1008. XMLUnknown::XMLUnknown( TiXMLDocument* doc ) : XMLNode( doc )
  1009. {
  1010. }
  1011.  
  1012.  
  1013. XMLUnknown::~XMLUnknown()
  1014. {
  1015. }
  1016.  
  1017.  
  1018. wchar_t* XMLUnknown::ParseDeep( wchar_t* p, StrPair* )
  1019. {
  1020.     // Unknown parses as text.
  1021.     const wchar_t* start = p;
  1022.  
  1023.     p = _value.ParseText( p, L">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
  1024.     if ( !p ) {
  1025.         _document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
  1026.     }
  1027.     return p;
  1028. }
  1029.  
  1030.  
  1031. XMLNode* XMLUnknown::ShallowClone( TiXMLDocument* doc ) const
  1032. {
  1033.     if ( !doc ) {
  1034.         doc = _document;
  1035.     }
  1036.     XMLUnknown* text = doc->NewUnknown( Value() );  // fixme: this will always allocate memory. Intern?
  1037.     return text;
  1038. }
  1039.  
  1040.  
  1041. bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
  1042. {
  1043.     return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
  1044. }
  1045.  
  1046.  
  1047. bool XMLUnknown::Accept( XMLVisitor* visitor ) const
  1048. {
  1049.     return visitor->Visit( *this );
  1050. }
  1051.  
  1052. // --------- XMLAttribute ---------- //
  1053. wchar_t* XMLAttribute::ParseDeep( wchar_t* p, bool processEntities )
  1054. {
  1055.     // Parse using the name rules: bug fix, was using ParseText before
  1056.     p = _name.ParseName( p );
  1057.     if ( !p || !*p ) {
  1058.         return 0;
  1059.     }
  1060.  
  1061.     // Skip white space before =
  1062.     p = XMLUtil::SkipWhiteSpace( p );
  1063.     if ( !p || *p != '=' ) {
  1064.         return 0;
  1065.     }
  1066.  
  1067.     ++p;    // move up to opening quote
  1068.     p = XMLUtil::SkipWhiteSpace( p );
  1069.     if ( *p != '\"' && *p != '\'' ) {
  1070.         return 0;
  1071.     }
  1072.  
  1073.     wchar_t endTag[2] = { *p, 0 };
  1074.     ++p;    // move past opening quote
  1075.  
  1076.     p = _value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
  1077.     return p;
  1078. }
  1079.  
  1080.  
  1081. void XMLAttribute::SetName( const wchar_t* n )
  1082. {
  1083.     _name.SetStr( n );
  1084. }
  1085.  
  1086.  
  1087. XMLError XMLAttribute::QueryIntValue( int* value ) const
  1088. {
  1089.     if ( XMLUtil::ToInt( Value(), value )) {
  1090.         return XML_NO_ERROR;
  1091.     }
  1092.     return XML_WRONG_ATTRIBUTE_TYPE;
  1093. }
  1094.  
  1095.  
  1096. XMLError XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
  1097. {
  1098.     if ( XMLUtil::ToUnsigned( Value(), value )) {
  1099.         return XML_NO_ERROR;
  1100.     }
  1101.     return XML_WRONG_ATTRIBUTE_TYPE;
  1102. }
  1103.  
  1104.  
  1105. XMLError XMLAttribute::QueryBoolValue( bool* value ) const
  1106. {
  1107.     if ( XMLUtil::ToBool( Value(), value )) {
  1108.         return XML_NO_ERROR;
  1109.     }
  1110.     return XML_WRONG_ATTRIBUTE_TYPE;
  1111. }
  1112.  
  1113.  
  1114. XMLError XMLAttribute::QueryFloatValue( float* value ) const
  1115. {
  1116.     if ( XMLUtil::ToFloat( Value(), value )) {
  1117.         return XML_NO_ERROR;
  1118.     }
  1119.     return XML_WRONG_ATTRIBUTE_TYPE;
  1120. }
  1121.  
  1122.  
  1123. XMLError XMLAttribute::QueryDoubleValue( double* value ) const
  1124. {
  1125.     if ( XMLUtil::ToDouble( Value(), value )) {
  1126.         return XML_NO_ERROR;
  1127.     }
  1128.     return XML_WRONG_ATTRIBUTE_TYPE;
  1129. }
  1130.  
  1131.  
  1132. void XMLAttribute::SetAttribute( const wchar_t* v )
  1133. {
  1134.     _value.SetStr( v );
  1135. }
  1136.  
  1137.  
  1138. void XMLAttribute::SetAttribute( int v )
  1139. {
  1140.     wchar_t buf[BUF_SIZE];
  1141.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1142.     _value.SetStr( buf );
  1143. }
  1144.  
  1145.  
  1146. void XMLAttribute::SetAttribute( unsigned v )
  1147. {
  1148.     wchar_t buf[BUF_SIZE];
  1149.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1150.     _value.SetStr( buf );
  1151. }
  1152.  
  1153.  
  1154. void XMLAttribute::SetAttribute( bool v )
  1155. {
  1156.     wchar_t buf[BUF_SIZE];
  1157.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1158.     _value.SetStr( buf );
  1159. }
  1160.  
  1161. void XMLAttribute::SetAttribute( double v )
  1162. {
  1163.     wchar_t buf[BUF_SIZE];
  1164.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1165.     _value.SetStr( buf );
  1166. }
  1167.  
  1168. void XMLAttribute::SetAttribute( float v )
  1169. {
  1170.     wchar_t buf[BUF_SIZE];
  1171.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1172.     _value.SetStr( buf );
  1173. }
  1174.  
  1175. void XMLAttribute::SetAttribute( __int64 v )
  1176. {
  1177.     wchar_t buf[BUF_SIZE];
  1178.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1179.     _value.SetStr( buf );
  1180. }
  1181.  
  1182. // --------- XMLElement ---------- //
  1183. XMLElement::XMLElement( TiXMLDocument* doc ) : XMLNode( doc ),
  1184.     _closingType( 0 ),
  1185.     _rootAttribute( 0 )
  1186. {
  1187. }
  1188.  
  1189.  
  1190. XMLElement::~XMLElement()
  1191. {
  1192.     while( _rootAttribute ) {
  1193.         XMLAttribute* next = _rootAttribute->_next;
  1194.         DELETE_ATTRIBUTE( _rootAttribute );
  1195.         _rootAttribute = next;
  1196.     }
  1197. }
  1198.  
  1199.  
  1200. XMLAttribute* XMLElement::FindAttribute( const wchar_t* name )
  1201. {
  1202.     XMLAttribute* a = 0;
  1203.     for( a=_rootAttribute; a; a = a->_next ) {
  1204.         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
  1205.             return a;
  1206.         }
  1207.     }
  1208.     return 0;
  1209. }
  1210.  
  1211.  
  1212. const XMLAttribute* XMLElement::FindAttribute( const wchar_t* name ) const
  1213. {
  1214.     XMLAttribute* a = 0;
  1215.     for( a=_rootAttribute; a; a = a->_next ) {
  1216.         if ( XMLUtil::StringEqual( a->Name(), name ) ) {
  1217.             return a;
  1218.         }
  1219.     }
  1220.     return 0;
  1221. }
  1222.  
  1223.  
  1224. const wchar_t* XMLElement::Attribute( const wchar_t* name, const wchar_t* value ) const
  1225. {
  1226.     const XMLAttribute* a = FindAttribute( name );
  1227.     if ( !a ) {
  1228.         return 0;
  1229.     }
  1230.     if ( !value || XMLUtil::StringEqual( a->Value(), value )) {
  1231.         return a->Value();
  1232.     }
  1233.     return 0;
  1234. }
  1235.  
  1236.  
  1237. const wchar_t* XMLElement::GetText() const
  1238. {
  1239.     if ( FirstChild() && FirstChild()->ToText() ) {
  1240.         return FirstChild()->ToText()->Value();
  1241.     }
  1242.     return 0;
  1243. }
  1244.  
  1245.  
  1246. XMLError XMLElement::QueryIntText( int* ival ) const
  1247. {
  1248.     if ( FirstChild() && FirstChild()->ToText() ) {
  1249.         const wchar_t* t = FirstChild()->ToText()->Value();
  1250.         if ( XMLUtil::ToInt( t, ival ) ) {
  1251.             return XML_SUCCESS;
  1252.         }
  1253.         return XML_CAN_NOT_CONVERT_TEXT;
  1254.     }
  1255.     return XML_NO_TEXT_NODE;
  1256. }
  1257.  
  1258.  
  1259. XMLError XMLElement::QueryUnsignedText( unsigned* uval ) const
  1260. {
  1261.     if ( FirstChild() && FirstChild()->ToText() ) {
  1262.         const wchar_t* t = FirstChild()->ToText()->Value();
  1263.         if ( XMLUtil::ToUnsigned( t, uval ) ) {
  1264.             return XML_SUCCESS;
  1265.         }
  1266.         return XML_CAN_NOT_CONVERT_TEXT;
  1267.     }
  1268.     return XML_NO_TEXT_NODE;
  1269. }
  1270.  
  1271.  
  1272. XMLError XMLElement::QueryBoolText( bool* bval ) const
  1273. {
  1274.     if ( FirstChild() && FirstChild()->ToText() ) {
  1275.         const wchar_t* t = FirstChild()->ToText()->Value();
  1276.         if ( XMLUtil::ToBool( t, bval ) ) {
  1277.             return XML_SUCCESS;
  1278.         }
  1279.         return XML_CAN_NOT_CONVERT_TEXT;
  1280.     }
  1281.     return XML_NO_TEXT_NODE;
  1282. }
  1283.  
  1284.  
  1285. XMLError XMLElement::QueryDoubleText( double* dval ) const
  1286. {
  1287.     if ( FirstChild() && FirstChild()->ToText() ) {
  1288.         const wchar_t* t = FirstChild()->ToText()->Value();
  1289.         if ( XMLUtil::ToDouble( t, dval ) ) {
  1290.             return XML_SUCCESS;
  1291.         }
  1292.         return XML_CAN_NOT_CONVERT_TEXT;
  1293.     }
  1294.     return XML_NO_TEXT_NODE;
  1295. }
  1296.  
  1297.  
  1298. XMLError XMLElement::QueryFloatText( float* fval ) const
  1299. {
  1300.     if ( FirstChild() && FirstChild()->ToText() ) {
  1301.         const wchar_t* t = FirstChild()->ToText()->Value();
  1302.         if ( XMLUtil::ToFloat( t, fval ) ) {
  1303.             return XML_SUCCESS;
  1304.         }
  1305.         return XML_CAN_NOT_CONVERT_TEXT;
  1306.     }
  1307.     return XML_NO_TEXT_NODE;
  1308. }
  1309.  
  1310.  
  1311.  
  1312. XMLAttribute* XMLElement::FindOrCreateAttribute( const wchar_t* name )
  1313. {
  1314.     XMLAttribute* last = 0;
  1315.     XMLAttribute* attrib = 0;
  1316.     for( attrib = _rootAttribute;
  1317.             attrib;
  1318.             last = attrib, attrib = attrib->_next ) {
  1319.         if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
  1320.             break;
  1321.         }
  1322.     }
  1323.     if ( !attrib ) {
  1324.         attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
  1325.         attrib->_memPool = &_document->_attributePool;
  1326.         if ( last ) {
  1327.             last->_next = attrib;
  1328.         }
  1329.         else {
  1330.             _rootAttribute = attrib;
  1331.         }
  1332.         attrib->SetName( name );
  1333.         attrib->_memPool->SetTracked(); // always created and linked.
  1334.     }
  1335.     return attrib;
  1336. }
  1337.  
  1338.  
  1339. void XMLElement::DeleteAttribute( const wchar_t* name )
  1340. {
  1341.     XMLAttribute* prev = 0;
  1342.     for( XMLAttribute* a=_rootAttribute; a; a=a->_next ) {
  1343.         if ( XMLUtil::StringEqual( name, a->Name() ) ) {
  1344.             if ( prev ) {
  1345.                 prev->_next = a->_next;
  1346.             }
  1347.             else {
  1348.                 _rootAttribute = a->_next;
  1349.             }
  1350.             DELETE_ATTRIBUTE( a );
  1351.             break;
  1352.         }
  1353.         prev = a;
  1354.     }
  1355. }
  1356.  
  1357.  
  1358. wchar_t* XMLElement::ParseAttributes( wchar_t* p )
  1359. {
  1360.     const wchar_t* start = p;
  1361.     XMLAttribute* prevAttribute = 0;
  1362.  
  1363.     // Read the attributes.
  1364.     while( p ) {
  1365.         p = XMLUtil::SkipWhiteSpace( p );
  1366.         if ( !p || !(*p) ) {
  1367.             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
  1368.             return 0;
  1369.         }
  1370.  
  1371.         // attribute.
  1372.         if ( XMLUtil::IsAlpha( *p ) ) {
  1373.             XMLAttribute* attrib = new (_document->_attributePool.Alloc() ) XMLAttribute();
  1374.             attrib->_memPool = &_document->_attributePool;
  1375.             attrib->_memPool->SetTracked();
  1376.  
  1377.             p = attrib->ParseDeep( p, _document->ProcessEntities() );
  1378.             if ( !p || Attribute( attrib->Name() ) ) {
  1379.                 DELETE_ATTRIBUTE( attrib );
  1380.                 _document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
  1381.                 return 0;
  1382.             }
  1383.             // There is a minor bug here: if the attribute in the source xml
  1384.             // document is duplicated, it will not be detected and the
  1385.             // attribute will be doubly added. However, tracking the 'prevAttribute'
  1386.             // avoids re-scanning the attribute list. Preferring performance for
  1387.             // now, may reconsider in the future.
  1388.             if ( prevAttribute ) {
  1389.                 prevAttribute->_next = attrib;
  1390.             }
  1391.             else {
  1392.                 _rootAttribute = attrib;
  1393.             }
  1394.             prevAttribute = attrib;
  1395.         }
  1396.         // end of the tag
  1397.         else if ( *p == '/' && *(p+1) == '>' ) {
  1398.             _closingType = CLOSED;
  1399.             return p+2; // done; sealed element.
  1400.         }
  1401.         // end of the tag
  1402.         else if ( *p == '>' ) {
  1403.             ++p;
  1404.             break;
  1405.         }
  1406.         else {
  1407.             _document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
  1408.             return 0;
  1409.         }
  1410.     }
  1411.     return p;
  1412. }
  1413.  
  1414.  
  1415. //
  1416. //  <ele></ele>
  1417. //  <ele>foo<b>bar</b></ele>
  1418. //
  1419. wchar_t* XMLElement::ParseDeep( wchar_t* p, StrPair* strPair )
  1420. {
  1421.     // Read the element name.
  1422.     p = XMLUtil::SkipWhiteSpace( p );
  1423.     if ( !p ) {
  1424.         return 0;
  1425.     }
  1426.  
  1427.     // The closing element is the </element> form. It is
  1428.     // parsed just like a regular element then deleted from
  1429.     // the DOM.
  1430.     if ( *p == '/' ) {
  1431.         _closingType = CLOSING;
  1432.         ++p;
  1433.     }
  1434.  
  1435.     p = _value.ParseName( p );
  1436.     if ( _value.Empty() ) {
  1437.         return 0;
  1438.     }
  1439.  
  1440.     p = ParseAttributes( p );
  1441.     if ( !p || !*p || _closingType ) {
  1442.         return p;
  1443.     }
  1444.  
  1445.     p = XMLNode::ParseDeep( p, strPair );
  1446.     return p;
  1447. }
  1448.  
  1449.  
  1450.  
  1451. XMLNode* XMLElement::ShallowClone( TiXMLDocument* doc ) const
  1452. {
  1453.     if ( !doc ) {
  1454.         doc = _document;
  1455.     }
  1456.     XMLElement* element = doc->NewElement( Value() );                   // fixme: this will always allocate memory. Intern?
  1457.     for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
  1458.         element->SetAttribute( a->Name(), a->Value() );                 // fixme: this will always allocate memory. Intern?
  1459.     }
  1460.     return element;
  1461. }
  1462.  
  1463.  
  1464. bool XMLElement::ShallowEqual( const XMLNode* compare ) const
  1465. {
  1466.     const XMLElement* other = compare->ToElement();
  1467.     if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
  1468.  
  1469.         const XMLAttribute* a=FirstAttribute();
  1470.         const XMLAttribute* b=other->FirstAttribute();
  1471.  
  1472.         while ( a && b ) {
  1473.             if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
  1474.                 return false;
  1475.             }
  1476.             a = a->Next();
  1477.             b = b->Next();
  1478.         }
  1479.         if ( a || b ) {
  1480.             // different count
  1481.             return false;
  1482.         }
  1483.         return true;
  1484.     }
  1485.     return false;
  1486. }
  1487.  
  1488.  
  1489. bool XMLElement::Accept( XMLVisitor* visitor ) const
  1490. {
  1491.     if ( visitor->VisitEnter( *this, _rootAttribute ) ) {
  1492.         for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() ) {
  1493.             if ( !node->Accept( visitor ) ) {
  1494.                 break;
  1495.             }
  1496.         }
  1497.     }
  1498.     return visitor->VisitExit( *this );
  1499. }
  1500.  
  1501.  
  1502. // --------- TiXMLDocument ----------- //
  1503. TiXMLDocument::TiXMLDocument( bool processEntities, Whitespace whitespace ) :
  1504.     XMLNode( 0 ),
  1505.     _writeBOM( false ),
  1506.     _processEntities( processEntities ),
  1507.     _errorID( XML_NO_ERROR ),
  1508.     _whitespace( whitespace ),
  1509.     _errorStr1( 0 ),
  1510.     _errorStr2( 0 ),
  1511.     _charBuffer( 0 )
  1512. {
  1513.     _document = this;   // avoid warning about 'this' in initializer list
  1514. }
  1515.  
  1516.  
  1517. TiXMLDocument::~TiXMLDocument()
  1518. {
  1519.     DeleteChildren();
  1520.     delete [] _charBuffer;
  1521.  
  1522. #if 0
  1523.     textPool.Trace( "text" );
  1524.     elementPool.Trace( "element" );
  1525.     commentPool.Trace( "comment" );
  1526.     attributePool.Trace( "attribute" );
  1527. #endif
  1528.  
  1529. #ifdef DEBUG
  1530.     if ( Error() == false ) {
  1531.         TIXMLASSERT( _elementPool.CurrentAllocs()   == _elementPool.Untracked() );
  1532.         TIXMLASSERT( _attributePool.CurrentAllocs() == _attributePool.Untracked() );
  1533.         TIXMLASSERT( _textPool.CurrentAllocs()      == _textPool.Untracked() );
  1534.         TIXMLASSERT( _commentPool.CurrentAllocs()   == _commentPool.Untracked() );
  1535.     }
  1536. #endif
  1537. }
  1538.  
  1539.  
  1540. void TiXMLDocument::InitDocument()
  1541. {
  1542.     _errorID = XML_NO_ERROR;
  1543.     _errorStr1 = 0;
  1544.     _errorStr2 = 0;
  1545.  
  1546.     delete [] _charBuffer;
  1547.     _charBuffer = 0;
  1548. }
  1549.  
  1550.  
  1551. XMLElement* TiXMLDocument::NewElement( const wchar_t* name )
  1552. {
  1553.     XMLElement* ele = new (_elementPool.Alloc()) XMLElement( this );
  1554.     ele->_memPool = &_elementPool;
  1555.     ele->SetName( name );
  1556.     return ele;
  1557. }
  1558.  
  1559.  
  1560. XMLComment* TiXMLDocument::NewComment( const wchar_t* str )
  1561. {
  1562.     XMLComment* comment = new (_commentPool.Alloc()) XMLComment( this );
  1563.     comment->_memPool = &_commentPool;
  1564.     comment->SetValue( str );
  1565.     return comment;
  1566. }
  1567.  
  1568.  
  1569. XMLText* TiXMLDocument::NewText( const wchar_t* str )
  1570. {
  1571.     XMLText* text = new (_textPool.Alloc()) XMLText( this );
  1572.     text->_memPool = &_textPool;
  1573.     text->SetValue( str );
  1574.     return text;
  1575. }
  1576.  
  1577.  
  1578. XMLDeclaration* TiXMLDocument::NewDeclaration( const wchar_t* str )
  1579. {
  1580.     XMLDeclaration* dec = new (_commentPool.Alloc()) XMLDeclaration( this );
  1581.     dec->_memPool = &_commentPool;
  1582.     dec->SetValue( str ? str : L"xml version=\"1.0\" encoding=\"UTF-8\"" );
  1583.     return dec;
  1584. }
  1585.  
  1586.  
  1587. XMLUnknown* TiXMLDocument::NewUnknown( const wchar_t* str )
  1588. {
  1589.     XMLUnknown* unk = new (_commentPool.Alloc()) XMLUnknown( this );
  1590.     unk->_memPool = &_commentPool;
  1591.     unk->SetValue( str );
  1592.     return unk;
  1593. }
  1594.  
  1595.  
  1596. XMLError TiXMLDocument::LoadFile( const wchar_t* filename )
  1597. {
  1598.     DeleteChildren();
  1599.     InitDocument();
  1600.     FILE* fp = 0;
  1601.  
  1602. #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
  1603.     errno_t err = _wfopen_s(&fp, filename, L"rb" );
  1604.     if ( !fp || err) {
  1605. #else
  1606.     fp = fopen( filename, "rb" );
  1607.     if ( !fp) {
  1608. #endif
  1609.         SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
  1610.         return _errorID;
  1611.     }
  1612.     LoadFile( fp );
  1613.     fclose( fp );
  1614.     return _errorID;
  1615. }
  1616.  
  1617.  
  1618. XMLError TiXMLDocument::LoadFile( FILE* fp )
  1619. {
  1620.     DeleteChildren();
  1621.     InitDocument();
  1622.  
  1623.     fseek( fp, 0, SEEK_END );
  1624.     size_t size = ftell( fp ) / sizeof(wchar_t); //because we need size in UNICODE chars not bytes
  1625.     fseek( fp, 0, SEEK_SET );
  1626.  
  1627.     if ( size == 0 ) {
  1628.         return _errorID;
  1629.     }
  1630.  
  1631.     _charBuffer = new wchar_t[size+1];
  1632.     size_t read = fread( _charBuffer, sizeof(wchar_t), size, fp );
  1633.     if ( read != size ) {
  1634.         SetError( XML_ERROR_FILE_READ_ERROR, 0, 0 );
  1635.         return _errorID;
  1636.     }
  1637.  
  1638.     _charBuffer[size] = 0;
  1639.  
  1640.     const wchar_t* p = _charBuffer;
  1641.     p = XMLUtil::SkipWhiteSpace( p );
  1642.     p = XMLUtil::ReadBOM( p, &_writeBOM );
  1643.     if ( !p || !*p ) {
  1644.         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  1645.         return _errorID;
  1646.     }
  1647.  
  1648.     ParseDeep( _charBuffer + (p-_charBuffer), 0 );
  1649.     return _errorID;
  1650. }
  1651.  
  1652.  
  1653. XMLError TiXMLDocument::SaveFile( const wchar_t* filename, bool compact )
  1654. {
  1655.     FILE* fp = 0;
  1656. #if defined(_MSC_VER) && (_MSC_VER >= 1400 )
  1657.     errno_t err = _wfopen_s(&fp, filename, L"wt,css=UNICODE" );
  1658.     if ( !fp || err) {
  1659. #else
  1660.     fp = fopen( filename, "w" );
  1661.     if ( !fp) {
  1662. #endif
  1663.         SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
  1664.         return _errorID;
  1665.     }
  1666.     SaveFile(fp, compact);
  1667.     fclose( fp );
  1668.     return _errorID;
  1669. }
  1670.  
  1671.  
  1672. XMLError TiXMLDocument::SaveFile( FILE* fp, bool compact )
  1673. {
  1674.     XMLPrinter stream( fp, compact );
  1675.     Print( &stream );
  1676.     return _errorID;
  1677. }
  1678.  
  1679.  
  1680. XMLError TiXMLDocument::Parse( const wchar_t *p, size_t len )
  1681. {
  1682.     DeleteChildren();
  1683.     InitDocument();
  1684.  
  1685.     if ( !p || !*p ) {
  1686.         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  1687.         return _errorID;
  1688.     }
  1689.     if ( len == (size_t)(-1) ) {
  1690.         len = wcslen( p );
  1691.     }
  1692.     _charBuffer = new wchar_t[ len+1 ];
  1693.     wmemcpy(_charBuffer, p, len);
  1694.     _charBuffer[len] = 0;
  1695.  
  1696.     p = XMLUtil::SkipWhiteSpace( p );
  1697.     p = XMLUtil::ReadBOM( p, &_writeBOM );
  1698.     if ( !p || !*p ) {
  1699.         SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  1700.         return _errorID;
  1701.     }
  1702.  
  1703.     ParseDeep( _charBuffer, 0 );
  1704.     return _errorID;
  1705. }
  1706.  
  1707.  
  1708. void TiXMLDocument::Print( XMLPrinter* streamer )
  1709. {
  1710.     XMLPrinter stdStreamer( stdout );
  1711.     if ( !streamer ) {
  1712.         streamer = &stdStreamer;
  1713.     }
  1714.     Accept( streamer );
  1715. }
  1716.  
  1717.  
  1718. void TiXMLDocument::SetError( XMLError error, const wchar_t* str1, const wchar_t* str2 )
  1719. {
  1720.     _errorID = error;
  1721.     _errorStr1 = str1;
  1722.     _errorStr2 = str2;
  1723. }
  1724.  
  1725.  
  1726. void TiXMLDocument::PrintError() const
  1727. {
  1728.     if ( _errorID ) {
  1729.         static const int LEN = 20;
  1730.         wchar_t buf1[LEN] = { 0 };
  1731.         wchar_t buf2[LEN] = { 0 };
  1732.  
  1733.         if ( _errorStr1 ) {
  1734.             TIXML_SNPRINTF( buf1, LEN, L"%s", _errorStr1 );
  1735.         }
  1736.         if ( _errorStr2 ) {
  1737.             TIXML_SNPRINTF( buf2, LEN, L"%s", _errorStr2 );
  1738.         }
  1739.  
  1740.         wprintf( L"TiXMLDocument error id=%d str1=%s str2=%s\n",
  1741.                 _errorID, buf1, buf2 );
  1742.     }
  1743. }
  1744.  
  1745.  
  1746. XMLPrinter::XMLPrinter( FILE* file, bool compact ) :
  1747.     _elementJustOpened( false ),
  1748.     _firstElement( true ),
  1749.     _fp( file ),
  1750.     _depth( 0 ),
  1751.     _textDepth( -1 ),
  1752.     _processEntities( true ),
  1753.     _compactMode( compact )
  1754. {
  1755.     for( int i=0; i<ENTITY_RANGE; ++i ) {
  1756.         _entityFlag[i] = false;
  1757.         _restrictedEntityFlag[i] = false;
  1758.     }
  1759.     for( int i=0; i<NUM_ENTITIES; ++i ) {
  1760.         TIXMLASSERT( entities[i].value < ENTITY_RANGE );
  1761.         if ( entities[i].value < ENTITY_RANGE ) {
  1762.             _entityFlag[ (int)entities[i].value ] = true;
  1763.         }
  1764.     }
  1765.     _restrictedEntityFlag[(int)'&'] = true;
  1766.     _restrictedEntityFlag[(int)'<'] = true;
  1767.     _restrictedEntityFlag[(int)'>'] = true; // not required, but consistency is nice
  1768.     _buffer.Push( 0 );
  1769. }
  1770.  
  1771.  
  1772. void XMLPrinter::Print( const wchar_t* format, ... )
  1773. {
  1774.     va_list     va;
  1775.     va_start( va, format );
  1776.  
  1777.     if ( _fp ) {
  1778.         vfwprintf( _fp, format, va );
  1779.     }
  1780.     else {
  1781.         // This seems brutally complex. Haven't figured out a better
  1782.         // way on windows.
  1783. #ifdef _MSC_VER
  1784.         int len = -1;
  1785.         int expand = 1000;
  1786.         while ( len < 0 ) {
  1787.             len = _vsnwprintf_s( _accumulator.Mem(), _accumulator.Capacity(), _TRUNCATE, format, va );
  1788.             if ( len < 0 ) {
  1789.                 expand *= 3/2;
  1790.                 _accumulator.PushArr( expand );
  1791.             }
  1792.         }
  1793.         wchar_t* p = _buffer.PushArr( len ) - 1;
  1794.         wmemcpy( p, _accumulator.Mem(), len+1 );
  1795. #else
  1796.         int len = vsnprintf( 0, 0, format, va );
  1797.         // Close out and re-start the va-args
  1798.         va_end( va );
  1799.         va_start( va, format );
  1800.         char* p = _buffer.PushArr( len ) - 1;
  1801.         vsnprintf( p, len+1, format, va );
  1802. #endif
  1803.     }
  1804.     va_end( va );
  1805. }
  1806.  
  1807.  
  1808. void XMLPrinter::PrintSpace( int depth )
  1809. {
  1810.     for( int i=0; i<depth; ++i ) {
  1811.         Print( L"    " );
  1812.     }
  1813. }
  1814.  
  1815.  
  1816. void XMLPrinter::PrintString( const wchar_t* p, bool restricted )
  1817. {
  1818.     // Look for runs of bytes between entities to print.
  1819.     const wchar_t* q = p;
  1820.     const bool* flag = restricted ? _restrictedEntityFlag : _entityFlag;
  1821.  
  1822.     if ( _processEntities ) {
  1823.         while ( *q ) {
  1824.             // Remember, char is sometimes signed. (How many times has that bitten me?)
  1825.             if ( *q > 0 && *q < ENTITY_RANGE ) {
  1826.                 // Check for entities. If one is found, flush
  1827.                 // the stream up until the entity, write the
  1828.                 // entity, and keep looking.
  1829.                 if ( flag[(unsigned)(*q)] ) {
  1830.                     while ( p < q ) {
  1831.                         Print( L"%c", *p );
  1832.                         ++p;
  1833.                     }
  1834.                     for( int i=0; i<NUM_ENTITIES; ++i ) {
  1835.                         if ( entities[i].value == *q ) {
  1836.                             Print( L"&%s;", entities[i].pattern );
  1837.                             break;
  1838.                         }
  1839.                     }
  1840.                     ++p;
  1841.                 }
  1842.             }
  1843.             ++q;
  1844.         }
  1845.     }
  1846.     // Flush the remaining string. This will be the entire
  1847.     // string if an entity wasn't found.
  1848.     if ( !_processEntities || (q-p > 0) ) {
  1849.         Print( L"%s", p );
  1850.     }
  1851. }
  1852.  
  1853.  
  1854. void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
  1855. {
  1856.     static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
  1857.     if ( writeBOM ) {
  1858.         Print( L"%s", bom );
  1859.     }
  1860.     if ( writeDec ) {
  1861.         PushDeclaration( L"xml version=\"1.0\"" );
  1862.     }
  1863. }
  1864.  
  1865.  
  1866. void XMLPrinter::OpenElement( const wchar_t* name )
  1867. {
  1868.     if ( _elementJustOpened ) {
  1869.         SealElement();
  1870.     }
  1871.     _stack.Push( name );
  1872.  
  1873.     if ( _textDepth < 0 && !_firstElement && !_compactMode ) {
  1874.         Print( L"\n" );
  1875.         PrintSpace( _depth );
  1876.     }
  1877.  
  1878.     Print( L"<%s", name );
  1879.     _elementJustOpened = true;
  1880.     _firstElement = false;
  1881.     ++_depth;
  1882. }
  1883.  
  1884.  
  1885. void XMLPrinter::PushAttribute( const wchar_t* name, const wchar_t* value )
  1886. {
  1887.     TIXMLASSERT( _elementJustOpened );
  1888.     Print( L" %s=\"", name );
  1889.     PrintString( value, false );
  1890.     Print( L"\"" );
  1891. }
  1892.  
  1893.  
  1894. void XMLPrinter::PushAttribute( const wchar_t* name, int v )
  1895. {
  1896.     wchar_t buf[BUF_SIZE];
  1897.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1898.     PushAttribute( name, buf );
  1899. }
  1900.  
  1901.  
  1902. void XMLPrinter::PushAttribute( const wchar_t* name, unsigned v )
  1903. {
  1904.     wchar_t buf[BUF_SIZE];
  1905.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1906.     PushAttribute( name, buf );
  1907. }
  1908.  
  1909.  
  1910. void XMLPrinter::PushAttribute( const wchar_t* name, bool v )
  1911. {
  1912.     wchar_t buf[BUF_SIZE];
  1913.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1914.     PushAttribute( name, buf );
  1915. }
  1916.  
  1917.  
  1918. void XMLPrinter::PushAttribute( const wchar_t* name, double v )
  1919. {
  1920.     wchar_t buf[BUF_SIZE];
  1921.     XMLUtil::ToStr( v, buf, BUF_SIZE );
  1922.     PushAttribute( name, buf );
  1923. }
  1924.  
  1925.  
  1926. void XMLPrinter::CloseElement()
  1927. {
  1928.     --_depth;
  1929.     const wchar_t* name = _stack.Pop();
  1930.  
  1931.     if ( _elementJustOpened ) {
  1932.         Print( L"/>" );
  1933.     }
  1934.     else {
  1935.         if ( _textDepth < 0 && !_compactMode) {
  1936.             Print( L"\n" );
  1937.             PrintSpace( _depth );
  1938.         }
  1939.         Print( L"</%s>", name );
  1940.     }
  1941.  
  1942.     if ( _textDepth == _depth ) {
  1943.         _textDepth = -1;
  1944.     }
  1945.     if ( _depth == 0 && !_compactMode) {
  1946.         Print( L"\n" );
  1947.     }
  1948.     _elementJustOpened = false;
  1949. }
  1950.  
  1951.  
  1952. void XMLPrinter::SealElement()
  1953. {
  1954.     _elementJustOpened = false;
  1955.     Print( L">" );
  1956. }
  1957.  
  1958.  
  1959. void XMLPrinter::PushText( const wchar_t* text, bool cdata )
  1960. {
  1961.     _textDepth = _depth-1;
  1962.  
  1963.     if ( _elementJustOpened ) {
  1964.         SealElement();
  1965.     }
  1966.     if ( cdata ) {
  1967.         Print( L"<![CDATA[" );
  1968.         Print( L"%s", text );
  1969.         Print( L"]]>" );
  1970.     }
  1971.     else {
  1972.         PrintString( text, true );
  1973.     }
  1974. }
  1975.  
  1976. void XMLPrinter::PushText( int value )
  1977. {
  1978.     wchar_t buf[BUF_SIZE];
  1979.     XMLUtil::ToStr( value, buf, BUF_SIZE );
  1980.     PushText( buf, false );
  1981. }
  1982.  
  1983.  
  1984. void XMLPrinter::PushText( unsigned value )
  1985. {
  1986.     wchar_t buf[BUF_SIZE];
  1987.     XMLUtil::ToStr( value, buf, BUF_SIZE );
  1988.     PushText( buf, false );
  1989. }
  1990.  
  1991.  
  1992. void XMLPrinter::PushText( bool value )
  1993. {
  1994.     wchar_t buf[BUF_SIZE];
  1995.     XMLUtil::ToStr( value, buf, BUF_SIZE );
  1996.     PushText( buf, false );
  1997. }
  1998.  
  1999.  
  2000. void XMLPrinter::PushText( float value )
  2001. {
  2002.     wchar_t buf[BUF_SIZE];
  2003.     XMLUtil::ToStr( value, buf, BUF_SIZE );
  2004.     PushText( buf, false );
  2005. }
  2006.  
  2007.  
  2008. void XMLPrinter::PushText( double value )
  2009. {
  2010.     wchar_t buf[BUF_SIZE];
  2011.     XMLUtil::ToStr( value, buf, BUF_SIZE );
  2012.     PushText( buf, false );
  2013. }
  2014.  
  2015.  
  2016. void XMLPrinter::PushComment( const wchar_t* comment )
  2017. {
  2018.     if ( _elementJustOpened ) {
  2019.         SealElement();
  2020.     }
  2021.     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
  2022.         Print( L"\n" );
  2023.         PrintSpace( _depth );
  2024.     }
  2025.     _firstElement = false;
  2026.     Print( L"<!--%s-->", comment );
  2027. }
  2028.  
  2029.  
  2030. void XMLPrinter::PushDeclaration( const wchar_t* value )
  2031. {
  2032.     if ( _elementJustOpened ) {
  2033.         SealElement();
  2034.     }
  2035.     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
  2036.         Print( L"\n" );
  2037.         PrintSpace( _depth );
  2038.     }
  2039.     _firstElement = false;
  2040.     Print( L"<?%s?>", value );
  2041. }
  2042.  
  2043.  
  2044. void XMLPrinter::PushUnknown( const wchar_t* value )
  2045. {
  2046.     if ( _elementJustOpened ) {
  2047.         SealElement();
  2048.     }
  2049.     if ( _textDepth < 0 && !_firstElement && !_compactMode) {
  2050.         Print( L"\n" );
  2051.         PrintSpace( _depth );
  2052.     }
  2053.     _firstElement = false;
  2054.     Print( L"<!%s>", value );
  2055. }
  2056.  
  2057.  
  2058. bool XMLPrinter::VisitEnter( const TiXMLDocument& doc )
  2059. {
  2060.     _processEntities = doc.ProcessEntities();
  2061.     if ( doc.HasBOM() ) {
  2062.         PushHeader( true, false );
  2063.     }
  2064.     return true;
  2065. }
  2066.  
  2067.  
  2068. bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
  2069. {
  2070.     OpenElement( element.Name() );
  2071.     while ( attribute ) {
  2072.         PushAttribute( attribute->Name(), attribute->Value() );
  2073.         attribute = attribute->Next();
  2074.     }
  2075.     return true;
  2076. }
  2077.  
  2078.  
  2079. bool XMLPrinter::VisitExit( const XMLElement& )
  2080. {
  2081.     CloseElement();
  2082.     return true;
  2083. }
  2084.  
  2085.  
  2086. bool XMLPrinter::Visit( const XMLText& text )
  2087. {
  2088.     PushText( text.Value(), text.CData() );
  2089.     return true;
  2090. }
  2091.  
  2092.  
  2093. bool XMLPrinter::Visit( const XMLComment& comment )
  2094. {
  2095.     PushComment( comment.Value() );
  2096.     return true;
  2097. }
  2098.  
  2099. bool XMLPrinter::Visit( const XMLDeclaration& declaration )
  2100. {
  2101.     PushDeclaration( declaration.Value() );
  2102.     return true;
  2103. }
  2104.  
  2105.  
  2106. bool XMLPrinter::Visit( const XMLUnknown& unknown )
  2107. {
  2108.     PushUnknown( unknown.Value() );
  2109.     return true;
  2110. }
  2111.  
  2112. }   // namespace tinyxml2
Advertisement
Add Comment
Please, Sign In to add comment