print to memory support

This commit is contained in:
U-Stream\Lee 2012-02-17 17:48:16 -08:00
parent 09a11c5964
commit ae25a44d94
3 changed files with 162 additions and 41 deletions

View File

@ -5,6 +5,7 @@
#include <stdio.h> #include <stdio.h>
#include <ctype.h> #include <ctype.h>
#include <new.h> #include <new.h>
#include <stdarg.h>
//#pragma warning ( disable : 4291 ) //#pragma warning ( disable : 4291 )
@ -332,6 +333,13 @@ void XMLNode::Unlink( XMLNode* child )
} }
void XMLNode::DeleteChild( XMLNode* node )
{
TIXMLASSERT( node->parent == this );
DELETE_NODE( node );
}
XMLNode* XMLNode::InsertEndChild( XMLNode* addThis ) XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
{ {
if ( lastChild ) { if ( lastChild ) {
@ -428,13 +436,6 @@ const XMLElement* XMLNode::LastChildElement( const char* value ) const
} }
void XMLNode::DeleteChild( XMLNode* node )
{
TIXMLASSERT( node->parent == this );
TIXMLASSERT( 0 );
}
char* XMLNode::ParseDeep( char* p ) char* XMLNode::ParseDeep( char* p )
{ {
while( p && *p ) { while( p && *p ) {
@ -733,6 +734,25 @@ void XMLElement::LinkAttribute( XMLAttribute* attrib )
} }
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 ) char* XMLElement::ParseAttributes( char* p, bool* closedElement )
{ {
const char* start = p; const char* start = p;
@ -947,13 +967,45 @@ XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpen
entityFlag[ entities[i].value ] = true; 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 ) void XMLStreamer::PrintSpace( int depth )
{ {
for( int i=0; i<depth; ++i ) { for( int i=0; i<depth; ++i ) {
fprintf( fp, " " ); Print( " " );
} }
} }
@ -970,12 +1022,12 @@ void XMLStreamer::PrintString( const char* p )
// entity, and keep looking. // entity, and keep looking.
if ( entityFlag[*q] ) { if ( entityFlag[*q] ) {
while ( p < q ) { while ( p < q ) {
fputc( *p, fp ); Print( "%c", *p );
++p; ++p;
} }
for( int i=0; i<NUM_ENTITIES; ++i ) { for( int i=0; i<NUM_ENTITIES; ++i ) {
if ( entities[i].value == *q ) { if ( entities[i].value == *q ) {
fprintf( fp, "&%s;", entities[i].pattern ); Print( "&%s;", entities[i].pattern );
break; break;
} }
} }
@ -987,10 +1039,11 @@ void XMLStreamer::PrintString( const char* p )
// Flush the remaining string. This will be the entire // Flush the remaining string. This will be the entire
// string if an entity wasn't found. // string if an entity wasn't found.
if ( q-p > 0 ) { if ( q-p > 0 ) {
fprintf( fp, "%s", p ); Print( "%s", p );
} }
} }
void XMLStreamer::OpenElement( const char* name ) void XMLStreamer::OpenElement( const char* name )
{ {
if ( elementJustOpened ) { if ( elementJustOpened ) {
@ -999,11 +1052,11 @@ void XMLStreamer::OpenElement( const char* name )
stack.Push( name ); stack.Push( name );
if ( textDepth < 0 && depth > 0) { if ( textDepth < 0 && depth > 0) {
fprintf( fp, "\n" ); Print( "\n" );
PrintSpace( depth ); PrintSpace( depth );
} }
fprintf( fp, "<%s", name ); Print( "<%s", name );
elementJustOpened = true; elementJustOpened = true;
++depth; ++depth;
} }
@ -1012,9 +1065,9 @@ void XMLStreamer::OpenElement( const char* name )
void XMLStreamer::PushAttribute( const char* name, const char* value ) void XMLStreamer::PushAttribute( const char* name, const char* value )
{ {
TIXMLASSERT( elementJustOpened ); TIXMLASSERT( elementJustOpened );
fprintf( fp, " %s=\"", name ); Print( " %s=\"", name );
PrintString( value ); PrintString( value );
fprintf( fp, "\"" ); Print( "\"" );
} }
@ -1024,20 +1077,20 @@ void XMLStreamer::CloseElement()
const char* name = stack.Pop(); const char* name = stack.Pop();
if ( elementJustOpened ) { if ( elementJustOpened ) {
fprintf( fp, "/>" ); Print( "/>" );
} }
else { else {
if ( textDepth < 0 ) { if ( textDepth < 0 ) {
fprintf( fp, "\n" ); Print( "\n" );
PrintSpace( depth ); PrintSpace( depth );
} }
fprintf( fp, "</%s>", name ); Print( "</%s>", name );
} }
if ( textDepth == depth ) if ( textDepth == depth )
textDepth = -1; textDepth = -1;
if ( depth == 0 ) if ( depth == 0 )
fprintf( fp, "\n" ); Print( "\n" );
elementJustOpened = false; elementJustOpened = false;
} }
@ -1045,7 +1098,7 @@ void XMLStreamer::CloseElement()
void XMLStreamer::SealElement() void XMLStreamer::SealElement()
{ {
elementJustOpened = false; elementJustOpened = false;
fprintf( fp, ">" ); Print( ">" );
} }
@ -1057,10 +1110,10 @@ void XMLStreamer::PushText( const char* text, bool cdata )
SealElement(); SealElement();
} }
if ( cdata ) if ( cdata )
fprintf( fp, "<![CDATA[" ); Print( "<![CDATA[" );
PrintString( text ); PrintString( text );
if ( cdata ) if ( cdata )
fprintf( fp, "]]>" ); Print( "]]>" );
} }
@ -1070,10 +1123,10 @@ void XMLStreamer::PushComment( const char* comment )
SealElement(); SealElement();
} }
if ( textDepth < 0 && depth > 0) { if ( textDepth < 0 && depth > 0) {
fprintf( fp, "\n" ); Print( "\n" );
PrintSpace( depth ); PrintSpace( depth );
} }
fprintf( fp, "<!--%s-->", comment ); Print( "<!--%s-->", comment );
} }

