Blame ACM/tinyxml/tinyxmlparser.cpp

Packit 47f805
/*
Packit 47f805
Copyright (c) 2000-2002 Lee Thomason (www.grinninglizard.com)
Packit 47f805
Packit 47f805
This software is provided 'as-is', without any express or implied 
Packit 47f805
warranty. In no event will the authors be held liable for any 
Packit 47f805
damages arising from the use of this software.
Packit 47f805
Packit 47f805
Permission is granted to anyone to use this software for any 
Packit 47f805
purpose, including commercial applications, and to alter it and 
Packit 47f805
redistribute it freely, subject to the following restrictions:
Packit 47f805
Packit 47f805
1. The origin of this software must not be misrepresented; you must 
Packit 47f805
not claim that you wrote the original software. If you use this
Packit 47f805
software in a product, an acknowledgment in the product documentation 
Packit 47f805
would be appreciated but is not required.
Packit 47f805
Packit 47f805
2. Altered source versions must be plainly marked as such, and 
Packit 47f805
must not be misrepresented as being the original software.
Packit 47f805
Packit 47f805
3. This notice may not be removed or altered from any source 
Packit 47f805
distribution.
Packit 47f805
*/
Packit 47f805
Packit 47f805
#include "tinyxml.h"
Packit 47f805
#include <ctype.h>
Packit 47f805
#include <strstream>
Packit 47f805
using namespace std;
Packit 47f805
Packit 47f805
//#define DEBUG_PARSER
Packit 47f805
Packit 47f805
TiXmlBase::Entity TiXmlBase::entity[ NUM_ENTITY ] = 
Packit 47f805
{
Packit 47f805
	{ "&",  5, '&' },
Packit 47f805
	{ "<",   4, '<' },
Packit 47f805
	{ ">",   4, '>' },
Packit 47f805
	{ """, 6, '\"' },
Packit 47f805
	{ "'", 6, '\'' }
Packit 47f805
};
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlBase::SkipWhiteSpace( const char* p )
Packit 47f805
{
Packit 47f805
	if ( !p || !*p )
Packit 47f805
	{
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
	while ( p && *p )
Packit 47f805
	{
Packit 47f805
		if ( isspace( *p ) || *p == '\n' || *p =='\r' )		// Still using old rules for white space.
Packit 47f805
			++p;
Packit 47f805
		else
Packit 47f805
			break;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
/*static*/ bool TiXmlBase::StreamWhiteSpace( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	for( ;; )
Packit 47f805
	{
Packit 47f805
		if ( !in->good() ) return false;
Packit 47f805
Packit 47f805
		int c = in->peek();
Packit 47f805
		if ( !IsWhiteSpace( c ) )
Packit 47f805
			return true;
Packit 47f805
		*tag += in->get();
Packit 47f805
	}
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
/*static*/ bool TiXmlBase::StreamTo( std::istream* in, int character, std::string* tag )
Packit 47f805
{
Packit 47f805
	while ( in->good() )
Packit 47f805
	{
Packit 47f805
		int c = in->peek();
Packit 47f805
		if ( c == character )
Packit 47f805
			return true;
Packit 47f805
Packit 47f805
		in->get();
Packit 47f805
		*tag += c;
Packit 47f805
	}
Packit 47f805
	return false;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlBase::ReadName( const char* p, string* name )
Packit 47f805
{
Packit 47f805
	*name = "";
Packit 47f805
	assert( p );
Packit 47f805
Packit 47f805
	// Names start with letters or underscores.
Packit 47f805
	// After that, they can be letters, underscores, numbers,
Packit 47f805
	// hyphens, or colons. (Colons are valid ony for namespaces,
Packit 47f805
	// but tinyxml can't tell namespaces from names.)
Packit 47f805
	if (    p && *p 
Packit 47f805
		 && ( isalpha( (unsigned char) *p ) || *p == '_' ) )
Packit 47f805
	{
Packit 47f805
		while(		p && *p
Packit 47f805
				&&	(		isalnum( (unsigned char ) *p ) 
Packit 47f805
						 || *p == '_'
Packit 47f805
						 || *p == '-'
Packit 47f805
						 || *p == ':' ) )
Packit 47f805
		{
Packit 47f805
			(*name) += *p;
Packit 47f805
			++p;
Packit 47f805
		}
Packit 47f805
		return p;
Packit 47f805
	}
Packit 47f805
	return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlBase::GetEntity( const char* p, char* value )
Packit 47f805
{
Packit 47f805
	// Presume an entity, and pull it out.
Packit 47f805
	string ent;
Packit 47f805
	int i;
Packit 47f805
Packit 47f805
	// Ignore the &#x entities.
Packit 47f805
	if ( strncmp( "&#x", p, 3 ) == 0 )
Packit 47f805
	{
Packit 47f805
		*value = *p;
Packit 47f805
		return p+1;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	// Now try to match it.
Packit 47f805
	for( i=0; i
Packit 47f805
	{
Packit 47f805
		if ( strncmp( entity[i].str, p, entity[i].strLength ) == 0 )
Packit 47f805
		{
Packit 47f805
			assert( strlen( entity[i].str ) == entity[i].strLength );
Packit 47f805
			*value = entity[i].chr;
Packit 47f805
			return ( p + entity[i].strLength );
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
Packit 47f805
	// So it wasn't an entity, its unrecognized, or something like that.
Packit 47f805
	*value = *p;	// Don't put back the last one, since we return it!
Packit 47f805
	return p+1;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
bool TiXmlBase::StringEqual( const char* p,
Packit 47f805
							 const char* tag,
Packit 47f805
							 bool ignoreCase )
Packit 47f805
{
Packit 47f805
	assert( p );
Packit 47f805
	if ( !p || !*p )
Packit 47f805
	{
Packit 47f805
		assert( 0 );
Packit 47f805
		return false;
Packit 47f805
	}
Packit 47f805
Packit 47f805
    if ( tolower( *p ) == tolower( *tag ) )
Packit 47f805
	{
Packit 47f805
		const char* q = p;
Packit 47f805
Packit 47f805
		if (ignoreCase)
Packit 47f805
		{
Packit 47f805
			while ( *q && *tag && *q == *tag )
Packit 47f805
			{
Packit 47f805
				++q;
Packit 47f805
				++tag;
Packit 47f805
			}
Packit 47f805
Packit 47f805
			if ( *tag == 0 )		// Have we found the end of the tag, and everything equal?
Packit 47f805
			{
Packit 47f805
				return true;
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
		else
Packit 47f805
		{
Packit 47f805
			while ( *q && *tag && tolower( *q ) == tolower( *tag ) )
Packit 47f805
			{
Packit 47f805
				++q;
Packit 47f805
				++tag;
Packit 47f805
			}
Packit 47f805
Packit 47f805
			if ( *tag == 0 )
Packit 47f805
			{
Packit 47f805
				return true;
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	return false;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlBase::ReadText(	const char* p, 
Packit 47f805
									string* text, 
Packit 47f805
									bool trimWhiteSpace, 
Packit 47f805
									const char* endTag, 
Packit 47f805
									bool caseInsensitive )
Packit 47f805
{
Packit 47f805
	*text = "";
Packit 47f805
Packit 47f805
	if (    !trimWhiteSpace			// certain tags always keep whitespace
Packit 47f805
		 || !condenseWhiteSpace )	// if true, whitespace is always kept
Packit 47f805
	{
Packit 47f805
		// Keep all the white space.
Packit 47f805
		while (	   p && *p
Packit 47f805
				&& !StringEqual( p, endTag, caseInsensitive )
Packit 47f805
			  )
Packit 47f805
		{
Packit 47f805
			char c;
Packit 47f805
			p = GetChar( p, &c );
Packit 47f805
			text->append( &c, 1 );
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	else
Packit 47f805
	{
Packit 47f805
		bool whitespace = false;
Packit 47f805
Packit 47f805
		// Remove leading white space:
Packit 47f805
		p = SkipWhiteSpace( p );
Packit 47f805
		while (	   p && *p
Packit 47f805
				&& !StringEqual( p, endTag, caseInsensitive ) )
Packit 47f805
		{
Packit 47f805
			if ( *p == '\r' || *p == '\n' )
Packit 47f805
			{
Packit 47f805
				whitespace = true;
Packit 47f805
				++p;
Packit 47f805
			}
Packit 47f805
			else if ( isspace( *p ) )
Packit 47f805
			{
Packit 47f805
				whitespace = true;
Packit 47f805
				++p;
Packit 47f805
			}
Packit 47f805
			else
Packit 47f805
			{
Packit 47f805
				// If we've found whitespace, add it before the
Packit 47f805
				// new character. Any whitespace just becomes a space.
Packit 47f805
				if ( whitespace )
Packit 47f805
				{
Packit 47f805
					text->append( " ", 1 );
Packit 47f805
					whitespace = false;
Packit 47f805
				}
Packit 47f805
				char c;
Packit 47f805
				p = GetChar( p, &c );
Packit 47f805
				text->append( &c, 1 );
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	return p + strlen( endTag );
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void TiXmlDocument::StreamIn( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	// The basic issue with a document is that we don't know what we're
Packit 47f805
	// streaming. Read something presumed to be a tag (and hope), then
Packit 47f805
	// identify it, and call the appropriate stream method on the tag.
Packit 47f805
	//
Packit 47f805
	// This "pre-streaming" will never read the closing ">" so the
Packit 47f805
	// sub-tag can orient itself.
Packit 47f805
Packit 47f805
	if ( !StreamTo( in, '<', tag ) ) 
Packit 47f805
	{
Packit 47f805
		SetError( TIXML_ERROR_PARSING_EMPTY );
Packit 47f805
		return;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	while ( in->good() )
Packit 47f805
	{
Packit 47f805
		int tagIndex = tag->length();
Packit 47f805
		while ( in->good() && in->peek() != '>' )
Packit 47f805
		{
Packit 47f805
			int c = in->get();
Packit 47f805
			(*tag) += (char) c;
Packit 47f805
		}
Packit 47f805
Packit 47f805
		if ( in->good() )
Packit 47f805
		{
Packit 47f805
			// We now have something we presume to be a node of 
Packit 47f805
			// some sort. Identify it, and call the node to
Packit 47f805
			// continue streaming.
Packit 47f805
			TiXmlNode* node = Identify( tag->c_str() + tagIndex );
Packit 47f805
Packit 47f805
			if ( node )
Packit 47f805
			{
Packit 47f805
				node->StreamIn( in, tag );
Packit 47f805
				bool isElement = node->ToElement() != 0;
Packit 47f805
				delete node;
Packit 47f805
				node = 0;
Packit 47f805
Packit 47f805
				// If this is the root element, we're done. Parsing will be
Packit 47f805
				// done by the >> operator.
Packit 47f805
				if ( isElement )
Packit 47f805
				{
Packit 47f805
					return;
Packit 47f805
				}
Packit 47f805
			}
Packit 47f805
			else
Packit 47f805
			{
Packit 47f805
				SetError( TIXML_ERROR );
Packit 47f805
				return;
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	// We should have returned sooner. 
Packit 47f805
	SetError( TIXML_ERROR );
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlDocument::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	// Parse away, at the document level. Since a document
Packit 47f805
	// contains nothing but other tags, most of what happens
Packit 47f805
	// here is skipping white space.
Packit 47f805
	//
Packit 47f805
	// In this variant (as opposed to stream and Parse) we
Packit 47f805
	// read everything we can.
Packit 47f805
Packit 47f805
Packit 47f805
	if ( !p || !*p  || !( p = SkipWhiteSpace( p ) ) )
Packit 47f805
	{
Packit 47f805
		SetError( TIXML_ERROR_DOCUMENT_EMPTY );
Packit 47f805
		return false;
Packit 47f805
	}
Packit 47f805
	
Packit 47f805
	while ( p && *p )
Packit 47f805
	{
Packit 47f805
		TiXmlNode* node = Identify( p );
Packit 47f805
		if ( node )
Packit 47f805
		{				
Packit 47f805
			p = node->Parse( p );
Packit 47f805
			LinkEndChild( node );
Packit 47f805
		}		
Packit 47f805
		else
Packit 47f805
		{
Packit 47f805
			break;
Packit 47f805
		}		
Packit 47f805
		p = SkipWhiteSpace( p );
Packit 47f805
	}
Packit 47f805
	// All is well.
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
TiXmlNode* TiXmlNode::Identify( const char* p )
Packit 47f805
{
Packit 47f805
	TiXmlNode* returnNode = 0;
Packit 47f805
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	if( !p || !*p || *p != '<' )
Packit 47f805
	{
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	TiXmlDocument* doc = GetDocument();
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
Packit 47f805
	if ( !p || !*p )
Packit 47f805
	{
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	// What is this thing? 
Packit 47f805
	// - Elements start with a letter or underscore, but xml is reserved.
Packit 47f805
	// - Comments: 
Packit 47f805
	// - Decleration: 
Packit 47f805
	// - Everthing else is unknown to tinyxml.
Packit 47f805
	//
Packit 47f805
Packit 47f805
	const char* xmlHeader = { "
Packit 47f805
	const char* commentHeader = { "
Packit 47f805
Packit 47f805
	if ( StringEqual( p, xmlHeader, true ) )
Packit 47f805
	{
Packit 47f805
		#ifdef DEBUG_PARSER
Packit 47f805
			TIXML_LOG( "XML parsing Declaration\n" );
Packit 47f805
		#endif
Packit 47f805
		returnNode = new TiXmlDeclaration();
Packit 47f805
	}
Packit 47f805
	else if (    isalpha( *(p+1) )
Packit 47f805
			  || *(p+1) == '_' )
Packit 47f805
	{
Packit 47f805
		#ifdef DEBUG_PARSER
Packit 47f805
			TIXML_LOG( "XML parsing Element\n" );
Packit 47f805
		#endif
Packit 47f805
		returnNode = new TiXmlElement( "" );
Packit 47f805
	}
Packit 47f805
	else if ( StringEqual( p, commentHeader, false ) )
Packit 47f805
	{
Packit 47f805
		#ifdef DEBUG_PARSER
Packit 47f805
			TIXML_LOG( "XML parsing Comment\n" );
Packit 47f805
		#endif
Packit 47f805
		returnNode = new TiXmlComment();
Packit 47f805
	}
Packit 47f805
	else
Packit 47f805
	{
Packit 47f805
		#ifdef DEBUG_PARSER
Packit 47f805
			TIXML_LOG( "XML parsing Unknown\n" );
Packit 47f805
		#endif
Packit 47f805
		returnNode = new TiXmlUnknown();
Packit 47f805
	}
Packit 47f805
Packit 47f805
	if ( returnNode )
Packit 47f805
	{
Packit 47f805
		// Set the parent, so it can report errors
Packit 47f805
		returnNode->parent = this;
Packit 47f805
		//p = returnNode->Parse( p );
Packit 47f805
	}
Packit 47f805
	else
Packit 47f805
	{
Packit 47f805
		if ( doc )
Packit 47f805
			doc->SetError( TIXML_ERROR_OUT_OF_MEMORY );
Packit 47f805
	}
Packit 47f805
	return returnNode;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void TiXmlElement::StreamIn( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	// We're called with some amount of pre-parsing. That is, some of "this"
Packit 47f805
	// element is in "tag". Go ahead and stream to the closing ">"
Packit 47f805
	while( in->good() )
Packit 47f805
	{
Packit 47f805
		int c = in->get();
Packit 47f805
		(*tag) += (char) c ;
Packit 47f805
		
Packit 47f805
		if ( c == '>' )
Packit 47f805
			break;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	if ( tag->length() < 3 ) return;
Packit 47f805
Packit 47f805
	// Okay...if we are a "/>" tag, then we're done. We've read a complete tag.
Packit 47f805
	// If not, identify and stream.
Packit 47f805
Packit 47f805
	if (    tag->at( tag->length() - 1 ) == '>' 
Packit 47f805
		 && tag->at( tag->length() - 2 ) == '/' )
Packit 47f805
	{
Packit 47f805
		// All good!
Packit 47f805
		return;
Packit 47f805
	}
Packit 47f805
	else if ( tag->at( tag->length() - 1 ) == '>' )
Packit 47f805
	{
Packit 47f805
		// There is more. Could be:
Packit 47f805
		//		text
Packit 47f805
		//		closing tag
Packit 47f805
		//		another node.
Packit 47f805
		for ( ;; )
Packit 47f805
		{
Packit 47f805
			StreamWhiteSpace( in, tag );
Packit 47f805
Packit 47f805
			// Do we have text?
Packit 47f805
			if ( in->peek() != '<' )
Packit 47f805
			{
Packit 47f805
				// Yep, text.
Packit 47f805
				TiXmlText text( "" );
Packit 47f805
				text.StreamIn( in, tag );
Packit 47f805
Packit 47f805
				// What follows text is a closing tag or another node.
Packit 47f805
				// Go around again and figure it out.
Packit 47f805
				continue;
Packit 47f805
			}
Packit 47f805
Packit 47f805
			// We now have either a closing tag...or another node.
Packit 47f805
			// We should be at a "<", regardless.
Packit 47f805
			if ( !in->good() ) return;
Packit 47f805
			assert( in->peek() == '<' );
Packit 47f805
			int tagIndex = tag->length();
Packit 47f805
Packit 47f805
			bool closingTag = false;
Packit 47f805
			bool firstCharFound = false;
Packit 47f805
Packit 47f805
			for( ;; )
Packit 47f805
			{
Packit 47f805
				if ( !in->good() )
Packit 47f805
					return;
Packit 47f805
Packit 47f805
				int c = in->peek();
Packit 47f805
				
Packit 47f805
				if ( c == '>' )
Packit 47f805
					break;
Packit 47f805
Packit 47f805
				*tag += c;
Packit 47f805
				in->get();
Packit 47f805
Packit 47f805
				if ( !firstCharFound && c != '<' && !IsWhiteSpace( c ) )
Packit 47f805
				{
Packit 47f805
					firstCharFound = true;
Packit 47f805
					if ( c == '/' )
Packit 47f805
						closingTag = true;
Packit 47f805
				}
Packit 47f805
			}
Packit 47f805
			// If it was a closing tag, then read in the closing '>' to clean up the input stream.
Packit 47f805
			// If it was not, the streaming will be done by the tag.
Packit 47f805
			if ( closingTag )
Packit 47f805
			{
Packit 47f805
				int c = in->get();
Packit 47f805
				assert( c == '>' );
Packit 47f805
				*tag += c;
Packit 47f805
Packit 47f805
				// We are done, once we've found our closing tag.
Packit 47f805
				return;
Packit 47f805
			}
Packit 47f805
			else
Packit 47f805
			{
Packit 47f805
				// If not a closing tag, id it, and stream.
Packit 47f805
				const char* tagloc = tag->c_str() + tagIndex;
Packit 47f805
				TiXmlNode* node = Identify( tagloc );
Packit 47f805
				if ( !node )
Packit 47f805
					return;
Packit 47f805
				node->StreamIn( in, tag );
Packit 47f805
				delete node;
Packit 47f805
				node = 0;
Packit 47f805
Packit 47f805
				// No return: go around from the beginning: text, closing tag, or node.
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlElement::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	TiXmlDocument* document = GetDocument();
Packit 47f805
Packit 47f805
	if ( !p || !*p || *p != '<' )
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
Packit 47f805
		return false;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	p = SkipWhiteSpace( p+1 );
Packit 47f805
Packit 47f805
	// Read the name.
Packit 47f805
	p = ReadName( p, &value );
Packit 47f805
	if ( !p || !*p )
Packit 47f805
	{
Packit 47f805
		if ( document )	document->SetError( TIXML_ERROR_FAILED_TO_READ_ELEMENT_NAME );
Packit 47f805
		return false;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	string endTag = "</";
Packit 47f805
	endTag += value;
Packit 47f805
	endTag += ">";
Packit 47f805
Packit 47f805
	// Check for and read attributes. Also look for an empty
Packit 47f805
	// tag or an end tag.
Packit 47f805
	while ( p && *p )
Packit 47f805
	{
Packit 47f805
		p = SkipWhiteSpace( p );
Packit 47f805
		if ( !p || !*p )
Packit 47f805
		{
Packit 47f805
			if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
Packit 47f805
			return 0;
Packit 47f805
		}
Packit 47f805
		if ( *p == '/' )
Packit 47f805
		{
Packit 47f805
			++p;
Packit 47f805
			// Empty tag.
Packit 47f805
			if ( *p  != '>' )
Packit 47f805
			{
Packit 47f805
				if ( document ) document->SetError( TIXML_ERROR_PARSING_EMPTY );		
Packit 47f805
				return 0;
Packit 47f805
			}
Packit 47f805
			return (p+1);
Packit 47f805
		}
Packit 47f805
		else if ( *p == '>' )
Packit 47f805
		{
Packit 47f805
			// Done with attributes (if there were any.)
Packit 47f805
			// Read the value -- which can include other
Packit 47f805
			// elements -- read the end tag, and return.
Packit 47f805
			++p;
Packit 47f805
			p = ReadValue( p );		// Note this is an Element method, and will set the error if one happens.
Packit 47f805
			if ( !p || !*p )
Packit 47f805
				return 0;
Packit 47f805
Packit 47f805
			// We should find the end tag now
Packit 47f805
			if ( StringEqual( p, endTag.c_str(), false ) )
Packit 47f805
			{
Packit 47f805
				p += endTag.length();
Packit 47f805
				return p;
Packit 47f805
			}
Packit 47f805
			else
Packit 47f805
			{
Packit 47f805
				if ( document ) document->SetError( TIXML_ERROR_READING_END_TAG );
Packit 47f805
				return 0;
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
		else
Packit 47f805
		{
Packit 47f805
			// Try to read an element:
Packit 47f805
			TiXmlAttribute attrib;
Packit 47f805
			attrib.SetDocument( document );
Packit 47f805
			p = attrib.Parse( p );
Packit 47f805
Packit 47f805
			if ( !p || !*p )
Packit 47f805
			{
Packit 47f805
				if ( document ) document->SetError( TIXML_ERROR_PARSING_ELEMENT );
Packit 47f805
				return 0;
Packit 47f805
			}
Packit 47f805
			SetAttribute( attrib.Name(), attrib.Value() );
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlElement::ReadValue( const char* p )
Packit 47f805
{
Packit 47f805
	TiXmlDocument* document = GetDocument();
Packit 47f805
Packit 47f805
	// Read in text and elements in any order.
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	while ( p && *p )
Packit 47f805
	{
Packit 47f805
//		string text;
Packit 47f805
//		while ( p && *p && *p != '<' )
Packit 47f805
//		{
Packit 47f805
//			text += (*p);
Packit 47f805
//			++p;
Packit 47f805
//		}
Packit 47f805
//
Packit 47f805
//		p = SkipWhiteSpace( p );
Packit 47f805
Packit 47f805
		if ( *p != '<' )
Packit 47f805
		{
Packit 47f805
			// Take what we have, make a text element.
Packit 47f805
			TiXmlText* textNode = new TiXmlText( "" );
Packit 47f805
Packit 47f805
			if ( !textNode )
Packit 47f805
			{
Packit 47f805
				if ( document ) document->SetError( TIXML_ERROR_OUT_OF_MEMORY );
Packit 47f805
				return 0;
Packit 47f805
			}
Packit 47f805
Packit 47f805
			p = textNode->Parse( p );
Packit 47f805
Packit 47f805
			if ( !textNode->Blank() )
Packit 47f805
				LinkEndChild( textNode );
Packit 47f805
			else
Packit 47f805
				delete textNode;
Packit 47f805
		} 
Packit 47f805
		else 
Packit 47f805
		{
Packit 47f805
			// We hit a '<'
Packit 47f805
			// Have we hit a new element or an end tag?
Packit 47f805
			if ( StringEqual( p, "</", false ) )
Packit 47f805
			{
Packit 47f805
				return p;
Packit 47f805
			}
Packit 47f805
			else
Packit 47f805
			{
Packit 47f805
				TiXmlNode* node = Identify( p );
Packit 47f805
				if ( node )
Packit 47f805
				{
Packit 47f805
					p = node->Parse( p );
Packit 47f805
					LinkEndChild( node );
Packit 47f805
				}				
Packit 47f805
				else
Packit 47f805
				{
Packit 47f805
					return 0;
Packit 47f805
				}
Packit 47f805
			}
Packit 47f805
		}
Packit 47f805
		p = SkipWhiteSpace( p );
Packit 47f805
	}
Packit 47f805
Packit 47f805
	if ( !p )
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_READING_ELEMENT_VALUE );
Packit 47f805
	}	
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void TiXmlUnknown::StreamIn( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	while ( in->good() )
Packit 47f805
	{
Packit 47f805
		int c = in->get();	
Packit 47f805
		(*tag) += c;
Packit 47f805
Packit 47f805
		if ( c == '>' )
Packit 47f805
		{
Packit 47f805
			// All is well.
Packit 47f805
			return;		
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlUnknown::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	TiXmlDocument* document = GetDocument();
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	if ( !p || !*p || *p != '<' )
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
	++p;
Packit 47f805
	value = "";
Packit 47f805
Packit 47f805
	while ( p && *p && *p != '>' )
Packit 47f805
	{
Packit 47f805
		value += *p;
Packit 47f805
		++p;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	if ( !p )
Packit 47f805
	{
Packit 47f805
		if ( document )	document->SetError( TIXML_ERROR_PARSING_UNKNOWN );
Packit 47f805
	}
Packit 47f805
	if ( *p == '>' )
Packit 47f805
		return p+1;
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void TiXmlComment::StreamIn( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	while ( in->good() )
Packit 47f805
	{
Packit 47f805
		int c = in->get();	
Packit 47f805
		(*tag) += c;
Packit 47f805
Packit 47f805
		if ( c == '>' 
Packit 47f805
			 && tag->at( tag->length() - 2 ) == '-'
Packit 47f805
			 && tag->at( tag->length() - 3 ) == '-' )
Packit 47f805
		{
Packit 47f805
			// All is well.
Packit 47f805
			return;		
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlComment::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	TiXmlDocument* document = GetDocument();
Packit 47f805
	value = "";
Packit 47f805
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	const char* startTag = "
Packit 47f805
	const char* endTag   = "-->";
Packit 47f805
Packit 47f805
	if ( !StringEqual( p, startTag, false ) )
Packit 47f805
	{
Packit 47f805
		document->SetError( TIXML_ERROR_PARSING_COMMENT );
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
	p += strlen( startTag );
Packit 47f805
	p = ReadText( p, &value, false, endTag, false );
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlAttribute::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	if ( !p || !*p ) return 0;
Packit 47f805
Packit 47f805
	// Read the name, the '=' and the value.
Packit 47f805
	p = ReadName( p, &name );
Packit 47f805
	if ( !p || !*p )
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	if ( !p || !*p || *p != '=' )
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	++p;	// skip '='
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	if ( !p || !*p )
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_READING_ATTRIBUTES );
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
	
Packit 47f805
	const char* end;
Packit 47f805
Packit 47f805
	if ( *p == '\'' )
Packit 47f805
	{
Packit 47f805
		++p;
Packit 47f805
		end = "\'";
Packit 47f805
		p = ReadText( p, &value, false, end, false );
Packit 47f805
	}
Packit 47f805
	else if ( *p == '"' )
Packit 47f805
	{
Packit 47f805
		++p;
Packit 47f805
		end = "\"";
Packit 47f805
		p = ReadText( p, &value, false, end, false );
Packit 47f805
	}
Packit 47f805
	else
Packit 47f805
	{
Packit 47f805
		// All attribute values should be in single or double quotes.
Packit 47f805
		// But this is such a common error that the parser will try
Packit 47f805
		// its best, even without them.
Packit 47f805
		value = "";
Packit 47f805
		while (    p && *p										// existence
Packit 47f805
				&& !isspace( *p ) && *p != '\n' && *p != '\r'	// whitespace
Packit 47f805
				&& *p != '/' && *p != '>' )						// tag end
Packit 47f805
		{
Packit 47f805
			value += *p;
Packit 47f805
			++p;
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	return p;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void TiXmlText::StreamIn( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	while ( in->good() )
Packit 47f805
	{
Packit 47f805
		int c = in->peek();	
Packit 47f805
		if ( c == '<' )
Packit 47f805
			return;
Packit 47f805
Packit 47f805
		(*tag) += c;
Packit 47f805
		in->get();
Packit 47f805
	}
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
Packit 47f805
const char* TiXmlText::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	value = "";
Packit 47f805
Packit 47f805
	//TiXmlDocument* doc = GetDocument();
Packit 47f805
	bool ignoreWhite = true;
Packit 47f805
//	if ( doc && !doc->IgnoreWhiteSpace() ) ignoreWhite = false;
Packit 47f805
Packit 47f805
	const char* end = "<";
Packit 47f805
	p = ReadText( p, &value, ignoreWhite, end, false );
Packit 47f805
	if ( p )
Packit 47f805
		return p-1;	// don't truncate the '<'
Packit 47f805
	return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
Packit 47f805
void TiXmlDeclaration::StreamIn( std::istream* in, std::string* tag )
Packit 47f805
{
Packit 47f805
	while ( in->good() )
Packit 47f805
	{
Packit 47f805
		int c = in->get();
Packit 47f805
		(*tag) += c;
Packit 47f805
Packit 47f805
		if ( c == '>' )
Packit 47f805
		{
Packit 47f805
			// All is well.
Packit 47f805
			return;
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
}
Packit 47f805
Packit 47f805
const char* TiXmlDeclaration::Parse( const char* p )
Packit 47f805
{
Packit 47f805
	p = SkipWhiteSpace( p );
Packit 47f805
	// Find the beginning, find the end, and look for
Packit 47f805
	// the stuff in-between.
Packit 47f805
	TiXmlDocument* document = GetDocument();
Packit 47f805
	if ( !p || !*p || !StringEqual( p, "
Packit 47f805
	{
Packit 47f805
		if ( document ) document->SetError( TIXML_ERROR_PARSING_DECLARATION );
Packit 47f805
		return 0;
Packit 47f805
	}
Packit 47f805
Packit 47f805
	p += 5;
Packit 47f805
//	const char* start = p+5;
Packit 47f805
//	const char* end  = strstr( start, "?>" );
Packit 47f805
Packit 47f805
	version = "";
Packit 47f805
	encoding = "";
Packit 47f805
	standalone = "";
Packit 47f805
Packit 47f805
	while ( p && *p )
Packit 47f805
	{
Packit 47f805
		if ( *p == '>' )
Packit 47f805
		{
Packit 47f805
			++p;
Packit 47f805
			return p;
Packit 47f805
		}
Packit 47f805
Packit 47f805
		p = SkipWhiteSpace( p );
Packit 47f805
		if ( StringEqual( p, "version", true ) )
Packit 47f805
		{
Packit 47f805
//			p += 7;
Packit 47f805
			TiXmlAttribute attrib;
Packit 47f805
			p = attrib.Parse( p );		
Packit 47f805
			version = attrib.Value();
Packit 47f805
		}
Packit 47f805
		else if ( StringEqual( p, "encoding", true ) )
Packit 47f805
		{
Packit 47f805
//			p += 8;
Packit 47f805
			TiXmlAttribute attrib;
Packit 47f805
			p = attrib.Parse( p );		
Packit 47f805
			encoding = attrib.Value();
Packit 47f805
		}
Packit 47f805
		else if ( StringEqual( p, "standalone", true ) )
Packit 47f805
		{
Packit 47f805
//			p += 10;
Packit 47f805
			TiXmlAttribute attrib;
Packit 47f805
			p = attrib.Parse( p );		
Packit 47f805
			standalone = attrib.Value();
Packit 47f805
		}
Packit 47f805
		else
Packit 47f805
		{
Packit 47f805
			// Read over whatever it is.
Packit 47f805
			while( p && *p && *p != '>' && !isspace( *p ) )
Packit 47f805
				++p;
Packit 47f805
		}
Packit 47f805
	}
Packit 47f805
	return 0;
Packit 47f805
}
Packit 47f805
Packit 47f805
bool TiXmlText::Blank() const
Packit 47f805
{
Packit 47f805
	for ( unsigned i=0; i
Packit 47f805
		if ( !isspace( value[i] ) )
Packit 47f805
			return false;
Packit 47f805
	return true;
Packit 47f805
}
Packit 47f805