pulled out streamer class.

This commit is contained in:
Lee Thomason 2012-01-24 18:03:07 -08:00
parent 67d6131d74
commit 5cae897775
3 changed files with 230 additions and 40 deletions

View File

@ -250,10 +250,10 @@ XMLNode* XMLNode::InsertEndChild( XMLNode* addThis )
} }
void XMLNode::Print( FILE* fp, int depth ) void XMLNode::Print( XMLStreamer* streamer )
{ {
for( XMLNode* node = firstChild; node; node=node->next ) { for( XMLNode* node = firstChild; node; node=node->next ) {
node->Print( fp, depth ); node->Print( streamer );
} }
} }
@ -276,14 +276,14 @@ char* XMLNode::ParseDeep( char* p )
return 0; return 0;
} }
/*
void XMLNode::PrintSpace( FILE* fp, int depth ) void XMLNode::PrintSpace( FILE* fp, int depth )
{ {
for( int i=0; i<depth; ++i ) { for( int i=0; i<depth; ++i ) {
fprintf( fp, " " ); fprintf( fp, " " );
} }
} }
*/
// --------- XMLText ---------- // // --------- XMLText ---------- //
char* XMLText::ParseDeep( char* p ) char* XMLText::ParseDeep( char* p )
@ -297,10 +297,10 @@ char* XMLText::ParseDeep( char* p )
} }
void XMLText::Print( FILE* cfile, int depth ) void XMLText::Print( XMLStreamer* streamer )
{ {
const char* v = value.GetStr(); const char* v = value.GetStr();
fprintf( cfile, v ); streamer->PushText( v );
} }
@ -317,10 +317,11 @@ XMLComment::~XMLComment()
} }
void XMLComment::Print( FILE* fp, int depth ) void XMLComment::Print( XMLStreamer* streamer )
{ {
XMLNode::Print( fp, depth ); // XMLNode::Print( fp, depth );
fprintf( fp, "<!--%s-->\n", value.GetStr() ); // fprintf( fp, "<!--%s-->\n", value.GetStr() );
streamer->PushComment( value.GetStr() );
} }
@ -345,10 +346,11 @@ char* XMLAttribute::ParseDeep( char* p )
} }
void XMLAttribute::Print( FILE* cfile ) void XMLAttribute::Print( XMLStreamer* streamer )
{ {
// fixme: sort out single vs. double quote // fixme: sort out single vs. double quote
fprintf( cfile, "%s=\"%s\"", name.GetStr(), value.GetStr() ); //fprintf( cfile, "%s=\"%s\"", name.GetStr(), value.GetStr() );
streamer->PushAttribute( name.GetStr(), value.GetStr() );
} }
@ -460,19 +462,26 @@ char* XMLElement::ParseDeep( char* p )
} }
void XMLElement::Print( FILE* cfile, int depth ) void XMLElement::Print( XMLStreamer* streamer )
{ {
if ( !parent || !parent->IsTextParent() ) { //if ( !parent || !parent->IsTextParent() ) {
PrintSpace( cfile, depth ); // PrintSpace( cfile, depth );
} //}
fprintf( cfile, "<%s", Name() ); //fprintf( cfile, "<%s", Name() );
streamer->OpenElement( Name(), IsTextParent() );
for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) { for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
fprintf( cfile, " " ); //fprintf( cfile, " " );
attrib->Print( cfile ); attrib->Print( streamer );
} }
if ( firstChild ) { for( XMLNode* node=firstChild; node; node=node->next ) {
node->Print( streamer );
}
streamer->CloseElement();
/* if ( firstChild ) {
fprintf( cfile, ">", Name() ); fprintf( cfile, ">", Name() );
if ( !IsTextParent() ) { if ( !IsTextParent() ) {
fprintf( cfile, "\n" ); fprintf( cfile, "\n" );
@ -492,7 +501,7 @@ void XMLElement::Print( FILE* cfile, int depth )
if ( !IsTextParent() ) { if ( !IsTextParent() ) {
fprintf( cfile, "\n" ); fprintf( cfile, "\n" );
} }
} }*/
} }
@ -520,10 +529,13 @@ bool XMLDocument::Parse( const char* p )
} }
void XMLDocument::Print( FILE* fp, int depth ) void XMLDocument::Print( XMLStreamer* streamer )
{ {
XMLStreamer stdStreamer( stdout );
if ( !streamer )
streamer = &stdStreamer;
for( XMLNode* node = firstChild; node; node=node->next ) { for( XMLNode* node = firstChild; node; node=node->next ) {
node->Print( fp, depth ); node->Print( streamer );
} }
} }
@ -533,3 +545,133 @@ void XMLDocument::SetError( int error, const char* str1, const char* str2 )
printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 ); printf( "ERROR: id=%d '%s' '%s'\n", error, str1, str2 );
} }
StringStack::StringStack()
{
mem = new char[INIT];
*mem = 0;
inUse = 1; // always has a null
allocated = INIT;
nPositive = 0;
}
void StringStack::Push( const char* str ) {
int needed = strlen( str ) + 1;
if ( needed > 1 )
nPositive++;
if ( inUse+needed > allocated ) {
// fixme: power of 2
// less stupid allocation
int more = inUse+needed + 1000;
char* newMem = new char[more];
memcpy( newMem, mem, inUse );
delete [] mem;
mem = newMem;
}
strcpy( mem+inUse, str );
inUse += needed;
}
const char* StringStack::Pop() {
TIXMLASSERT( inUse > 1 );
const char* p = mem+inUse-2;
if ( *p ) {
nPositive--;
}
while( *p ) { // stack starts with a null, don't need to check for 'mem'
TIXMLASSERT( p > mem );
--p;
}
inUse = p-mem+1;
return p+1;
}
XMLStreamer::XMLStreamer( FILE* file ) : fp( file ), depth( 0 ), elementJustOpened( false )
{
}
void XMLStreamer::PrintSpace( int depth )
{
for( int i=0; i<depth; ++i ) {
fprintf( fp, " " );
}
}
void XMLStreamer::OpenElement( const char* name, bool textParent )
{
if ( elementJustOpened ) {
SealElement();
}
stack.Push( name );
text.Push( textParent ? "T" : "" );
PrintSpace( depth );
fprintf( fp, "<%s", name );
elementJustOpened = true;
++depth;
}
void XMLStreamer::PushAttribute( const char* name, const char* value )
{
TIXMLASSERT( elementJustOpened );
fprintf( fp, " %s=\"%s\"", name, value );
}
void XMLStreamer::CloseElement()
{
--depth;
const char* name = stack.Pop();
text.Pop();
if ( elementJustOpened ) {
fprintf( fp, "/>" );
if ( text.NumPositive() == 0 ) {
fprintf( fp, "\n" );
}
}
else {
PrintSpace( depth );
fprintf( fp, "</%s>", name );
if ( text.NumPositive() == 0 ) {
fprintf( fp, "\n" );
}
}
elementJustOpened = false;
}
void XMLStreamer::SealElement()
{
elementJustOpened = false;
fprintf( fp, ">" );
if ( text.NumPositive() == 0 ) {
fprintf( fp, "\n" );
}
}
void XMLStreamer::PushText( const char* text )
{
if ( elementJustOpened ) {
SealElement();
}
fprintf( fp, "%s", text );
}
void XMLStreamer::PushComment( const char* comment )
{
if ( elementJustOpened ) {
SealElement();
}
PrintSpace( depth );
fprintf( fp, "<!--%s-->\n", comment );
}

