print to memory support
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 2287341..3a9b2c9 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -5,6 +5,7 @@
 #include <stdio.h>

 #include <ctype.h>

 #include <new.h>

+#include <stdarg.h>

 

 //#pragma warning ( disable : 4291 )

 

@@ -332,6 +333,13 @@
 }

 

 

+void XMLNode::DeleteChild( XMLNode* node )

+{

+	TIXMLASSERT( node->parent == this );

+	DELETE_NODE( node );

+}

+

+

 XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )

 {

 	if ( lastChild ) {

@@ -428,13 +436,6 @@
 }

 

 

-void XMLNode::DeleteChild( XMLNode* node )

-{

-	TIXMLASSERT( node->parent == this );

-	TIXMLASSERT( 0 );

-}

-

-

 char* XMLNode::ParseDeep( char* p )

 {

 	while( p && *p ) {

@@ -733,6 +734,25 @@
 }

 

 

+void XMLElement::DeleteAttribute( const char* name )

+{

+	XMLAttribute* prev = 0;

+	for( XMLAttribute* a=rootAttribute; a; a=a->next ) {

+		if ( XMLUtil::StringEqual( name, a->Name() ) ) {

+			if ( prev ) {

+				prev->next = a->next;

+			}

+			else {

+				rootAttribute = a->next;

+			}

+			DELETE_ATTRIBUTE( a );

+			break;

+		}

+		prev = a;

+	}

+}

+

+

 char* XMLElement::ParseAttributes( char* p, bool* closedElement )

 {

 	const char* start = p;

@@ -947,13 +967,45 @@
 			entityFlag[ entities[i].value ] = true;

 		}

 	}

+	buffer.Push( 0 );

+}

+

+

+void XMLStreamer::Print( const char* format, ... )

+{

+    va_list     va;

+    va_start( va, format );

+

+	if ( fp ) {

+		vfprintf( fp, format, va );

+	}

+	else {

+		// This seems brutally complex. Haven't figured out a better

+		// way on windows.

+		#ifdef _MSC_VER

+			int len = -1;

+			while ( len < 0 ) {

+				len = vsnprintf_s( accumulator.Mem(), accumulator.Capacity(), accumulator.Capacity()-1, format, va );

+				if ( len < 0 ) {

+					accumulator.PushArr( 1000 );

+				}

+			}

+			char* p = buffer.PushArr( len ) - 1;

+			memcpy( p, accumulator.Mem(), len+1 );

+		#else

+			int len = vsnprintf( 0, 0, format, va );

+			char* p = buffer.PushArr( len ) - 1;

+			vsprintf_s( p, len+1, format, va );

+		#endif

+	}

+    va_end( va );

 }

 

 

 void XMLStreamer::PrintSpace( int depth )

 {

 	for( int i=0; i<depth; ++i ) {

-		fprintf( fp, "    " );

+		Print( "    " );

 	}

 }

 

@@ -970,12 +1022,12 @@
 			// entity, and keep looking.

 			if ( entityFlag[*q] ) {

 				while ( p < q ) {

-					fputc( *p, fp );

+					Print( "%c", *p );

 					++p;

 				}

 				for( int i=0; i<NUM_ENTITIES; ++i ) {

 					if ( entities[i].value == *q ) {

-						fprintf( fp, "&%s;", entities[i].pattern );

+						Print( "&%s;", entities[i].pattern );

 						break;

 					}

 				}

@@ -987,10 +1039,11 @@
 	// Flush the remaining string. This will be the entire

 	// string if an entity wasn't found.

 	if ( q-p > 0 ) {

-		fprintf( fp, "%s", p );

+		Print( "%s", p );

 	}

 }

 

+

 void XMLStreamer::OpenElement( const char* name )

 {

 	if ( elementJustOpened ) {

@@ -999,11 +1052,11 @@
 	stack.Push( name );

 

 	if ( textDepth < 0 && depth > 0) {

-		fprintf( fp, "\n" );

+		Print( "\n" );

 		PrintSpace( depth );

 	}

 

-	fprintf( fp, "<%s", name );

+	Print( "<%s", name );

 	elementJustOpened = true;

 	++depth;

 }

@@ -1012,9 +1065,9 @@
 void XMLStreamer::PushAttribute( const char* name, const char* value )

 {

 	TIXMLASSERT( elementJustOpened );

-	fprintf( fp, " %s=\"", name );

+	Print( " %s=\"", name );

 	PrintString( value );

-	fprintf( fp, "\"" );

+	Print( "\"" );

 }

 

 

@@ -1024,20 +1077,20 @@
 	const char* name = stack.Pop();

 

 	if ( elementJustOpened ) {

-		fprintf( fp, "/>" );

+		Print( "/>" );

 	}

 	else {

 		if ( textDepth < 0 ) {

-			fprintf( fp, "\n" );

+			Print( "\n" );

 			PrintSpace( depth );

 		}

-		fprintf( fp, "</%s>", name );

+		Print( "</%s>", name );

 	}

 

 	if ( textDepth == depth )

 		textDepth = -1;

 	if ( depth == 0 )

-		fprintf( fp, "\n" );

+		Print( "\n" );

 	elementJustOpened = false;

 }

 

