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;
}