View File

@ -36,6 +36,8 @@ class XMLComment;
class XMLNode; class XMLNode;
class XMLText; class XMLText;
class XMLStreamer;
// internal - move to separate namespace // internal - move to separate namespace
struct CharBuffer struct CharBuffer
{ {
@ -106,6 +108,7 @@ protected:
char* Identify( XMLDocument* document, char* p, XMLNode** node ); char* Identify( XMLDocument* document, char* p, XMLNode** node );
}; };
class XMLNode : public XMLBase class XMLNode : public XMLBase
{ {
friend class XMLDocument; friend class XMLDocument;
@ -114,7 +117,7 @@ public:
virtual ~XMLNode(); virtual ~XMLNode();
XMLNode* InsertEndChild( XMLNode* addThis ); XMLNode* InsertEndChild( XMLNode* addThis );
virtual void Print( FILE* cfile, int depth ); virtual void Print( XMLStreamer* streamer );
virtual XMLElement* ToElement() { return 0; } virtual XMLElement* ToElement() { return 0; }
virtual XMLText* ToText() { return 0; } virtual XMLText* ToText() { return 0; }
@ -142,8 +145,6 @@ protected:
XMLNode* next; XMLNode* next;
private: private:
void PrintSpace( FILE* cfile, int depth ); // prints leading spaces.
}; };
@ -153,7 +154,7 @@ public:
XMLText( XMLDocument* doc ) : XMLNode( doc ) {} XMLText( XMLDocument* doc ) : XMLNode( doc ) {}
virtual ~XMLText() {} virtual ~XMLText() {}
virtual void Print( FILE* cfile, int depth ); virtual void Print( XMLStreamer* streamer );
const char* Value() { return value.GetStr(); } const char* Value() { return value.GetStr(); }
virtual XMLText* ToText() { return this; } virtual XMLText* ToText() { return this; }
@ -172,7 +173,7 @@ public:
XMLComment( XMLDocument* doc ); XMLComment( XMLDocument* doc );
virtual ~XMLComment(); virtual ~XMLComment();
virtual void Print( FILE* cfile, int depth ); virtual void Print( XMLStreamer* );
virtual XMLComment* ToComment() { return this; } virtual XMLComment* ToComment() { return this; }
const char* Value() { return value.GetStr(); } const char* Value() { return value.GetStr(); }
@ -192,7 +193,7 @@ class XMLAttribute : public XMLBase
public: public:
XMLAttribute( XMLElement* element ) : next( 0 ) {} XMLAttribute( XMLElement* element ) : next( 0 ) {}
virtual ~XMLAttribute() {} virtual ~XMLAttribute() {}
virtual void Print( FILE* cfile ); virtual void Print( XMLStreamer* streamer );
private: private:
char* ParseDeep( char* p ); char* ParseDeep( char* p );
@ -210,7 +211,7 @@ public:
virtual ~XMLElement(); virtual ~XMLElement();
const char* Name() { return name.GetStr(); } const char* Name() { return name.GetStr(); }
virtual void Print( FILE* cfile, int depth ); virtual void Print( XMLStreamer* );
virtual XMLElement* ToElement() { return this; } virtual XMLElement* ToElement() { return this; }
virtual bool IsClosingElement() const { return closing; } virtual bool IsClosingElement() const { return closing; }
@ -236,7 +237,7 @@ public:
~XMLDocument(); ~XMLDocument();
bool Parse( const char* ); bool Parse( const char* );
void Print( FILE* cfile=stdout, int depth=0 ); void Print( XMLStreamer* streamer=0 );
/* /*
XMLNode* Root() { return root; } XMLNode* Root() { return root; }
@ -255,6 +256,54 @@ private:
}; };
class StringStack
{
public:
StringStack();
~StringStack() { delete[] mem; }
void Push( const char* str );
const char* Pop();
int NumPositive() const { return nPositive; }
private:
enum {
INIT=10 // fixme, super small for testing
};
char* mem;
int inUse; // includes null
int allocated; // bytes allocated
int nPositive; // number of strings with len > 0
};
class XMLStreamer
{
public:
XMLStreamer( FILE* file );
~XMLStreamer() {}
void OpenElement( const char* name, bool textParent );
void PushAttribute( const char* name, const char* value );
void CloseElement();
void PushText( const char* text );
void PushComment( const char* comment );
private:
void SealElement();
void PrintSpace( int depth );
FILE* fp;
int depth;
bool elementJustOpened;
StringStack stack;
StringStack text;
};
}; // tinyxml2 }; // tinyxml2

View File

@ -28,25 +28,24 @@ int main( int argc, const char* argv )
} }
#endif #endif
{ {
static const char* test[] = { //"<!--single element-->", static const char* test[] = { //"<element />",
"<element />", //"<element></element>",
"<element></element>", //"<element><subelement/></element>",
//"<!--single sub-element-->", //"<element><subelement></subelement></element>",
"<element><subelement/></element>", "<element><subelement><subsub/></subelement></element>",
"<element><subelement></subelement></element>",
"<!--comment beside elements--><element><subelement></subelement></element>", "<!--comment beside elements--><element><subelement></subelement></element>",
"<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>", //"<!--comment beside elements, this time with spaces--> \n <element> <subelement> \n </subelement> </element>",
"<element attrib1='foo' attrib2=\"bar\" ></element>", "<element attrib1='foo' attrib2=\"bar\" ></element>",
"<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>", "<element attrib1='foo' attrib2=\"bar\" ><subelement attrib3='yeehaa' /></element>",
"<element>Text inside element.</element>", //"<element>Text inside element.</element>",
"<element><b></b></element>", //"<element><b></b></element>",
"<element>Text inside and <b>bolded</b> in the element.</element>", "<element>Text inside and <b>bolded</b> in the element.</element>",
0 0
}; };
for( int i=0; test[i]; ++i ) { for( int i=0; test[i]; ++i ) {
XMLDocument doc; XMLDocument doc;
doc.Parse( test[i] ); doc.Parse( test[i] );
doc.Print( stdout ); doc.Print();
printf( "----------------------------------------------\n" ); printf( "----------------------------------------------\n" );
} }
} }