@@ -1045,7 +1098,7 @@
 void XMLStreamer::SealElement()

 {

 	elementJustOpened = false;

-	fprintf( fp, ">" );

+	Print( ">" );

 }

 

 

@@ -1057,10 +1110,10 @@
 		SealElement();

 	}

 	if ( cdata )

-		fprintf( fp, "<![CDATA[" );

+		Print( "<![CDATA[" );

 	PrintString( text );

 	if ( cdata ) 

-		fprintf( fp, "]]>" );

+		Print( "]]>" );

 }

 

 

@@ -1070,10 +1123,10 @@
 		SealElement();

 	}

 	if ( textDepth < 0 && depth > 0) {

-		fprintf( fp, "\n" );

+		Print( "\n" );

 		PrintSpace( depth );

 	}

-	fprintf( fp, "<!--%s-->", comment );

+	Print( "<!--%s-->", comment );

 }

 

 

diff --git a/tinyxml2.h b/tinyxml2.h
index 0d5a591..2e46ba1 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -13,13 +13,16 @@
 	X hide copy constructor

 	X hide = operator

 	X UTF8 support: isAlpha, etc.

-	- string buffer for sets. (Grr.)

+	X string buffer for sets. (Grr.)

 	- MS BOM

 	- print to memory buffer

 	- tests from xml1

 	- xml1 tests especially UTF-8

 	- perf test: xml1

 	- perf test: xenowar

+	- test: load(char*)

+	- test: load(FILE*)

+

 */

 

 #include <limits.h>

@@ -64,7 +67,7 @@
 	#define TIXML_SNPRINTF _snprintf

 	#define TIXML_SSCANF   sscanf

 #elif defined(__GNUC__) && (__GNUC__ >= 3 )

-	// GCC version 3 and higher.s

+	// GCC version 3 and higher

 	//#warning( "Using sn* functions." )

 	#define TIXML_SNPRINTF snprintf

 	#define TIXML_SSCANF   sscanf

@@ -87,6 +90,12 @@
 

 class XMLStreamer;

 

+/*

+	A class that wraps strings. Normally stores the start and end

+	pointers into the XML file itself, and will apply normalization

+	and entity transalion if actually read. Can also store (and memory

+	manage) a traditional char[]

+*/

 class StrPair

 {

 public:

@@ -132,6 +141,11 @@
 };

 

 

+/*

+	A dynamic array of Plain Old Data. Doesn't support constructors, etc.

+	Has a small initial memory pool, so that low or no usage will not

+	cause a call to new/delete

+*/

 template <class T, int INIT>

 class DynArray

 {

@@ -170,12 +184,13 @@
 		size -= count;

 	}

 

-	bool Empty() const { return size == 0; }

-	T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }

-	const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }

-	int Size() const { return size; }

-	const T* Mem() const { return mem; }

-	T* Mem() { return mem; }

+	bool Empty() const					{ return size == 0; }

+	T& operator[](int i)				{ TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }

+	const T& operator[](int i) const	{ TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }

+	int Size() const					{ return size; }

+	int Capacity() const				{ return allocated; }

+	const T* Mem() const				{ return mem; }

+	T* Mem()							{ return mem; }

 

 

 private:

@@ -197,6 +212,10 @@
 };

 

 

+/*

+	Parent virtual class a a pool for fast allocation

+	and deallocation of objects.

+*/

 class MemPool

 {

 public:

@@ -209,6 +228,9 @@
 };

 

 

+/*

+	Template child class to create pools of the correct type.

+*/

 template< int SIZE >

 class MemPoolT : public MemPool

 {

@@ -321,13 +343,16 @@
 };

 

 

+/*

+	Utility functionality.

+*/

 class XMLUtil

 {

 public:

 	// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't 

 	// correct, but simple, and usually works.

-	static const char* SkipWhiteSpace( const char* p )	{ while( IsUTF8Continuation(*p) || isspace( *p ) ) { ++p; } return p; }

-	static char* SkipWhiteSpace( char* p )				{ while( IsUTF8Continuation(*p) || isspace( *p ) ) { ++p; } return p; }

+	static const char* SkipWhiteSpace( const char* p )	{ while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }

+	static char* SkipWhiteSpace( char* p )				{ while( !IsUTF8Continuation(*p) && isspace( *p ) ) { ++p; } return p; }

 

 	inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX )  {

 		int n = 0;

@@ -418,11 +443,17 @@
 	*/

 	XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );

 	

+	/**

+		Tests: All (used by destructor)

+	*/

 	void ClearChildren();