View File

@ -13,13 +13,16 @@
X hide copy constructor X hide copy constructor
X hide = operator X hide = operator
X UTF8 support: isAlpha, etc. X UTF8 support: isAlpha, etc.
- string buffer for sets. (Grr.) X string buffer for sets. (Grr.)
- MS BOM - MS BOM
- print to memory buffer - print to memory buffer
- tests from xml1 - tests from xml1
- xml1 tests especially UTF-8 - xml1 tests especially UTF-8
- perf test: xml1 - perf test: xml1
- perf test: xenowar - perf test: xenowar
- test: load(char*)
- test: load(FILE*)
*/ */
#include <limits.h> #include <limits.h>
@ -64,7 +67,7 @@
#define TIXML_SNPRINTF _snprintf #define TIXML_SNPRINTF _snprintf
#define TIXML_SSCANF sscanf #define TIXML_SSCANF sscanf
#elif defined(__GNUC__) && (__GNUC__ >= 3 ) #elif defined(__GNUC__) && (__GNUC__ >= 3 )
// GCC version 3 and higher.s // GCC version 3 and higher
//#warning( "Using sn* functions." ) //#warning( "Using sn* functions." )
#define TIXML_SNPRINTF snprintf #define TIXML_SNPRINTF snprintf
#define TIXML_SSCANF sscanf #define TIXML_SSCANF sscanf
@ -87,6 +90,12 @@ class XMLUnknown;
class XMLStreamer; 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 class StrPair
{ {
public: public:
@ -132,6 +141,11 @@ private:
}; };
/*
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> template <class T, int INIT>
class DynArray class DynArray
{ {
@ -174,6 +188,7 @@ public:
T& operator[](int i) { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; } 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]; } const T& operator[](int i) const { TIXMLASSERT( i>= 0 && i < size ); return mem[i]; }
int Size() const { return size; } int Size() const { return size; }
int Capacity() const { return allocated; }
const T* Mem() const { return mem; } const T* Mem() const { return mem; }
T* Mem() { return mem; } T* Mem() { return mem; }
@ -197,6 +212,10 @@ private:
}; };
/*
Parent virtual class a a pool for fast allocation
and deallocation of objects.
*/
class MemPool class MemPool
{ {
public: public:
@ -209,6 +228,9 @@ public:
}; };
/*
Template child class to create pools of the correct type.
*/
template< int SIZE > template< int SIZE >
class MemPoolT : public MemPool class MemPoolT : public MemPool
{ {
@ -321,13 +343,16 @@ public:
}; };
/*
Utility functionality.
*/
class XMLUtil class XMLUtil
{ {
public: public:
// Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't // Anything in the high order range of UTF-8 is assumed to not be whitespace. This isn't
// correct, but simple, and usually works. // correct, but simple, and usually works.
static const char* SkipWhiteSpace( const 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; } 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 ) { inline static bool StringEqual( const char* p, const char* q, int nChar=INT_MAX ) {
int n = 0; int n = 0;
@ -418,11 +443,17 @@ public:
*/ */
XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis ); XMLNode* InsertAfterChild( XMLNode* afterThis, XMLNode* addThis );
/**
Tests: All (used by destructor)
*/
void ClearChildren(); void ClearChildren();
/**
Tests: Progammatic DOM
*/
void DeleteChild( XMLNode* node ); void DeleteChild( XMLNode* node );
virtual bool Accept( XMLVisitor* visitor ) const = 0; virtual bool Accept( XMLVisitor* visitor ) const = 0;
//virtual void Print( XMLStreamer* streamer );
virtual char* ParseDeep( char* ); virtual char* ParseDeep( char* );
virtual bool IsClosingElement() const { return false; } virtual bool IsClosingElement() const { return false; }
@ -549,6 +580,12 @@ public:
const char* Value() const { return value.GetStr(); } const char* Value() const { return value.GetStr(); }
const XMLAttribute* Next() const { return next; } 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 QueryIntAttribute( int* value ) const;
int QueryUnsignedAttribute( unsigned int* value ) const; int QueryUnsignedAttribute( unsigned int* value ) const;
int QueryBoolAttribute( bool* value ) const; int QueryBoolAttribute( bool* value ) const;
@ -612,7 +649,10 @@ public:
void SetAttribute( const char* name, bool value ) { XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); } 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 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* FirstAttribute() const { return rootAttribute; }
const XMLAttribute* FindAttribute( const char* name ) const; const XMLAttribute* FindAttribute( const char* name ) const;
@ -657,18 +697,23 @@ public:
virtual bool Accept( XMLVisitor* visitor ) const; virtual bool Accept( XMLVisitor* visitor ) const;
/** /**
Testing: Programmatic DOM Tests: Programmatic DOM
*/ */
XMLElement* NewElement( const char* name ); XMLElement* NewElement( const char* name );
/** /**
Testing: Programmatic DOM Tests: Programmatic DOM
*/ */
XMLComment* NewComment( const char* comment ); XMLComment* NewComment( const char* comment );
/** /**
Testing: Programmatic DOM Tests: Programmatic DOM
*/ */
XMLText* NewText( const char* text ); XMLText* NewText( const char* text );
/**
Tests: Programmatic DOM
*/
void DeleteNode( XMLNode* node ) { node->parent->DeleteChild( node ); }
enum { enum {
NO_ERROR = 0, NO_ERROR = 0,
ERROR_ELEMENT_MISMATCH, ERROR_ELEMENT_MISMATCH,
@ -705,7 +750,7 @@ private:
class XMLStreamer : public XMLVisitor class XMLStreamer : public XMLVisitor
{ {
public: public:
XMLStreamer( FILE* file ); XMLStreamer( FILE* file=0 );
~XMLStreamer() {} ~XMLStreamer() {}
void OpenElement( const char* name ); void OpenElement( const char* name );
@ -724,11 +769,13 @@ public:
virtual bool Visit( const XMLText& text ); virtual bool Visit( const XMLText& text );
virtual bool Visit( const XMLComment& comment ); virtual bool Visit( const XMLComment& comment );
const char* CStr() const { return buffer.Mem(); }
private: private:
void SealElement(); void SealElement();
void PrintSpace( int depth ); void PrintSpace( int depth );
void PrintString( const char* ); // prints out, after detecting entities. void PrintString( const char* ); // prints out, after detecting entities.
void Print( const char* format, ... );
FILE* fp; FILE* fp;
int depth; int depth;
@ -741,6 +788,7 @@ private:
bool entityFlag[ENTITY_RANGE]; bool entityFlag[ENTITY_RANGE];
DynArray< const char*, 10 > stack; DynArray< const char*, 10 > stack;
DynArray< char, 20 > buffer, accumulator;
}; };

View File

@ -147,6 +147,26 @@ int main( int argc, const char* argv )
XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) ); XMLTest( "Programmatic DOM", 2, doc->FirstChildElement()->LastChildElement( "sub" )->IntAttribute( "attrib" ) );
XMLTest( "Programmatic DOM", "& Text!", XMLTest( "Programmatic DOM", "& Text!",
doc->FirstChildElement()->LastChildElement( "sub" )->FirstChild()->ToText()->Value() ); 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; delete doc;
} }