Prechádzať zdrojové kódy

pulled out streamer class.

Lee Thomason 14 rokov pred
rodič
commit
5cae897775
3 zmenil súbory, kde vykonal 230 pridanie a 40 odobranie
  1. 164 22
      tinyxml2.cpp
  2. 57 8
      tinyxml2.h
  3. 9 10
      xmltest.cpp

+ 164 - 22
tinyxml2.cpp

@@ -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 ) {
-		node->Print( fp, depth );
+		node->Print( streamer );
 	}
 }
 
@@ -276,14 +276,14 @@ char* XMLNode::ParseDeep( char* p )
 	return 0;
 }
 
-
+/*
 void XMLNode::PrintSpace( FILE* fp, int depth ) 
 {
 	for( int i=0; i<depth; ++i ) {
 		fprintf( fp, "    " );
 	}
 }
-
+*/
 
 // --------- XMLText ---------- //
 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();
-	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 );
-	fprintf( fp, "<!--%s-->\n", value.GetStr() );
+//	XMLNode::Print( fp, depth );
+//	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
-	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() ) {
-		PrintSpace( cfile, depth );
-	}
-	fprintf( cfile, "<%s", Name() );
+	//if ( !parent || !parent->IsTextParent() ) {
+	//	PrintSpace( cfile, depth );
+	//}
+	//fprintf( cfile, "<%s", Name() );
+	streamer->OpenElement( Name(), IsTextParent() );
 
 	for( XMLAttribute* attrib=rootAttribute; attrib; attrib=attrib->next ) {
-		fprintf( cfile, " " );
-		attrib->Print( cfile );
+		//fprintf( cfile, " " );
+		attrib->Print( streamer );
+
 	}
 
-	if ( firstChild ) {
+	for( XMLNode* node=firstChild; node; node=node->next ) {
+		node->Print( streamer );
+	}
+	streamer->CloseElement();
+
+/*	if ( firstChild ) {
 		fprintf( cfile, ">", Name() );
 		if ( !IsTextParent() ) {
 			fprintf( cfile, "\n" );
@@ -492,7 +501,7 @@ void XMLElement::Print( FILE* cfile, int depth )
 		if ( !IsTextParent() ) {
 			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 ) {
-		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 );
 }
 
+
+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 );
+}

+ 57 - 8
tinyxml2.h

@@ -36,6 +36,8 @@ class XMLComment;
 class XMLNode;
 class XMLText;
 
+class XMLStreamer;
+
 // internal - move to separate namespace
 struct CharBuffer
 {
@@ -106,6 +108,7 @@ protected:
 	char* Identify( XMLDocument* document, char* p, XMLNode** node );
 };
 
+
 class XMLNode : public XMLBase
 {
 	friend class XMLDocument;
@@ -114,7 +117,7 @@ public:
 	virtual ~XMLNode();
 
 	XMLNode* InsertEndChild( XMLNode* addThis );
-	virtual void Print( FILE* cfile, int depth );
+	virtual void Print( XMLStreamer* streamer );
 
 	virtual XMLElement* ToElement()		{ return 0; }
 	virtual XMLText*	ToText()		{ return 0; }
@@ -142,8 +145,6 @@ protected:
 	XMLNode*		next;
 
 private:
-	void PrintSpace( FILE* cfile, int depth );			// prints leading spaces.
-
 };
 
 
@@ -153,7 +154,7 @@ public:
 	XMLText( XMLDocument* doc )	: XMLNode( doc )	{}
 	virtual ~XMLText()								{}
 
-	virtual void Print( FILE* cfile, int depth );
+	virtual void Print( XMLStreamer* streamer );
 	const char* Value() { return value.GetStr(); }
 	virtual XMLText*	ToText()		{ return this; }
 
@@ -172,7 +173,7 @@ public:
 	XMLComment( XMLDocument* doc );
 	virtual ~XMLComment();
 
-	virtual void Print( FILE* cfile, int depth );
+	virtual void Print( XMLStreamer* );
 	virtual XMLComment*	ToComment()		{ return this; }
 
 	const char* Value() { return value.GetStr(); }
@@ -192,7 +193,7 @@ class XMLAttribute : public XMLBase
 public:
 	XMLAttribute( XMLElement* element ) : next( 0 ) {}
 	virtual ~XMLAttribute()	{}
-	virtual void Print( FILE* cfile );
+	virtual void Print( XMLStreamer* streamer );
 
 private:
 	char* ParseDeep( char* p );
@@ -210,7 +211,7 @@ public:
 	virtual ~XMLElement();
 
 	const char* Name() { return name.GetStr(); }
-	virtual void Print( FILE* cfile, int depth );
+	virtual void Print( XMLStreamer* );
 
 	virtual XMLElement* ToElement() { return this; }
 	virtual bool IsClosingElement() const { return closing; }
@@ -236,7 +237,7 @@ public:
 	~XMLDocument();
 
 	bool Parse( const char* );
-	void Print( FILE* cfile=stdout, int depth=0 );
+	void Print( XMLStreamer* streamer=0 );
 
 	/*
 	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
 
 

+ 9 - 10
xmltest.cpp

@@ -28,25 +28,24 @@ int main( int argc, const char* argv )
 	}
 #endif
 	{
-		static const char* test[] = {	//"<!--single element-->",
-										"<element />",
-									    "<element></element>",
-										//"<!--single sub-element-->",
-									    "<element><subelement/></element>",
-									    "<element><subelement></subelement></element>",
+		static const char* test[] = {	//"<element />",
+									    //"<element></element>",
+										//"<element><subelement/></element>",
+									    //"<element><subelement></subelement></element>",
+									    "<element><subelement><subsub/></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\" ><subelement attrib3='yeehaa' /></element>",
-										"<element>Text inside element.</element>",
-										"<element><b></b></element>",
+										//"<element>Text inside element.</element>",
+										//"<element><b></b></element>",
 										"<element>Text inside and <b>bolded</b> in the element.</element>",
 										0
 		};
 		for( int i=0; test[i]; ++i ) {
 			XMLDocument doc;
 			doc.Parse( test[i] );
-			doc.Print( stdout );
+			doc.Print();
 			printf( "----------------------------------------------\n" );
 		}
 	}