stratgame

diff level/src/tinyxml2.cc @ 0:86b53f76899f

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Mon, 21 May 2012 19:07:40 +0300
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/level/src/tinyxml2.cc	Mon May 21 19:07:40 2012 +0300
     1.3 @@ -0,0 +1,1826 @@
     1.4 +/*
     1.5 +Original code by Lee Thomason (www.grinninglizard.com)
     1.6 +
     1.7 +This software is provided 'as-is', without any express or implied
     1.8 +warranty. In no event will the authors be held liable for any
     1.9 +damages arising from the use of this software.
    1.10 +
    1.11 +Permission is granted to anyone to use this software for any
    1.12 +purpose, including commercial applications, and to alter it and
    1.13 +redistribute it freely, subject to the following restrictions:
    1.14 +
    1.15 +1. The origin of this software must not be misrepresented; you must
    1.16 +not claim that you wrote the original software. If you use this
    1.17 +software in a product, an acknowledgment in the product documentation
    1.18 +would be appreciated but is not required.
    1.19 +
    1.20 +2. Altered source versions must be plainly marked as such, and
    1.21 +must not be misrepresented as being the original software.
    1.22 +
    1.23 +3. This notice may not be removed or altered from any source
    1.24 +distribution.
    1.25 +*/
    1.26 +
    1.27 +#include "tinyxml2.h"
    1.28 +
    1.29 +#include <cstdio>
    1.30 +#include <cstdlib>
    1.31 +#include <new>
    1.32 +#include <cstddef>
    1.33 +
    1.34 +using namespace tinyxml2;
    1.35 +
    1.36 +static const char LINE_FEED				= (char)0x0a;			// all line endings are normalized to LF
    1.37 +static const char LF = LINE_FEED;
    1.38 +static const char CARRIAGE_RETURN		= (char)0x0d;			// CR gets filtered out
    1.39 +static const char CR = CARRIAGE_RETURN;
    1.40 +static const char SINGLE_QUOTE			= '\'';
    1.41 +static const char DOUBLE_QUOTE			= '\"';
    1.42 +
    1.43 +// Bunch of unicode info at:
    1.44 +//		http://www.unicode.org/faq/utf_bom.html
    1.45 +//	ef bb bf (Microsoft "lead bytes") - designates UTF-8
    1.46 +
    1.47 +static const unsigned char TIXML_UTF_LEAD_0 = 0xefU;
    1.48 +static const unsigned char TIXML_UTF_LEAD_1 = 0xbbU;
    1.49 +static const unsigned char TIXML_UTF_LEAD_2 = 0xbfU;
    1.50 +
    1.51 +
    1.52 +#define DELETE_NODE( node )	{			\
    1.53 +	if ( node ) {						\
    1.54 +		MemPool* pool = node->memPool;	\
    1.55 +		node->~XMLNode();				\
    1.56 +		pool->Free( node );				\
    1.57 +	}									\
    1.58 +}
    1.59 +#define DELETE_ATTRIBUTE( attrib ) {		\
    1.60 +	if ( attrib ) {							\
    1.61 +		MemPool* pool = attrib->memPool;	\
    1.62 +		attrib->~XMLAttribute();			\
    1.63 +		pool->Free( attrib );				\
    1.64 +	}										\
    1.65 +}
    1.66 +
    1.67 +struct Entity {
    1.68 +	const char* pattern;
    1.69 +	int length;
    1.70 +	char value;
    1.71 +};
    1.72 +
    1.73 +static const int NUM_ENTITIES = 5;
    1.74 +static const Entity entities[NUM_ENTITIES] = 
    1.75 +{
    1.76 +	{ "quot", 4,	DOUBLE_QUOTE },
    1.77 +	{ "amp", 3,		'&'  },
    1.78 +	{ "apos", 4,	SINGLE_QUOTE },
    1.79 +	{ "lt",	2, 		'<'	 },
    1.80 +	{ "gt",	2,		'>'	 }
    1.81 +};
    1.82 +
    1.83 +
    1.84 +StrPair::~StrPair()
    1.85 +{
    1.86 +	Reset();
    1.87 +}
    1.88 +
    1.89 +
    1.90 +void StrPair::Reset()
    1.91 +{
    1.92 +	if ( flags & NEEDS_DELETE ) {
    1.93 +		delete [] start;
    1.94 +	}
    1.95 +	flags = 0;
    1.96 +	start = 0;
    1.97 +	end = 0;
    1.98 +}
    1.99 +
   1.100 +
   1.101 +void StrPair::SetStr( const char* str, int flags )
   1.102 +{
   1.103 +	Reset();
   1.104 +	size_t len = strlen( str );
   1.105 +	start = new char[ len+1 ];
   1.106 +	memcpy( start, str, len+1 );
   1.107 +	end = start + len;
   1.108 +	this->flags = flags | NEEDS_DELETE;
   1.109 +}
   1.110 +
   1.111 +
   1.112 +char* StrPair::ParseText( char* p, const char* endTag, int strFlags )
   1.113 +{
   1.114 +	TIXMLASSERT( endTag && *endTag );
   1.115 +
   1.116 +	char* start = p;	// fixme: hides a member
   1.117 +	char  endChar = *endTag;
   1.118 +	size_t length = strlen( endTag );
   1.119 +
   1.120 +	// Inner loop of text parsing.
   1.121 +	while ( *p ) {
   1.122 +		if ( *p == endChar && strncmp( p, endTag, length ) == 0 ) {
   1.123 +			Set( start, p, strFlags );
   1.124 +			return p + length;
   1.125 +		}
   1.126 +		++p;
   1.127 +	}	
   1.128 +	return 0;
   1.129 +}
   1.130 +
   1.131 +
   1.132 +char* StrPair::ParseName( char* p )
   1.133 +{
   1.134 +	char* start = p;
   1.135 +
   1.136 +	if ( !start || !(*start) ) {
   1.137 +		return 0;
   1.138 +	}
   1.139 +
   1.140 +	if ( !XMLUtil::IsAlpha( *p ) ) {
   1.141 +		return 0;
   1.142 +	}
   1.143 +
   1.144 +	while( *p && (
   1.145 +			   XMLUtil::IsAlphaNum( (unsigned char) *p ) 
   1.146 +			|| *p == '_'
   1.147 +			|| *p == '-'
   1.148 +			|| *p == '.'
   1.149 +			|| *p == ':' ))
   1.150 +	{
   1.151 +		++p;
   1.152 +	}
   1.153 +
   1.154 +	if ( p > start ) {
   1.155 +		Set( start, p, 0 );
   1.156 +		return p;
   1.157 +	}
   1.158 +	return 0;
   1.159 +}
   1.160 +
   1.161 +
   1.162 +
   1.163 +const char* StrPair::GetStr()
   1.164 +{
   1.165 +	if ( flags & NEEDS_FLUSH ) {
   1.166 +		*end = 0;
   1.167 +		flags ^= NEEDS_FLUSH;
   1.168 +
   1.169 +		if ( flags ) {
   1.170 +			char* p = start;	// the read pointer
   1.171 +			char* q = start;	// the write pointer
   1.172 +
   1.173 +			while( p < end ) {
   1.174 +				if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == CR ) {
   1.175 +					// CR-LF pair becomes LF
   1.176 +					// CR alone becomes LF
   1.177 +					// LF-CR becomes LF
   1.178 +					if ( *(p+1) == LF ) {
   1.179 +						p += 2;
   1.180 +					}
   1.181 +					else {
   1.182 +						++p;
   1.183 +					}
   1.184 +					*q++ = LF;
   1.185 +				}
   1.186 +				else if ( (flags & NEEDS_NEWLINE_NORMALIZATION) && *p == LF ) {
   1.187 +					if ( *(p+1) == CR ) {
   1.188 +						p += 2;
   1.189 +					}
   1.190 +					else {
   1.191 +						++p;
   1.192 +					}
   1.193 +					*q++ = LF;
   1.194 +				}
   1.195 +				else if ( (flags & NEEDS_ENTITY_PROCESSING) && *p == '&' ) {
   1.196 +					int i=0;
   1.197 +
   1.198 +					// Entities handled by tinyXML2:
   1.199 +					// - special entities in the entity table [in/out]
   1.200 +					// - numeric character reference [in]
   1.201 +					//   &#20013; or &#x4e2d;
   1.202 +
   1.203 +					if ( *(p+1) == '#' ) {
   1.204 +						char buf[10] = { 0 };
   1.205 +						int len;
   1.206 +						p = const_cast<char*>( XMLUtil::GetCharacterRef( p, buf, &len ) );
   1.207 +						for( int i=0; i<len; ++i ) {
   1.208 +							*q++ = buf[i];
   1.209 +						}
   1.210 +						TIXMLASSERT( q <= p );
   1.211 +					}
   1.212 +					else {
   1.213 +						for( i=0; i<NUM_ENTITIES; ++i ) {
   1.214 +							if (    strncmp( p+1, entities[i].pattern, entities[i].length ) == 0
   1.215 +								 && *(p+entities[i].length+1) == ';' ) 
   1.216 +							{
   1.217 +								// Found an entity convert;
   1.218 +								*q = entities[i].value;
   1.219 +								++q;
   1.220 +								p += entities[i].length + 2;
   1.221 +								break;
   1.222 +							}
   1.223 +						}
   1.224 +						if ( i == NUM_ENTITIES ) {
   1.225 +							// fixme: treat as error?
   1.226 +							++p;
   1.227 +							++q;
   1.228 +						}
   1.229 +					}
   1.230 +				}
   1.231 +				else {
   1.232 +					*q = *p;
   1.233 +					++p;
   1.234 +					++q;
   1.235 +				}
   1.236 +			}
   1.237 +			*q = 0;
   1.238 +		}
   1.239 +		flags = (flags & NEEDS_DELETE);
   1.240 +	}
   1.241 +	return start;
   1.242 +}
   1.243 +
   1.244 +
   1.245 +
   1.246 +
   1.247 +// --------- XMLUtil ----------- //
   1.248 +
   1.249 +const char* XMLUtil::ReadBOM( const char* p, bool* bom )
   1.250 +{
   1.251 +	*bom = false;
   1.252 +	const unsigned char* pu = reinterpret_cast<const unsigned char*>(p);
   1.253 +	// Check for BOM:
   1.254 +	if (    *(pu+0) == TIXML_UTF_LEAD_0 
   1.255 +		 && *(pu+1) == TIXML_UTF_LEAD_1
   1.256 +		 && *(pu+2) == TIXML_UTF_LEAD_2 ) 
   1.257 +	{
   1.258 +		*bom = true;
   1.259 +		p += 3;
   1.260 +	}
   1.261 +	return p;
   1.262 +}
   1.263 +
   1.264 +
   1.265 +void XMLUtil::ConvertUTF32ToUTF8( unsigned long input, char* output, int* length )
   1.266 +{
   1.267 +	const unsigned long BYTE_MASK = 0xBF;
   1.268 +	const unsigned long BYTE_MARK = 0x80;
   1.269 +	const unsigned long FIRST_BYTE_MARK[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
   1.270 +
   1.271 +	if (input < 0x80) 
   1.272 +		*length = 1;
   1.273 +	else if ( input < 0x800 )
   1.274 +		*length = 2;
   1.275 +	else if ( input < 0x10000 )
   1.276 +		*length = 3;
   1.277 +	else if ( input < 0x200000 )
   1.278 +		*length = 4;
   1.279 +	else
   1.280 +		{ *length = 0; return; }	// This code won't covert this correctly anyway.
   1.281 +
   1.282 +	output += *length;
   1.283 +
   1.284 +	// Scary scary fall throughs.
   1.285 +	switch (*length) 
   1.286 +	{
   1.287 +		case 4:
   1.288 +			--output; 
   1.289 +			*output = (char)((input | BYTE_MARK) & BYTE_MASK); 
   1.290 +			input >>= 6;
   1.291 +		case 3:
   1.292 +			--output; 
   1.293 +			*output = (char)((input | BYTE_MARK) & BYTE_MASK); 
   1.294 +			input >>= 6;
   1.295 +		case 2:
   1.296 +			--output; 
   1.297 +			*output = (char)((input | BYTE_MARK) & BYTE_MASK); 
   1.298 +			input >>= 6;
   1.299 +		case 1:
   1.300 +			--output; 
   1.301 +			*output = (char)(input | FIRST_BYTE_MARK[*length]);
   1.302 +	}
   1.303 +}
   1.304 +
   1.305 +
   1.306 +const char* XMLUtil::GetCharacterRef( const char* p, char* value, int* length )
   1.307 +{
   1.308 +	// Presume an entity, and pull it out.
   1.309 +	*length = 0;
   1.310 +
   1.311 +	if ( *(p+1) == '#' && *(p+2) )
   1.312 +	{
   1.313 +		unsigned long ucs = 0;
   1.314 +		ptrdiff_t delta = 0;
   1.315 +		unsigned mult = 1;
   1.316 +
   1.317 +		if ( *(p+2) == 'x' )
   1.318 +		{
   1.319 +			// Hexadecimal.
   1.320 +			if ( !*(p+3) ) return 0;
   1.321 +
   1.322 +			const char* q = p+3;
   1.323 +			q = strchr( q, ';' );
   1.324 +
   1.325 +			if ( !q || !*q ) return 0;
   1.326 +
   1.327 +			delta = q-p;
   1.328 +			--q;
   1.329 +
   1.330 +			while ( *q != 'x' )
   1.331 +			{
   1.332 +				if ( *q >= '0' && *q <= '9' )
   1.333 +					ucs += mult * (*q - '0');
   1.334 +				else if ( *q >= 'a' && *q <= 'f' )
   1.335 +					ucs += mult * (*q - 'a' + 10);
   1.336 +				else if ( *q >= 'A' && *q <= 'F' )
   1.337 +					ucs += mult * (*q - 'A' + 10 );
   1.338 +				else 
   1.339 +					return 0;
   1.340 +				mult *= 16;
   1.341 +				--q;
   1.342 +			}
   1.343 +		}
   1.344 +		else
   1.345 +		{
   1.346 +			// Decimal.
   1.347 +			if ( !*(p+2) ) return 0;
   1.348 +
   1.349 +			const char* q = p+2;
   1.350 +			q = strchr( q, ';' );
   1.351 +
   1.352 +			if ( !q || !*q ) return 0;
   1.353 +
   1.354 +			delta = q-p;
   1.355 +			--q;
   1.356 +
   1.357 +			while ( *q != '#' )
   1.358 +			{
   1.359 +				if ( *q >= '0' && *q <= '9' )
   1.360 +					ucs += mult * (*q - '0');
   1.361 +				else 
   1.362 +					return 0;
   1.363 +				mult *= 10;
   1.364 +				--q;
   1.365 +			}
   1.366 +		}
   1.367 +		// convert the UCS to UTF-8
   1.368 +		ConvertUTF32ToUTF8( ucs, value, length );
   1.369 +		return p + delta + 1;
   1.370 +	}
   1.371 +	return p+1;
   1.372 +}
   1.373 +
   1.374 +
   1.375 +char* XMLDocument::Identify( char* p, XMLNode** node ) 
   1.376 +{
   1.377 +	XMLNode* returnNode = 0;
   1.378 +	char* start = p;
   1.379 +	p = XMLUtil::SkipWhiteSpace( p );
   1.380 +	if( !p || !*p )
   1.381 +	{
   1.382 +		return p;
   1.383 +	}
   1.384 +
   1.385 +	// What is this thing? 
   1.386 +	// - Elements start with a letter or underscore, but xml is reserved.
   1.387 +	// - Comments: <!--
   1.388 +	// - Decleration: <?
   1.389 +	// - Everthing else is unknown to tinyxml.
   1.390 +	//
   1.391 +
   1.392 +	static const char* xmlHeader		= { "<?" };
   1.393 +	static const char* commentHeader	= { "<!--" };
   1.394 +	static const char* dtdHeader		= { "<!" };
   1.395 +	static const char* cdataHeader		= { "<![CDATA[" };
   1.396 +	static const char* elementHeader	= { "<" };	// and a header for everything else; check last.
   1.397 +
   1.398 +	static const int xmlHeaderLen		= 2;
   1.399 +	static const int commentHeaderLen	= 4;
   1.400 +	static const int dtdHeaderLen		= 2;
   1.401 +	static const int cdataHeaderLen		= 9;
   1.402 +	static const int elementHeaderLen	= 1;
   1.403 +
   1.404 +#if defined(_MSC_VER)
   1.405 +#pragma warning ( push )
   1.406 +#pragma warning ( disable : 4127 )
   1.407 +#endif
   1.408 +	TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
   1.409 +	TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
   1.410 +#if defined(_MSC_VER)
   1.411 +#pragma warning (pop)
   1.412 +#endif
   1.413 +	if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
   1.414 +		returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
   1.415 +		returnNode->memPool = &commentPool;
   1.416 +		p += xmlHeaderLen;
   1.417 +	}
   1.418 +	else if ( XMLUtil::StringEqual( p, commentHeader, commentHeaderLen ) ) {
   1.419 +		returnNode = new (commentPool.Alloc()) XMLComment( this );
   1.420 +		returnNode->memPool = &commentPool;
   1.421 +		p += commentHeaderLen;
   1.422 +	}
   1.423 +	else if ( XMLUtil::StringEqual( p, cdataHeader, cdataHeaderLen ) ) {
   1.424 +		XMLText* text = new (textPool.Alloc()) XMLText( this );
   1.425 +		returnNode = text;
   1.426 +		returnNode->memPool = &textPool;
   1.427 +		p += cdataHeaderLen;
   1.428 +		text->SetCData( true );
   1.429 +	}
   1.430 +	else if ( XMLUtil::StringEqual( p, dtdHeader, dtdHeaderLen ) ) {
   1.431 +		returnNode = new (commentPool.Alloc()) XMLUnknown( this );
   1.432 +		returnNode->memPool = &commentPool;
   1.433 +		p += dtdHeaderLen;
   1.434 +	}
   1.435 +	else if ( XMLUtil::StringEqual( p, elementHeader, elementHeaderLen ) ) {
   1.436 +		returnNode = new (elementPool.Alloc()) XMLElement( this );
   1.437 +		returnNode->memPool = &elementPool;
   1.438 +		p += elementHeaderLen;
   1.439 +	}
   1.440 +	else {
   1.441 +		returnNode = new (textPool.Alloc()) XMLText( this );
   1.442 +		returnNode->memPool = &textPool;
   1.443 +		p = start;	// Back it up, all the text counts.
   1.444 +	}
   1.445 +
   1.446 +	*node = returnNode;
   1.447 +	return p;
   1.448 +}
   1.449 +
   1.450 +
   1.451 +bool XMLDocument::Accept( XMLVisitor* visitor ) const
   1.452 +{
   1.453 +	if ( visitor->VisitEnter( *this ) )
   1.454 +	{
   1.455 +		for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
   1.456 +		{
   1.457 +			if ( !node->Accept( visitor ) )
   1.458 +				break;
   1.459 +		}
   1.460 +	}
   1.461 +	return visitor->VisitExit( *this );
   1.462 +}
   1.463 +
   1.464 +
   1.465 +// --------- XMLNode ----------- //
   1.466 +
   1.467 +XMLNode::XMLNode( XMLDocument* doc ) :
   1.468 +	document( doc ),
   1.469 +	parent( 0 ),
   1.470 +	firstChild( 0 ), lastChild( 0 ),
   1.471 +	prev( 0 ), next( 0 )
   1.472 +{
   1.473 +}
   1.474 +
   1.475 +
   1.476 +XMLNode::~XMLNode()
   1.477 +{
   1.478 +	DeleteChildren();
   1.479 +	if ( parent ) {
   1.480 +		parent->Unlink( this );
   1.481 +	}
   1.482 +}
   1.483 +
   1.484 +
   1.485 +void XMLNode::SetValue( const char* str, bool staticMem )
   1.486 +{
   1.487 +	if ( staticMem )
   1.488 +		value.SetInternedStr( str );
   1.489 +	else
   1.490 +		value.SetStr( str );
   1.491 +}
   1.492 +
   1.493 +
   1.494 +void XMLNode::DeleteChildren()
   1.495 +{
   1.496 +	while( firstChild ) {
   1.497 +		XMLNode* node = firstChild;
   1.498 +		Unlink( node );
   1.499 +		
   1.500 +		DELETE_NODE( node );
   1.501 +	}
   1.502 +	firstChild = lastChild = 0;
   1.503 +}
   1.504 +
   1.505 +
   1.506 +void XMLNode::Unlink( XMLNode* child )
   1.507 +{
   1.508 +	TIXMLASSERT( child->parent == this );
   1.509 +	if ( child == firstChild ) 
   1.510 +		firstChild = firstChild->next;
   1.511 +	if ( child == lastChild ) 
   1.512 +		lastChild = lastChild->prev;
   1.513 +
   1.514 +	if ( child->prev ) {
   1.515 +		child->prev->next = child->next;
   1.516 +	}
   1.517 +	if ( child->next ) {
   1.518 +		child->next->prev = child->prev;
   1.519 +	}
   1.520 +	child->parent = 0;
   1.521 +}
   1.522 +
   1.523 +
   1.524 +void XMLNode::DeleteChild( XMLNode* node )
   1.525 +{
   1.526 +	TIXMLASSERT( node->parent == this );
   1.527 +	DELETE_NODE( node );
   1.528 +}
   1.529 +
   1.530 +
   1.531 +XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
   1.532 +{
   1.533 +	if ( lastChild ) {
   1.534 +		TIXMLASSERT( firstChild );
   1.535 +		TIXMLASSERT( lastChild->next == 0 );
   1.536 +		lastChild->next = addThis;
   1.537 +		addThis->prev = lastChild;
   1.538 +		lastChild = addThis;
   1.539 +
   1.540 +		addThis->next = 0;
   1.541 +	}
   1.542 +	else {
   1.543 +		TIXMLASSERT( firstChild == 0 );
   1.544 +		firstChild = lastChild = addThis;
   1.545 +
   1.546 +		addThis->prev = 0;
   1.547 +		addThis->next = 0;
   1.548 +	}
   1.549 +	addThis->parent = this;
   1.550 +	return addThis;
   1.551 +}
   1.552 +
   1.553 +
   1.554 +XMLNode* XMLNode::InsertFirstChild( XMLNode* addThis )
   1.555 +{
   1.556 +	if ( firstChild ) {
   1.557 +		TIXMLASSERT( lastChild );
   1.558 +		TIXMLASSERT( firstChild->prev == 0 );
   1.559 +
   1.560 +		firstChild->prev = addThis;
   1.561 +		addThis->next = firstChild;
   1.562 +		firstChild = addThis;
   1.563 +
   1.564 +		addThis->prev = 0;
   1.565 +	}
   1.566 +	else {
   1.567 +		TIXMLASSERT( lastChild == 0 );
   1.568 +		firstChild = lastChild = addThis;
   1.569 +
   1.570 +		addThis->prev = 0;
   1.571 +		addThis->next = 0;
   1.572 +	}
   1.573 +	addThis->parent = this;
   1.574 +	return addThis;
   1.575 +}
   1.576 +
   1.577 +
   1.578 +XMLNode* XMLNode::InsertAfterChild( XMLNode* afterThis, XMLNode* addThis )
   1.579 +{
   1.580 +	TIXMLASSERT( afterThis->parent == this );
   1.581 +	if ( afterThis->parent != this )
   1.582 +		return 0;
   1.583 +
   1.584 +	if ( afterThis->next == 0 ) {
   1.585 +		// The last node or the only node.
   1.586 +		return InsertEndChild( addThis );
   1.587 +	}
   1.588 +	addThis->prev = afterThis;
   1.589 +	addThis->next = afterThis->next;
   1.590 +	afterThis->next->prev = addThis;
   1.591 +	afterThis->next = addThis;
   1.592 +	addThis->parent = this;
   1.593 +	return addThis;
   1.594 +}
   1.595 +
   1.596 +
   1.597 +
   1.598 +
   1.599 +const XMLElement* XMLNode::FirstChildElement( const char* value ) const
   1.600 +{
   1.601 +	for( XMLNode* node=firstChild; node; node=node->next ) {
   1.602 +		XMLElement* element = node->ToElement();
   1.603 +		if ( element ) {
   1.604 +			if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
   1.605 +				return element;
   1.606 +			}
   1.607 +		}
   1.608 +	}
   1.609 +	return 0;
   1.610 +}
   1.611 +
   1.612 +
   1.613 +const XMLElement* XMLNode::LastChildElement( const char* value ) const
   1.614 +{
   1.615 +	for( XMLNode* node=lastChild; node; node=node->prev ) {
   1.616 +		XMLElement* element = node->ToElement();
   1.617 +		if ( element ) {
   1.618 +			if ( !value || XMLUtil::StringEqual( element->Name(), value ) ) {
   1.619 +				return element;
   1.620 +			}
   1.621 +		}
   1.622 +	}
   1.623 +	return 0;
   1.624 +}
   1.625 +
   1.626 +
   1.627 +const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
   1.628 +{
   1.629 +	for( XMLNode* element=this->next; element; element = element->next ) {
   1.630 +		if (    element->ToElement() 
   1.631 +			 && (!value || XMLUtil::StringEqual( value, element->Value() ))) 
   1.632 +		{
   1.633 +			return element->ToElement();
   1.634 +		}
   1.635 +	}
   1.636 +	return 0;
   1.637 +}
   1.638 +
   1.639 +
   1.640 +const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
   1.641 +{
   1.642 +	for( XMLNode* element=this->prev; element; element = element->prev ) {
   1.643 +		if (    element->ToElement()
   1.644 +			 && (!value || XMLUtil::StringEqual( value, element->Value() ))) 
   1.645 +		{
   1.646 +			return element->ToElement();
   1.647 +		}
   1.648 +	}
   1.649 +	return 0;
   1.650 +}
   1.651 +
   1.652 +
   1.653 +char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
   1.654 +{
   1.655 +	// This is a recursive method, but thinking about it "at the current level"
   1.656 +	// it is a pretty simple flat list:
   1.657 +	//		<foo/>
   1.658 +	//		<!-- comment -->
   1.659 +	//
   1.660 +	// With a special case:
   1.661 +	//		<foo>
   1.662 +	//		</foo>
   1.663 +	//		<!-- comment -->
   1.664 +	//		
   1.665 +	// Where the closing element (/foo) *must* be the next thing after the opening
   1.666 +	// element, and the names must match. BUT the tricky bit is that the closing
   1.667 +	// element will be read by the child.
   1.668 +	// 
   1.669 +	// 'endTag' is the end tag for this node, it is returned by a call to a child.
   1.670 +	// 'parentEnd' is the end tag for the parent, which is filled in and returned.
   1.671 +
   1.672 +	while( p && *p ) {
   1.673 +		XMLNode* node = 0;
   1.674 +
   1.675 +		p = document->Identify( p, &node );
   1.676 +		if ( p == 0 || node == 0 ) {
   1.677 +			break;
   1.678 +		}
   1.679 +
   1.680 +		StrPair endTag;
   1.681 +		p = node->ParseDeep( p, &endTag );
   1.682 +		if ( !p ) {
   1.683 +			DELETE_NODE( node );
   1.684 +			node = 0;
   1.685 +			if ( !document->Error() ) {
   1.686 +				document->SetError( XML_ERROR_PARSING, 0, 0 );
   1.687 +			}
   1.688 +			break;
   1.689 +		}
   1.690 +
   1.691 +		// We read the end tag. Return it to the parent.
   1.692 +		if ( node->ToElement() && node->ToElement()->ClosingType() == XMLElement::CLOSING ) {
   1.693 +			if ( parentEnd ) {
   1.694 +				*parentEnd = ((XMLElement*)node)->value;
   1.695 +			}
   1.696 +			DELETE_NODE( node );
   1.697 +			return p;
   1.698 +		}
   1.699 +
   1.700 +		// Handle an end tag returned to this level.
   1.701 +		// And handle a bunch of annoying errors.
   1.702 +		XMLElement* ele = node->ToElement();
   1.703 +		if ( ele ) {
   1.704 +			if ( endTag.Empty() && ele->ClosingType() == XMLElement::OPEN ) {
   1.705 +				document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
   1.706 +				p = 0;
   1.707 +			}
   1.708 +			else if ( !endTag.Empty() && ele->ClosingType() != XMLElement::OPEN ) {
   1.709 +				document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
   1.710 +				p = 0;
   1.711 +			}
   1.712 +			else if ( !endTag.Empty() ) {
   1.713 +				if ( !XMLUtil::StringEqual( endTag.GetStr(), node->Value() )) { 
   1.714 +					document->SetError( XML_ERROR_MISMATCHED_ELEMENT, node->Value(), 0 );
   1.715 +					p = 0;
   1.716 +				}
   1.717 +			}
   1.718 +		}
   1.719 +		if ( p == 0 ) {
   1.720 +			DELETE_NODE( node );
   1.721 +			node = 0;
   1.722 +		}
   1.723 +		if ( node ) {
   1.724 +			this->InsertEndChild( node );
   1.725 +		}
   1.726 +	}
   1.727 +	return 0;
   1.728 +}
   1.729 +
   1.730 +// --------- XMLText ---------- //
   1.731 +char* XMLText::ParseDeep( char* p, StrPair* )
   1.732 +{
   1.733 +	const char* start = p;
   1.734 +	if ( this->CData() ) {
   1.735 +		p = value.ParseText( p, "]]>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
   1.736 +		if ( !p ) {
   1.737 +			document->SetError( XML_ERROR_PARSING_CDATA, start, 0 );
   1.738 +		}
   1.739 +		return p;
   1.740 +	}
   1.741 +	else {
   1.742 +		p = value.ParseText( p, "<", document->ProcessEntities() ? StrPair::TEXT_ELEMENT : StrPair::TEXT_ELEMENT_LEAVE_ENTITIES );
   1.743 +		if ( !p ) {
   1.744 +			document->SetError( XML_ERROR_PARSING_TEXT, start, 0 );
   1.745 +		}
   1.746 +		if ( p && *p ) {
   1.747 +			return p-1;
   1.748 +		}
   1.749 +	}
   1.750 +	return 0;
   1.751 +}
   1.752 +
   1.753 +
   1.754 +XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
   1.755 +{
   1.756 +	if ( !doc ) {
   1.757 +		doc = document;
   1.758 +	}
   1.759 +	XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
   1.760 +	text->SetCData( this->CData() );
   1.761 +	return text;
   1.762 +}
   1.763 +
   1.764 +
   1.765 +bool XMLText::ShallowEqual( const XMLNode* compare ) const
   1.766 +{
   1.767 +	return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
   1.768 +}
   1.769 +
   1.770 +
   1.771 +bool XMLText::Accept( XMLVisitor* visitor ) const
   1.772 +{
   1.773 +	return visitor->Visit( *this );
   1.774 +}
   1.775 +
   1.776 +
   1.777 +// --------- XMLComment ---------- //
   1.778 +
   1.779 +XMLComment::XMLComment( XMLDocument* doc ) : XMLNode( doc )
   1.780 +{
   1.781 +}
   1.782 +
   1.783 +
   1.784 +XMLComment::~XMLComment()
   1.785 +{
   1.786 +	//printf( "~XMLComment\n" );
   1.787 +}
   1.788 +
   1.789 +
   1.790 +char* XMLComment::ParseDeep( char* p, StrPair* )
   1.791 +{
   1.792 +	// Comment parses as text.
   1.793 +	const char* start = p;
   1.794 +	p = value.ParseText( p, "-->", StrPair::COMMENT );
   1.795 +	if ( p == 0 ) {
   1.796 +		document->SetError( XML_ERROR_PARSING_COMMENT, start, 0 );
   1.797 +	}
   1.798 +	return p;
   1.799 +}
   1.800 +
   1.801 +
   1.802 +XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
   1.803 +{
   1.804 +	if ( !doc ) {
   1.805 +		doc = document;
   1.806 +	}
   1.807 +	XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
   1.808 +	return comment;
   1.809 +}
   1.810 +
   1.811 +
   1.812 +bool XMLComment::ShallowEqual( const XMLNode* compare ) const
   1.813 +{
   1.814 +	return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
   1.815 +}
   1.816 +
   1.817 +
   1.818 +bool XMLComment::Accept( XMLVisitor* visitor ) const
   1.819 +{
   1.820 +	return visitor->Visit( *this );
   1.821 +}
   1.822 +
   1.823 +
   1.824 +// --------- XMLDeclaration ---------- //
   1.825 +
   1.826 +XMLDeclaration::XMLDeclaration( XMLDocument* doc ) : XMLNode( doc )
   1.827 +{
   1.828 +}
   1.829 +
   1.830 +
   1.831 +XMLDeclaration::~XMLDeclaration()
   1.832 +{
   1.833 +	//printf( "~XMLDeclaration\n" );
   1.834 +}
   1.835 +
   1.836 +
   1.837 +char* XMLDeclaration::ParseDeep( char* p, StrPair* )
   1.838 +{
   1.839 +	// Declaration parses as text.
   1.840 +	const char* start = p;
   1.841 +	p = value.ParseText( p, "?>", StrPair::NEEDS_NEWLINE_NORMALIZATION );
   1.842 +	if ( p == 0 ) {
   1.843 +		document->SetError( XML_ERROR_PARSING_DECLARATION, start, 0 );
   1.844 +	}
   1.845 +	return p;
   1.846 +}
   1.847 +
   1.848 +
   1.849 +XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
   1.850 +{
   1.851 +	if ( !doc ) {
   1.852 +		doc = document;
   1.853 +	}
   1.854 +	XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
   1.855 +	return dec;
   1.856 +}
   1.857 +
   1.858 +
   1.859 +bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
   1.860 +{
   1.861 +	return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
   1.862 +}
   1.863 +
   1.864 +
   1.865 +
   1.866 +bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
   1.867 +{
   1.868 +	return visitor->Visit( *this );
   1.869 +}
   1.870 +
   1.871 +// --------- XMLUnknown ---------- //
   1.872 +
   1.873 +XMLUnknown::XMLUnknown( XMLDocument* doc ) : XMLNode( doc )
   1.874 +{
   1.875 +}
   1.876 +
   1.877 +
   1.878 +XMLUnknown::~XMLUnknown()
   1.879 +{
   1.880 +}
   1.881 +
   1.882 +
   1.883 +char* XMLUnknown::ParseDeep( char* p, StrPair* )
   1.884 +{
   1.885 +	// Unknown parses as text.
   1.886 +	const char* start = p;
   1.887 +
   1.888 +	p = value.ParseText( p, ">", StrPair::NEEDS_NEWLINE_NORMALIZATION );
   1.889 +	if ( !p ) {
   1.890 +		document->SetError( XML_ERROR_PARSING_UNKNOWN, start, 0 );
   1.891 +	}
   1.892 +	return p;
   1.893 +}
   1.894 +
   1.895 +
   1.896 +XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
   1.897 +{
   1.898 +	if ( !doc ) {
   1.899 +		doc = document;
   1.900 +	}
   1.901 +	XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
   1.902 +	return text;
   1.903 +}
   1.904 +
   1.905 +
   1.906 +bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
   1.907 +{
   1.908 +	return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
   1.909 +}
   1.910 +
   1.911 +
   1.912 +bool XMLUnknown::Accept( XMLVisitor* visitor ) const
   1.913 +{
   1.914 +	return visitor->Visit( *this );
   1.915 +}
   1.916 +
   1.917 +// --------- XMLAttribute ---------- //
   1.918 +char* XMLAttribute::ParseDeep( char* p, bool processEntities )
   1.919 +{
   1.920 +	p = name.ParseText( p, "=", StrPair::ATTRIBUTE_NAME );
   1.921 +	if ( !p || !*p ) return 0;
   1.922 +
   1.923 +	char endTag[2] = { *p, 0 };
   1.924 +	++p;
   1.925 +	p = value.ParseText( p, endTag, processEntities ? StrPair::ATTRIBUTE_VALUE : StrPair::ATTRIBUTE_VALUE_LEAVE_ENTITIES );
   1.926 +	//if ( value.Empty() ) return 0;
   1.927 +	return p;
   1.928 +}
   1.929 +
   1.930 +
   1.931 +void XMLAttribute::SetName( const char* n )
   1.932 +{
   1.933 +	name.SetStr( n );
   1.934 +}
   1.935 +
   1.936 +
   1.937 +int XMLAttribute::QueryIntValue( int* value ) const
   1.938 +{
   1.939 +	if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
   1.940 +		return XML_NO_ERROR;
   1.941 +	return XML_WRONG_ATTRIBUTE_TYPE;
   1.942 +}
   1.943 +
   1.944 +
   1.945 +int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
   1.946 +{
   1.947 +	if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
   1.948 +		return XML_NO_ERROR;
   1.949 +	return XML_WRONG_ATTRIBUTE_TYPE;
   1.950 +}
   1.951 +
   1.952 +
   1.953 +int XMLAttribute::QueryBoolValue( bool* value ) const
   1.954 +{
   1.955 +	int ival = -1;
   1.956 +	QueryIntValue( &ival );
   1.957 +
   1.958 +	if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
   1.959 +		*value = true;
   1.960 +		return XML_NO_ERROR;
   1.961 +	}
   1.962 +	else if ( ival == 0 || XMLUtil::StringEqual( Value(), "false" ) ) {
   1.963 +		*value = false;
   1.964 +		return XML_NO_ERROR;
   1.965 +	}
   1.966 +	return XML_WRONG_ATTRIBUTE_TYPE;
   1.967 +}
   1.968 +
   1.969 +
   1.970 +int XMLAttribute::QueryDoubleValue( double* value ) const
   1.971 +{
   1.972 +	if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
   1.973 +		return XML_NO_ERROR;
   1.974 +	return XML_WRONG_ATTRIBUTE_TYPE;
   1.975 +}
   1.976 +
   1.977 +
   1.978 +int XMLAttribute::QueryFloatValue( float* value ) const
   1.979 +{
   1.980 +	if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
   1.981 +		return XML_NO_ERROR;
   1.982 +	return XML_WRONG_ATTRIBUTE_TYPE;
   1.983 +}
   1.984 +
   1.985 +
   1.986 +void XMLAttribute::SetAttribute( const char* v )
   1.987 +{
   1.988 +	value.SetStr( v );
   1.989 +}
   1.990 +
   1.991 +
   1.992 +void XMLAttribute::SetAttribute( int v )
   1.993 +{
   1.994 +	char buf[BUF_SIZE];
   1.995 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );	
   1.996 +	value.SetStr( buf );
   1.997 +}
   1.998 +
   1.999 +
  1.1000 +void XMLAttribute::SetAttribute( unsigned v )
  1.1001 +{
  1.1002 +	char buf[BUF_SIZE];
  1.1003 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );	
  1.1004 +	value.SetStr( buf );
  1.1005 +}
  1.1006 +
  1.1007 +
  1.1008 +void XMLAttribute::SetAttribute( bool v )
  1.1009 +{
  1.1010 +	char buf[BUF_SIZE];
  1.1011 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );	
  1.1012 +	value.SetStr( buf );
  1.1013 +}
  1.1014 +
  1.1015 +void XMLAttribute::SetAttribute( double v )
  1.1016 +{
  1.1017 +	char buf[BUF_SIZE];
  1.1018 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	
  1.1019 +	value.SetStr( buf );
  1.1020 +}
  1.1021 +
  1.1022 +void XMLAttribute::SetAttribute( float v )
  1.1023 +{
  1.1024 +	char buf[BUF_SIZE];
  1.1025 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	
  1.1026 +	value.SetStr( buf );
  1.1027 +}
  1.1028 +
  1.1029 +
  1.1030 +// --------- XMLElement ---------- //
  1.1031 +XMLElement::XMLElement( XMLDocument* doc ) : XMLNode( doc ),
  1.1032 +	closingType( 0 ),
  1.1033 +	rootAttribute( 0 )
  1.1034 +{
  1.1035 +}
  1.1036 +
  1.1037 +
  1.1038 +XMLElement::~XMLElement()
  1.1039 +{
  1.1040 +	while( rootAttribute ) {
  1.1041 +		XMLAttribute* next = rootAttribute->next;
  1.1042 +		DELETE_ATTRIBUTE( rootAttribute );
  1.1043 +		rootAttribute = next;
  1.1044 +	}
  1.1045 +}
  1.1046 +
  1.1047 +
  1.1048 +XMLAttribute* XMLElement::FindAttribute( const char* name )
  1.1049 +{
  1.1050 +	XMLAttribute* a = 0;
  1.1051 +	for( a=rootAttribute; a; a = a->next ) {
  1.1052 +		if ( XMLUtil::StringEqual( a->Name(), name ) )
  1.1053 +			return a;
  1.1054 +	}
  1.1055 +	return 0;
  1.1056 +}
  1.1057 +
  1.1058 +
  1.1059 +const XMLAttribute* XMLElement::FindAttribute( const char* name ) const
  1.1060 +{
  1.1061 +	XMLAttribute* a = 0;
  1.1062 +	for( a=rootAttribute; a; a = a->next ) {
  1.1063 +		if ( XMLUtil::StringEqual( a->Name(), name ) )
  1.1064 +			return a;
  1.1065 +	}
  1.1066 +	return 0;
  1.1067 +}
  1.1068 +
  1.1069 +
  1.1070 +const char* XMLElement::Attribute( const char* name, const char* value ) const
  1.1071 +{ 
  1.1072 +	const XMLAttribute* a = FindAttribute( name ); 
  1.1073 +	if ( !a ) 
  1.1074 +		return 0; 
  1.1075 +	if ( !value || XMLUtil::StringEqual( a->Value(), value ))
  1.1076 +		return a->Value();
  1.1077 +	return 0;
  1.1078 +}
  1.1079 +
  1.1080 +
  1.1081 +const char* XMLElement::GetText() const
  1.1082 +{
  1.1083 +	if ( FirstChild() && FirstChild()->ToText() ) {
  1.1084 +		return FirstChild()->ToText()->Value();
  1.1085 +	}
  1.1086 +	return 0;
  1.1087 +}
  1.1088 +
  1.1089 +
  1.1090 +XMLAttribute* XMLElement::FindOrCreateAttribute( const char* name )
  1.1091 +{
  1.1092 +	XMLAttribute* last = 0;
  1.1093 +	XMLAttribute* attrib = 0;
  1.1094 +	for( attrib = rootAttribute;
  1.1095 +		 attrib;
  1.1096 +		 last = attrib, attrib = attrib->next )
  1.1097 +	{		 
  1.1098 +		if ( XMLUtil::StringEqual( attrib->Name(), name ) ) {
  1.1099 +			break;
  1.1100 +		}
  1.1101 +	}
  1.1102 +	if ( !attrib ) {
  1.1103 +		attrib = new (document->attributePool.Alloc() ) XMLAttribute();
  1.1104 +		attrib->memPool = &document->attributePool;
  1.1105 +		if ( last ) {
  1.1106 +			last->next = attrib;
  1.1107 +		}
  1.1108 +		else {
  1.1109 +			rootAttribute = attrib;
  1.1110 +		}
  1.1111 +		attrib->SetName( name );
  1.1112 +	}
  1.1113 +	return attrib;
  1.1114 +}
  1.1115 +
  1.1116 +
  1.1117 +void XMLElement::DeleteAttribute( const char* name )
  1.1118 +{
  1.1119 +	XMLAttribute* prev = 0;
  1.1120 +	for( XMLAttribute* a=rootAttribute; a; a=a->next ) {
  1.1121 +		if ( XMLUtil::StringEqual( name, a->Name() ) ) {
  1.1122 +			if ( prev ) {
  1.1123 +				prev->next = a->next;
  1.1124 +			}
  1.1125 +			else {
  1.1126 +				rootAttribute = a->next;
  1.1127 +			}
  1.1128 +			DELETE_ATTRIBUTE( a );
  1.1129 +			break;
  1.1130 +		}
  1.1131 +		prev = a;
  1.1132 +	}
  1.1133 +}
  1.1134 +
  1.1135 +
  1.1136 +char* XMLElement::ParseAttributes( char* p )
  1.1137 +{
  1.1138 +	const char* start = p;
  1.1139 +	XMLAttribute* prevAttribute = 0;
  1.1140 +
  1.1141 +	// Read the attributes.
  1.1142 +	while( p ) {
  1.1143 +		p = XMLUtil::SkipWhiteSpace( p );
  1.1144 +		if ( !p || !(*p) ) {
  1.1145 +			document->SetError( XML_ERROR_PARSING_ELEMENT, start, Name() );
  1.1146 +			return 0;
  1.1147 +		}
  1.1148 +
  1.1149 +		// attribute.
  1.1150 +		if ( XMLUtil::IsAlpha( *p ) ) {
  1.1151 +			XMLAttribute* attrib = new (document->attributePool.Alloc() ) XMLAttribute();
  1.1152 +			attrib->memPool = &document->attributePool;
  1.1153 +
  1.1154 +			p = attrib->ParseDeep( p, document->ProcessEntities() );
  1.1155 +			if ( !p || Attribute( attrib->Name() ) ) {
  1.1156 +				DELETE_ATTRIBUTE( attrib );
  1.1157 +				document->SetError( XML_ERROR_PARSING_ATTRIBUTE, start, p );
  1.1158 +				return 0;
  1.1159 +			}
  1.1160 +			// There is a minor bug here: if the attribute in the source xml
  1.1161 +			// document is duplicated, it will not be detected and the
  1.1162 +			// attribute will be doubly added. However, tracking the 'prevAttribute'
  1.1163 +			// avoids re-scanning the attribute list. Preferring performance for
  1.1164 +			// now, may reconsider in the future.
  1.1165 +			if ( prevAttribute ) { 
  1.1166 +				prevAttribute->next = attrib;
  1.1167 +			}
  1.1168 +			else {
  1.1169 +				rootAttribute = attrib;
  1.1170 +			}	
  1.1171 +			prevAttribute = attrib;
  1.1172 +		}
  1.1173 +		// end of the tag
  1.1174 +		else if ( *p == '/' && *(p+1) == '>' ) {
  1.1175 +			closingType = CLOSED;
  1.1176 +			return p+2;	// done; sealed element.
  1.1177 +		}
  1.1178 +		// end of the tag
  1.1179 +		else if ( *p == '>' ) {
  1.1180 +			++p;
  1.1181 +			break;
  1.1182 +		}
  1.1183 +		else {
  1.1184 +			document->SetError( XML_ERROR_PARSING_ELEMENT, start, p );
  1.1185 +			return 0;
  1.1186 +		}
  1.1187 +	}
  1.1188 +	return p;
  1.1189 +}
  1.1190 +
  1.1191 +
  1.1192 +//
  1.1193 +//	<ele></ele>
  1.1194 +//	<ele>foo<b>bar</b></ele>
  1.1195 +//
  1.1196 +char* XMLElement::ParseDeep( char* p, StrPair* strPair )
  1.1197 +{
  1.1198 +	// Read the element name.
  1.1199 +	p = XMLUtil::SkipWhiteSpace( p );
  1.1200 +	if ( !p ) return 0;
  1.1201 +
  1.1202 +	// The closing element is the </element> form. It is
  1.1203 +	// parsed just like a regular element then deleted from
  1.1204 +	// the DOM.
  1.1205 +	if ( *p == '/' ) {
  1.1206 +		closingType = CLOSING;
  1.1207 +		++p;
  1.1208 +	}
  1.1209 +
  1.1210 +	p = value.ParseName( p );
  1.1211 +	if ( value.Empty() ) return 0;
  1.1212 +
  1.1213 +	p = ParseAttributes( p );
  1.1214 +	if ( !p || !*p || closingType ) 
  1.1215 +		return p;
  1.1216 +
  1.1217 +	p = XMLNode::ParseDeep( p, strPair );
  1.1218 +	return p;
  1.1219 +}
  1.1220 +
  1.1221 +
  1.1222 +
  1.1223 +XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
  1.1224 +{
  1.1225 +	if ( !doc ) {
  1.1226 +		doc = document;
  1.1227 +	}
  1.1228 +	XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
  1.1229 +	for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
  1.1230 +		element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
  1.1231 +	}
  1.1232 +	return element;
  1.1233 +}
  1.1234 +
  1.1235 +
  1.1236 +bool XMLElement::ShallowEqual( const XMLNode* compare ) const
  1.1237 +{
  1.1238 +	const XMLElement* other = compare->ToElement();
  1.1239 +	if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
  1.1240 +
  1.1241 +		const XMLAttribute* a=FirstAttribute();
  1.1242 +		const XMLAttribute* b=other->FirstAttribute();
  1.1243 +
  1.1244 +		while ( a && b ) {
  1.1245 +			if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
  1.1246 +				return false;
  1.1247 +			}
  1.1248 +		}	
  1.1249 +		if ( a || b ) {
  1.1250 +			// different count
  1.1251 +			return false;
  1.1252 +		}
  1.1253 +		return true;
  1.1254 +	}
  1.1255 +	return false;
  1.1256 +}
  1.1257 +
  1.1258 +
  1.1259 +bool XMLElement::Accept( XMLVisitor* visitor ) const
  1.1260 +{
  1.1261 +	if ( visitor->VisitEnter( *this, rootAttribute ) ) 
  1.1262 +	{
  1.1263 +		for ( const XMLNode* node=FirstChild(); node; node=node->NextSibling() )
  1.1264 +		{
  1.1265 +			if ( !node->Accept( visitor ) )
  1.1266 +				break;
  1.1267 +		}
  1.1268 +	}
  1.1269 +	return visitor->VisitExit( *this );
  1.1270 +}
  1.1271 +
  1.1272 +
  1.1273 +// --------- XMLDocument ----------- //
  1.1274 +XMLDocument::XMLDocument( bool _processEntities ) :
  1.1275 +	XMLNode( 0 ),
  1.1276 +	writeBOM( false ),
  1.1277 +	processEntities( _processEntities ),
  1.1278 +	errorID( 0 ),
  1.1279 +	errorStr1( 0 ),
  1.1280 +	errorStr2( 0 ),
  1.1281 +	charBuffer( 0 )
  1.1282 +{
  1.1283 +	document = this;	// avoid warning about 'this' in initializer list
  1.1284 +}
  1.1285 +
  1.1286 +
  1.1287 +XMLDocument::~XMLDocument()
  1.1288 +{
  1.1289 +	DeleteChildren();
  1.1290 +	delete [] charBuffer;
  1.1291 +
  1.1292 +#if 0
  1.1293 +	textPool.Trace( "text" );
  1.1294 +	elementPool.Trace( "element" );
  1.1295 +	commentPool.Trace( "comment" );
  1.1296 +	attributePool.Trace( "attribute" );
  1.1297 +#endif
  1.1298 +
  1.1299 +	TIXMLASSERT( textPool.CurrentAllocs() == 0 );
  1.1300 +	TIXMLASSERT( elementPool.CurrentAllocs() == 0 );
  1.1301 +	TIXMLASSERT( commentPool.CurrentAllocs() == 0 );
  1.1302 +	TIXMLASSERT( attributePool.CurrentAllocs() == 0 );
  1.1303 +}
  1.1304 +
  1.1305 +
  1.1306 +void XMLDocument::InitDocument()
  1.1307 +{
  1.1308 +	errorID = XML_NO_ERROR;
  1.1309 +	errorStr1 = 0;
  1.1310 +	errorStr2 = 0;
  1.1311 +
  1.1312 +	delete [] charBuffer;
  1.1313 +	charBuffer = 0;
  1.1314 +
  1.1315 +}
  1.1316 +
  1.1317 +
  1.1318 +XMLElement* XMLDocument::NewElement( const char* name )
  1.1319 +{
  1.1320 +	XMLElement* ele = new (elementPool.Alloc()) XMLElement( this );
  1.1321 +	ele->memPool = &elementPool;
  1.1322 +	ele->SetName( name );
  1.1323 +	return ele;
  1.1324 +}
  1.1325 +
  1.1326 +
  1.1327 +XMLComment* XMLDocument::NewComment( const char* str )
  1.1328 +{
  1.1329 +	XMLComment* comment = new (commentPool.Alloc()) XMLComment( this );
  1.1330 +	comment->memPool = &commentPool;
  1.1331 +	comment->SetValue( str );
  1.1332 +	return comment;
  1.1333 +}
  1.1334 +
  1.1335 +
  1.1336 +XMLText* XMLDocument::NewText( const char* str )
  1.1337 +{
  1.1338 +	XMLText* text = new (textPool.Alloc()) XMLText( this );
  1.1339 +	text->memPool = &textPool;
  1.1340 +	text->SetValue( str );
  1.1341 +	return text;
  1.1342 +}
  1.1343 +
  1.1344 +
  1.1345 +XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
  1.1346 +{
  1.1347 +	XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
  1.1348 +	dec->memPool = &commentPool;
  1.1349 +	dec->SetValue( str ? str : "xml version=\"1.0\" encoding=\"UTF-8\"" );
  1.1350 +	return dec;
  1.1351 +}
  1.1352 +
  1.1353 +
  1.1354 +XMLUnknown* XMLDocument::NewUnknown( const char* str )
  1.1355 +{
  1.1356 +	XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
  1.1357 +	unk->memPool = &commentPool;
  1.1358 +	unk->SetValue( str );
  1.1359 +	return unk;
  1.1360 +}
  1.1361 +
  1.1362 +
  1.1363 +int XMLDocument::LoadFile( const char* filename )
  1.1364 +{
  1.1365 +	DeleteChildren();
  1.1366 +	InitDocument();
  1.1367 +
  1.1368 +#if defined(_MSC_VER)
  1.1369 +#pragma warning ( push )
  1.1370 +#pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
  1.1371 +#endif
  1.1372 +	FILE* fp = fopen( filename, "rb" );
  1.1373 +#if defined(_MSC_VER)
  1.1374 +#pragma warning ( pop )
  1.1375 +#endif
  1.1376 +	if ( !fp ) {
  1.1377 +		SetError( XML_ERROR_FILE_NOT_FOUND, filename, 0 );
  1.1378 +		return errorID;
  1.1379 +	}
  1.1380 +	LoadFile( fp );
  1.1381 +	fclose( fp );
  1.1382 +	return errorID;
  1.1383 +}
  1.1384 +
  1.1385 +
  1.1386 +int XMLDocument::LoadFile( FILE* fp ) 
  1.1387 +{
  1.1388 +	DeleteChildren();
  1.1389 +	InitDocument();
  1.1390 +
  1.1391 +	fseek( fp, 0, SEEK_END );
  1.1392 +	unsigned size = ftell( fp );
  1.1393 +	fseek( fp, 0, SEEK_SET );
  1.1394 +
  1.1395 +	if ( size == 0 ) {
  1.1396 +		return errorID;
  1.1397 +	}
  1.1398 +
  1.1399 +	charBuffer = new char[size+1];
  1.1400 +	fread( charBuffer, size, 1, fp );
  1.1401 +	charBuffer[size] = 0;
  1.1402 +
  1.1403 +	const char* p = charBuffer;
  1.1404 +	p = XMLUtil::SkipWhiteSpace( p );
  1.1405 +	p = XMLUtil::ReadBOM( p, &writeBOM );
  1.1406 +	if ( !p || !*p ) {
  1.1407 +		SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  1.1408 +		return errorID;
  1.1409 +	}
  1.1410 +
  1.1411 +	ParseDeep( charBuffer + (p-charBuffer), 0 );
  1.1412 +	return errorID;
  1.1413 +}
  1.1414 +
  1.1415 +
  1.1416 +int XMLDocument::SaveFile( const char* filename )
  1.1417 +{
  1.1418 +#if defined(_MSC_VER)
  1.1419 +#pragma warning ( push )
  1.1420 +#pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
  1.1421 +#endif
  1.1422 +	FILE* fp = fopen( filename, "w" );
  1.1423 +#if defined(_MSC_VER)
  1.1424 +#pragma warning ( pop )
  1.1425 +#endif
  1.1426 +	if ( !fp ) {
  1.1427 +		SetError( XML_ERROR_FILE_COULD_NOT_BE_OPENED, filename, 0 );
  1.1428 +		return errorID;
  1.1429 +	}
  1.1430 +	SaveFile(fp);
  1.1431 +	fclose( fp );
  1.1432 +	return errorID;
  1.1433 +}
  1.1434 +
  1.1435 +
  1.1436 +int XMLDocument::SaveFile( FILE* fp )
  1.1437 +{
  1.1438 +	XMLPrinter stream( fp );
  1.1439 +	Print( &stream );
  1.1440 +	return errorID;
  1.1441 +}
  1.1442 +
  1.1443 +
  1.1444 +int XMLDocument::Parse( const char* p )
  1.1445 +{
  1.1446 +	DeleteChildren();
  1.1447 +	InitDocument();
  1.1448 +
  1.1449 +	if ( !p || !*p ) {
  1.1450 +		SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  1.1451 +		return errorID;
  1.1452 +	}
  1.1453 +	p = XMLUtil::SkipWhiteSpace( p );
  1.1454 +	p = XMLUtil::ReadBOM( p, &writeBOM );
  1.1455 +	if ( !p || !*p ) {
  1.1456 +		SetError( XML_ERROR_EMPTY_DOCUMENT, 0, 0 );
  1.1457 +		return errorID;
  1.1458 +	}
  1.1459 +
  1.1460 +	size_t len = strlen( p );
  1.1461 +	charBuffer = new char[ len+1 ];
  1.1462 +	memcpy( charBuffer, p, len+1 );
  1.1463 +
  1.1464 +	
  1.1465 +	ParseDeep( charBuffer, 0 );
  1.1466 +	return errorID;
  1.1467 +}
  1.1468 +
  1.1469 +
  1.1470 +void XMLDocument::Print( XMLPrinter* streamer ) 
  1.1471 +{
  1.1472 +	XMLPrinter stdStreamer( stdout );
  1.1473 +	if ( !streamer )
  1.1474 +		streamer = &stdStreamer;
  1.1475 +	Accept( streamer );
  1.1476 +}
  1.1477 +
  1.1478 +
  1.1479 +void XMLDocument::SetError( int error, const char* str1, const char* str2 )
  1.1480 +{
  1.1481 +	errorID = error;
  1.1482 +	errorStr1 = str1;
  1.1483 +	errorStr2 = str2;
  1.1484 +}
  1.1485 +
  1.1486 +
  1.1487 +void XMLDocument::PrintError() const 
  1.1488 +{
  1.1489 +	if ( errorID ) {
  1.1490 +		static const int LEN = 20;
  1.1491 +		char buf1[LEN] = { 0 };
  1.1492 +		char buf2[LEN] = { 0 };
  1.1493 +		
  1.1494 +		if ( errorStr1 ) {
  1.1495 +			TIXML_SNPRINTF( buf1, LEN, "%s", errorStr1 );
  1.1496 +		}
  1.1497 +		if ( errorStr2 ) {
  1.1498 +			TIXML_SNPRINTF( buf2, LEN, "%s", errorStr2 );
  1.1499 +		}
  1.1500 +
  1.1501 +		printf( "XMLDocument error id=%d str1=%s str2=%s\n",
  1.1502 +			    errorID, buf1, buf2 );
  1.1503 +	}
  1.1504 +}
  1.1505 +
  1.1506 +
  1.1507 +XMLPrinter::XMLPrinter( FILE* file ) : 
  1.1508 +	elementJustOpened( false ), 
  1.1509 +	firstElement( true ),
  1.1510 +	fp( file ), 
  1.1511 +	depth( 0 ), 
  1.1512 +	textDepth( -1 ),
  1.1513 +	processEntities( true )
  1.1514 +{
  1.1515 +	for( int i=0; i<ENTITY_RANGE; ++i ) {
  1.1516 +		entityFlag[i] = false;
  1.1517 +		restrictedEntityFlag[i] = false;
  1.1518 +	}
  1.1519 +	for( int i=0; i<NUM_ENTITIES; ++i ) {
  1.1520 +		TIXMLASSERT( entities[i].value < ENTITY_RANGE );
  1.1521 +		if ( entities[i].value < ENTITY_RANGE ) {
  1.1522 +			entityFlag[ (int)entities[i].value ] = true;
  1.1523 +		}
  1.1524 +	}
  1.1525 +	restrictedEntityFlag[(int)'&'] = true;
  1.1526 +	restrictedEntityFlag[(int)'<'] = true;
  1.1527 +	restrictedEntityFlag[(int)'>'] = true;	// not required, but consistency is nice
  1.1528 +	buffer.Push( 0 );
  1.1529 +}
  1.1530 +
  1.1531 +
  1.1532 +void XMLPrinter::Print( const char* format, ... )
  1.1533 +{
  1.1534 +    va_list     va;
  1.1535 +    va_start( va, format );
  1.1536 +
  1.1537 +	if ( fp ) {
  1.1538 +		vfprintf( fp, format, va );
  1.1539 +	}
  1.1540 +	else {
  1.1541 +		// This seems brutally complex. Haven't figured out a better
  1.1542 +		// way on windows.
  1.1543 +		#ifdef _MSC_VER
  1.1544 +			int len = -1;
  1.1545 +			int expand = 1000;
  1.1546 +			while ( len < 0 ) {
  1.1547 +				len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), _TRUNCATE, format, va );
  1.1548 +				if ( len < 0 ) {
  1.1549 +					expand *= 3/2;
  1.1550 +					accumulator.PushArr( expand );
  1.1551 +				}
  1.1552 +			}
  1.1553 +			char* p = buffer.PushArr( len ) - 1;
  1.1554 +			memcpy( p, accumulator.Mem(), len+1 );
  1.1555 +		#else
  1.1556 +			int len = vsnprintf( 0, 0, format, va );
  1.1557 +			// Close out and re-start the va-args
  1.1558 +			va_end( va );
  1.1559 +			va_start( va, format );		
  1.1560 +			char* p = buffer.PushArr( len ) - 1;
  1.1561 +			vsnprintf( p, len+1, format, va );
  1.1562 +		#endif
  1.1563 +	}
  1.1564 +    va_end( va );
  1.1565 +}
  1.1566 +
  1.1567 +
  1.1568 +void XMLPrinter::PrintSpace( int depth )
  1.1569 +{
  1.1570 +	for( int i=0; i<depth; ++i ) {
  1.1571 +		Print( "    " );
  1.1572 +	}
  1.1573 +}
  1.1574 +
  1.1575 +
  1.1576 +void XMLPrinter::PrintString( const char* p, bool restricted )
  1.1577 +{
  1.1578 +	// Look for runs of bytes between entities to print.
  1.1579 +	const char* q = p;
  1.1580 +	const bool* flag = restricted ? restrictedEntityFlag : entityFlag;
  1.1581 +
  1.1582 +	if ( processEntities ) {
  1.1583 +		while ( *q ) {
  1.1584 +			// Remember, char is sometimes signed. (How many times has that bitten me?)
  1.1585 +			if ( *q > 0 && *q < ENTITY_RANGE ) {
  1.1586 +				// Check for entities. If one is found, flush
  1.1587 +				// the stream up until the entity, write the 
  1.1588 +				// entity, and keep looking.
  1.1589 +				if ( flag[(unsigned)(*q)] ) {
  1.1590 +					while ( p < q ) {
  1.1591 +						Print( "%c", *p );
  1.1592 +						++p;
  1.1593 +					}
  1.1594 +					for( int i=0; i<NUM_ENTITIES; ++i ) {
  1.1595 +						if ( entities[i].value == *q ) {
  1.1596 +							Print( "&%s;", entities[i].pattern );
  1.1597 +							break;
  1.1598 +						}
  1.1599 +					}
  1.1600 +					++p;
  1.1601 +				}
  1.1602 +			}
  1.1603 +			++q;
  1.1604 +		}
  1.1605 +	}
  1.1606 +	// Flush the remaining string. This will be the entire
  1.1607 +	// string if an entity wasn't found.
  1.1608 +	if ( !processEntities || (q-p > 0) ) {
  1.1609 +		Print( "%s", p );
  1.1610 +	}
  1.1611 +}
  1.1612 +
  1.1613 +
  1.1614 +void XMLPrinter::PushHeader( bool writeBOM, bool writeDec )
  1.1615 +{
  1.1616 +	static const unsigned char bom[] = { TIXML_UTF_LEAD_0, TIXML_UTF_LEAD_1, TIXML_UTF_LEAD_2, 0 };
  1.1617 +	if ( writeBOM ) {
  1.1618 +		Print( "%s", bom );
  1.1619 +	}
  1.1620 +	if ( writeDec ) {
  1.1621 +		PushDeclaration( "xml version=\"1.0\"" );
  1.1622 +	}
  1.1623 +}
  1.1624 +
  1.1625 +
  1.1626 +void XMLPrinter::OpenElement( const char* name )
  1.1627 +{
  1.1628 +	if ( elementJustOpened ) {
  1.1629 +		SealElement();
  1.1630 +	}
  1.1631 +	stack.Push( name );
  1.1632 +
  1.1633 +	if ( textDepth < 0 && !firstElement ) {
  1.1634 +		Print( "\n" );
  1.1635 +		PrintSpace( depth );
  1.1636 +	}
  1.1637 +
  1.1638 +	Print( "<%s", name );
  1.1639 +	elementJustOpened = true;
  1.1640 +	firstElement = false;
  1.1641 +	++depth;
  1.1642 +}
  1.1643 +
  1.1644 +
  1.1645 +void XMLPrinter::PushAttribute( const char* name, const char* value )
  1.1646 +{
  1.1647 +	TIXMLASSERT( elementJustOpened );
  1.1648 +	Print( " %s=\"", name );
  1.1649 +	PrintString( value, false );
  1.1650 +	Print( "\"" );
  1.1651 +}
  1.1652 +
  1.1653 +
  1.1654 +void XMLPrinter::PushAttribute( const char* name, int v )
  1.1655 +{
  1.1656 +	char buf[BUF_SIZE];
  1.1657 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v );	
  1.1658 +	PushAttribute( name, buf );
  1.1659 +}
  1.1660 +
  1.1661 +
  1.1662 +void XMLPrinter::PushAttribute( const char* name, unsigned v )
  1.1663 +{
  1.1664 +	char buf[BUF_SIZE];
  1.1665 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%u", v );	
  1.1666 +	PushAttribute( name, buf );
  1.1667 +}
  1.1668 +
  1.1669 +
  1.1670 +void XMLPrinter::PushAttribute( const char* name, bool v )
  1.1671 +{
  1.1672 +	char buf[BUF_SIZE];
  1.1673 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%d", v ? 1 : 0 );	
  1.1674 +	PushAttribute( name, buf );
  1.1675 +}
  1.1676 +
  1.1677 +
  1.1678 +void XMLPrinter::PushAttribute( const char* name, double v )
  1.1679 +{
  1.1680 +	char buf[BUF_SIZE];
  1.1681 +	TIXML_SNPRINTF( buf, BUF_SIZE, "%f", v );	
  1.1682 +	PushAttribute( name, buf );
  1.1683 +}
  1.1684 +
  1.1685 +
  1.1686 +void XMLPrinter::CloseElement()
  1.1687 +{
  1.1688 +	--depth;
  1.1689 +	const char* name = stack.Pop();
  1.1690 +
  1.1691 +	if ( elementJustOpened ) {
  1.1692 +		Print( "/>" );
  1.1693 +	}
  1.1694 +	else {
  1.1695 +		if ( textDepth < 0 ) {
  1.1696 +			Print( "\n" );
  1.1697 +			PrintSpace( depth );
  1.1698 +		}
  1.1699 +		Print( "</%s>", name );
  1.1700 +	}
  1.1701 +
  1.1702 +	if ( textDepth == depth )
  1.1703 +		textDepth = -1;
  1.1704 +	if ( depth == 0 )
  1.1705 +		Print( "\n" );
  1.1706 +	elementJustOpened = false;
  1.1707 +}
  1.1708 +
  1.1709 +
  1.1710 +void XMLPrinter::SealElement()
  1.1711 +{
  1.1712 +	elementJustOpened = false;
  1.1713 +	Print( ">" );
  1.1714 +}
  1.1715 +
  1.1716 +
  1.1717 +void XMLPrinter::PushText( const char* text, bool cdata )
  1.1718 +{
  1.1719 +	textDepth = depth-1;
  1.1720 +
  1.1721 +	if ( elementJustOpened ) {
  1.1722 +		SealElement();
  1.1723 +	}
  1.1724 +	if ( cdata ) {
  1.1725 +		Print( "<![CDATA[" );
  1.1726 +		Print( "%s", text );
  1.1727 +		Print( "]]>" );
  1.1728 +	}
  1.1729 +	else {
  1.1730 +		PrintString( text, true );
  1.1731 +	}
  1.1732 +}
  1.1733 +
  1.1734 +
  1.1735 +void XMLPrinter::PushComment( const char* comment )
  1.1736 +{
  1.1737 +	if ( elementJustOpened ) {
  1.1738 +		SealElement();
  1.1739 +	}
  1.1740 +	if ( textDepth < 0 && !firstElement ) {
  1.1741 +		Print( "\n" );
  1.1742 +		PrintSpace( depth );
  1.1743 +	}
  1.1744 +	firstElement = false;
  1.1745 +	Print( "<!--%s-->", comment );
  1.1746 +}
  1.1747 +
  1.1748 +
  1.1749 +void XMLPrinter::PushDeclaration( const char* value )
  1.1750 +{
  1.1751 +	if ( elementJustOpened ) {
  1.1752 +		SealElement();
  1.1753 +	}
  1.1754 +	if ( textDepth < 0 && !firstElement) {
  1.1755 +		Print( "\n" );
  1.1756 +		PrintSpace( depth );
  1.1757 +	}
  1.1758 +	firstElement = false;
  1.1759 +	Print( "<?%s?>", value );
  1.1760 +}
  1.1761 +
  1.1762 +
  1.1763 +void XMLPrinter::PushUnknown( const char* value )
  1.1764 +{
  1.1765 +	if ( elementJustOpened ) {
  1.1766 +		SealElement();
  1.1767 +	}
  1.1768 +	if ( textDepth < 0 && !firstElement ) {
  1.1769 +		Print( "\n" );
  1.1770 +		PrintSpace( depth );
  1.1771 +	}
  1.1772 +	firstElement = false;
  1.1773 +	Print( "<!%s>", value );
  1.1774 +}
  1.1775 +
  1.1776 +
  1.1777 +bool XMLPrinter::VisitEnter( const XMLDocument& doc )
  1.1778 +{
  1.1779 +	processEntities = doc.ProcessEntities();
  1.1780 +	if ( doc.HasBOM() ) {
  1.1781 +		PushHeader( true, false );
  1.1782 +	}
  1.1783 +	return true;
  1.1784 +}
  1.1785 +
  1.1786 +
  1.1787 +bool XMLPrinter::VisitEnter( const XMLElement& element, const XMLAttribute* attribute )
  1.1788 +{
  1.1789 +	OpenElement( element.Name() );
  1.1790 +	while ( attribute ) {
  1.1791 +		PushAttribute( attribute->Name(), attribute->Value() );
  1.1792 +		attribute = attribute->Next();
  1.1793 +	}
  1.1794 +	return true;
  1.1795 +}
  1.1796 +
  1.1797 +
  1.1798 +bool XMLPrinter::VisitExit( const XMLElement& )
  1.1799 +{
  1.1800 +	CloseElement();
  1.1801 +	return true;
  1.1802 +}
  1.1803 +
  1.1804 +
  1.1805 +bool XMLPrinter::Visit( const XMLText& text )
  1.1806 +{
  1.1807 +	PushText( text.Value(), text.CData() );
  1.1808 +	return true;
  1.1809 +}
  1.1810 +
  1.1811 +
  1.1812 +bool XMLPrinter::Visit( const XMLComment& comment )
  1.1813 +{
  1.1814 +	PushComment( comment.Value() );
  1.1815 +	return true;
  1.1816 +}
  1.1817 +
  1.1818 +bool XMLPrinter::Visit( const XMLDeclaration& declaration )
  1.1819 +{
  1.1820 +	PushDeclaration( declaration.Value() );
  1.1821 +	return true;
  1.1822 +}
  1.1823 +
  1.1824 +
  1.1825 +bool XMLPrinter::Visit( const XMLUnknown& unknown )
  1.1826 +{
  1.1827 +	PushUnknown( unknown.Value() );
  1.1828 +	return true;
  1.1829 +}