+

+	/**

+		Tests: Progammatic DOM

+	*/

 	void DeleteChild( XMLNode* node );

 

 	virtual bool Accept( XMLVisitor* visitor ) const = 0;

-	//virtual void Print( XMLStreamer* streamer );

 

 	virtual char* ParseDeep( char* );

 	virtual bool IsClosingElement() const { return false; }

@@ -549,6 +580,12 @@
 	const char* Value() const { return value.GetStr(); }

 	const XMLAttribute* Next() const { return next; }

 

+	int		 IntAttribute( const char* name ) const		{ int i=0;		QueryIntAttribute( &i );		return i; }

+	unsigned UnsignedAttribute( const char* name ) const{ unsigned i=0; QueryUnsignedAttribute( &i );	return i; }

+	bool	 BoolAttribute( const char* name ) const	{ bool b=false; QueryBoolAttribute( &b );		return b; }

+	double 	 DoubleAttribute( const char* name ) const	{ double d=0;	QueryDoubleAttribute( &d );		return d; }

+	float	 FloatAttribute( const char* name ) const	{ float f=0;	QueryFloatAttribute( &f );		return f; }

+

 	int QueryIntAttribute( int* value ) const;

 	int QueryUnsignedAttribute( unsigned int* value ) const;

 	int QueryBoolAttribute( bool* value ) const;

@@ -612,7 +649,10 @@
 	void SetAttribute( const char* name, bool value )			{ XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }

 	void SetAttribute( const char* name, double value )			{ XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }

 

-	void RemoveAttribute( const char* name );

+	/**

+		Tests: Programmatic DOM

+	*/

+	void DeleteAttribute( const char* name );

 

 	const XMLAttribute* FirstAttribute() const { return rootAttribute; }

 	const XMLAttribute* FindAttribute( const char* name ) const;

@@ -657,18 +697,23 @@
 	virtual bool Accept( XMLVisitor* visitor ) const;

 

 	/**

-		Testing: Programmatic DOM

+		Tests: Programmatic DOM

 	*/

 	XMLElement* NewElement( const char* name );

 	/**

-		Testing: Programmatic DOM

+		Tests: Programmatic DOM

 	*/

 	XMLComment* NewComment( const char* comment );

 	/**

-		Testing: Programmatic DOM

+		Tests: Programmatic DOM

 	*/

 	XMLText* NewText( const char* text );

 

+	/**

+		Tests: Programmatic DOM

+	*/

+	void DeleteNode( XMLNode* node )	{ node->parent->DeleteChild( node ); }

+

 	enum {

 		NO_ERROR = 0,

 		ERROR_ELEMENT_MISMATCH,

@@ -705,7 +750,7 @@
 class XMLStreamer : public XMLVisitor

 {

 public:

-	XMLStreamer( FILE* file );

+	XMLStreamer( FILE* file=0 );

 	~XMLStreamer()	{}

 

 	void OpenElement( const char* name );

@@ -724,11 +769,13 @@
 	virtual bool Visit( const XMLText& text );

 	virtual bool Visit( const XMLComment& comment );

 

+	const char* CStr() const { return buffer.Mem(); }

 

 private:

 	void SealElement();

 	void PrintSpace( int depth );

 	void PrintString( const char* );	// prints out, after detecting entities.

+	void Print( const char* format, ... );

 

 	FILE* fp;

 	int depth;

@@ -741,6 +788,7 @@
 	bool entityFlag[ENTITY_RANGE];

 

 	DynArray< const char*, 10 > stack;

+	DynArray< char, 20 > buffer, accumulator;

 };

 

 

@@ -748,4 +796,4 @@
 

 

 

-#endif // TINYXML2_INCLUDED
\ No newline at end of file
+#endif // TINYXML2_INCLUDED

diff --git a/xmltest.cpp b/xmltest.cpp
index a7194e0..f5cb241 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -147,6 +147,26 @@
 		XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );

 		XMLTest( "Programmatic DOM", "& Text!", 

 				 doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() );

+

+		// And now deletion:

+		element->DeleteChild( sub[2] );

+		doc->DeleteNode( comment );

+

+		element->FirstChildElement()->SetAttribute( "attrib", true );

+		element->LastChildElement()->DeleteAttribute( "attrib" );

+

+		XMLTest( "Programmatic DOM", true, doc->FirstChildElement()->FirstChildElement()->BoolAttribute( "attrib" ) );

+		int value = 10;

+		int result = doc->FirstChildElement()->LastChildElement()->QueryIntAttribute( "attrib", &value );

+		XMLTest( "Programmatic DOM", result, NO_ATTRIBUTE );

+		XMLTest( "Programmatic DOM", value, 10 );

+

+		doc->Print();

+

+		XMLStreamer streamer;

+		doc->Print( &streamer );

+		printf( "%s", streamer.CStr() );

+

 		delete doc;

 	}