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 <ctype.h>
#include <new.h>
#include <stdarg.h>
//#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 )
{
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 )
{
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 )
{
const char* start = p;
@ -947,13 +967,45 @@ XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpen
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 @@ void XMLStreamer::PrintString( const char* p )
// 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 @@ void XMLStreamer::PrintString( const char* p )
// 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 @@ void XMLStreamer::OpenElement( const char* name )
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::OpenElement( const char* name )
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 @@ void XMLStreamer::CloseElement()
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::CloseElement()
void XMLStreamer::SealElement()
{
elementJustOpened = false;
fprintf( fp, ">" );
Print( ">" );
}
@ -1057,10 +1110,10 @@ void XMLStreamer::PushText( const char* text, bool cdata )
SealElement();
}
if ( cdata )
fprintf( fp, "<![CDATA[" );
Print( "<![CDATA[" );
PrintString( text );
if ( cdata )
fprintf( fp, "]]>" );
Print( "]]>" );
}
@ -1070,10 +1123,10 @@ void XMLStreamer::PushComment( const char* comment )
SealElement();
}
if ( textDepth < 0 && depth > 0) {
fprintf( fp, "\n" );
Print( "\n" );
PrintSpace( depth );
}
fprintf( fp, "<!--%s-->", comment );
Print( "<!--%s-->", comment );
}

View File

@ -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 XMLUnknown;
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 @@ 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>
class DynArray
{
@ -170,12 +184,13 @@ public:
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 @@ private:
};
/*
Parent virtual class a a pool for fast allocation
and deallocation of objects.
*/
class MemPool
{
public:
@ -209,6 +228,9 @@ public:
};
/*
Template child class to create pools of the correct type.
*/
template< int SIZE >
class MemPoolT : public MemPool
{
@ -321,13 +343,16 @@ public:
};
/*
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 @@ public:
*/
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 @@ public:
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 @@ public:
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 @@ public:
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 @@ private:
class XMLStreamer : public XMLVisitor
{
public:
XMLStreamer( FILE* file );
XMLStreamer( FILE* file=0 );
~XMLStreamer() {}
void OpenElement( const char* name );
@ -724,11 +769,13 @@ public:
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 @@ private:
bool entityFlag[ENTITY_RANGE];
DynArray< const char*, 10 > stack;
DynArray< char, 20 > buffer, accumulator;
};
@ -748,4 +796,4 @@ private:
#endif // TINYXML2_INCLUDED
#endif // TINYXML2_INCLUDED

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", "& 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;
}