Просмотр исходного кода

Patching up incorrect boilerplate code. Added clone/equal methods.

Lee Thomason 14 лет назад
Родитель
Сommit
7d00b9ab95
3 измененных файлов с 306 добавлено и 30 удалено
  1. 198 8
      tinyxml2.cpp
  2. 74 22
      tinyxml2.h
  3. 34 0
      xmltest.cpp

+ 198 - 8
tinyxml2.cpp

@@ -402,12 +402,15 @@ char* XMLDocument::Identify( char* p, XMLNode** node )
 	static const int cdataHeaderLen		= 9;
 	static const int elementHeaderLen	= 1;
 
+#if defined(_MSC_VER)
 #pragma warning ( push )
 #pragma warning ( disable : 4127 )
+#endif
 	TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLUnknown ) );		// use same memory pool
 	TIXMLASSERT( sizeof( XMLComment ) == sizeof( XMLDeclaration ) );	// use same memory pool
+#if defined(_MSC_VER)
 #pragma warning (pop)
-
+#endif
 	if ( XMLUtil::StringEqual( p, xmlHeader, xmlHeaderLen ) ) {
 		returnNode = new (commentPool.Alloc()) XMLDeclaration( this );
 		returnNode->memPool = &commentPool;
@@ -622,6 +625,32 @@ const XMLElement* XMLNode::LastChildElement( const char* value ) const
 }
 
 
+const XMLElement* XMLNode::NextSiblingElement( const char* value ) const
+{
+	for( XMLNode* element=this->next; element; element = element->next ) {
+		if (    element->ToElement() 
+			 && (!value || XMLUtil::StringEqual( value, element->Value() ))) 
+		{
+			return element->ToElement();
+		}
+	}
+	return 0;
+}
+
+
+const XMLElement* XMLNode::PreviousSiblingElement( const char* value ) const
+{
+	for( XMLNode* element=this->prev; element; element = element->prev ) {
+		if (    element->ToElement()
+			 && (!value || XMLUtil::StringEqual( value, element->Value() ))) 
+		{
+			return element->ToElement();
+		}
+	}
+	return 0;
+}
+
+
 char* XMLNode::ParseDeep( char* p, StrPair* parentEnd )
 {
 	// This is a recursive method, but thinking about it "at the current level"
@@ -723,6 +752,23 @@ char* XMLText::ParseDeep( char* p, StrPair* )
 }
 
 
+XMLNode* XMLText::ShallowClone( XMLDocument* doc ) const
+{
+	if ( !doc ) {
+		doc = document;
+	}
+	XMLText* text = doc->NewText( Value() );	// fixme: this will always allocate memory. Intern?
+	text->SetCData( this->CData() );
+	return text;
+}
+
+
+bool XMLText::ShallowEqual( const XMLNode* compare ) const
+{
+	return ( compare->ToText() && XMLUtil::StringEqual( compare->ToText()->Value(), Value() ));
+}
+
+
 bool XMLText::Accept( XMLVisitor* visitor ) const
 {
 	return visitor->Visit( *this );
@@ -754,6 +800,22 @@ char* XMLComment::ParseDeep( char* p, StrPair* )
 }
 
 
+XMLNode* XMLComment::ShallowClone( XMLDocument* doc ) const
+{
+	if ( !doc ) {
+		doc = document;
+	}
+	XMLComment* comment = doc->NewComment( Value() );	// fixme: this will always allocate memory. Intern?
+	return comment;
+}
+
+
+bool XMLComment::ShallowEqual( const XMLNode* compare ) const
+{
+	return ( compare->ToComment() && XMLUtil::StringEqual( compare->ToComment()->Value(), Value() ));
+}
+
+
 bool XMLComment::Accept( XMLVisitor* visitor ) const
 {
 	return visitor->Visit( *this );
@@ -785,6 +847,23 @@ char* XMLDeclaration::ParseDeep( char* p, StrPair* )
 }
 
 
+XMLNode* XMLDeclaration::ShallowClone( XMLDocument* doc ) const
+{
+	if ( !doc ) {
+		doc = document;
+	}
+	XMLDeclaration* dec = doc->NewDeclaration( Value() );	// fixme: this will always allocate memory. Intern?
+	return dec;
+}
+
+
+bool XMLDeclaration::ShallowEqual( const XMLNode* compare ) const
+{
+	return ( compare->ToDeclaration() && XMLUtil::StringEqual( compare->ToDeclaration()->Value(), Value() ));
+}
+
+
+
 bool XMLDeclaration::Accept( XMLVisitor* visitor ) const
 {
 	return visitor->Visit( *this );
@@ -815,6 +894,22 @@ char* XMLUnknown::ParseDeep( char* p, StrPair* )
 }
 
 
+XMLNode* XMLUnknown::ShallowClone( XMLDocument* doc ) const
+{
+	if ( !doc ) {
+		doc = document;
+	}
+	XMLUnknown* text = doc->NewUnknown( Value() );	// fixme: this will always allocate memory. Intern?
+	return text;
+}
+
+
+bool XMLUnknown::ShallowEqual( const XMLNode* compare ) const
+{
+	return ( compare->ToUnknown() && XMLUtil::StringEqual( compare->ToUnknown()->Value(), Value() ));
+}
+
+
 bool XMLUnknown::Accept( XMLVisitor* visitor ) const
 {
 	return visitor->Visit( *this );
@@ -840,7 +935,7 @@ void XMLAttribute::SetName( const char* n )
 }
 
 
-int XMLAttribute::QueryIntAttribute( int* value ) const
+int XMLAttribute::QueryIntValue( int* value ) const
 {
 	if ( TIXML_SSCANF( Value(), "%d", value ) == 1 )
 		return XML_NO_ERROR;
@@ -848,7 +943,7 @@ int XMLAttribute::QueryIntAttribute( int* value ) const
 }
 
 
-int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
+int XMLAttribute::QueryUnsignedValue( unsigned int* value ) const
 {
 	if ( TIXML_SSCANF( Value(), "%u", value ) == 1 )
 		return XML_NO_ERROR;
@@ -856,10 +951,10 @@ int XMLAttribute::QueryUnsignedAttribute( unsigned int* value ) const
 }
 
 
-int XMLAttribute::QueryBoolAttribute( bool* value ) const
+int XMLAttribute::QueryBoolValue( bool* value ) const
 {
 	int ival = -1;
-	QueryIntAttribute( &ival );
+	QueryIntValue( &ival );
 
 	if ( ival > 0 || XMLUtil::StringEqual( Value(), "true" ) ) {
 		*value = true;
@@ -873,7 +968,7 @@ int XMLAttribute::QueryBoolAttribute( bool* value ) const
 }
 
 
-int XMLAttribute::QueryDoubleAttribute( double* value ) const
+int XMLAttribute::QueryDoubleValue( double* value ) const
 {
 	if ( TIXML_SSCANF( Value(), "%lf", value ) == 1 )
 		return XML_NO_ERROR;
@@ -881,7 +976,7 @@ int XMLAttribute::QueryDoubleAttribute( double* value ) const
 }
 
 
-int XMLAttribute::QueryFloatAttribute( float* value ) const
+int XMLAttribute::QueryFloatValue( float* value ) const
 {
 	if ( TIXML_SSCANF( Value(), "%f", value ) == 1 )
 		return XML_NO_ERROR;
@@ -1103,6 +1198,43 @@ char* XMLElement::ParseDeep( char* p, StrPair* strPair )
 }
 
 
+
+XMLNode* XMLElement::ShallowClone( XMLDocument* doc ) const
+{
+	if ( !doc ) {
+		doc = document;
+	}
+	XMLElement* element = doc->NewElement( Value() );					// fixme: this will always allocate memory. Intern?
+	for( const XMLAttribute* a=FirstAttribute(); a; a=a->Next() ) {
+		element->SetAttribute( a->Name(), a->Value() );					// fixme: this will always allocate memory. Intern?
+	}
+	return element;
+}
+
+
+bool XMLElement::ShallowEqual( const XMLNode* compare ) const
+{
+	const XMLElement* other = compare->ToElement();
+	if ( other && XMLUtil::StringEqual( other->Value(), Value() )) {
+
+		const XMLAttribute* a=FirstAttribute();
+		const XMLAttribute* b=other->FirstAttribute();
+
+		while ( a && b ) {
+			if ( !XMLUtil::StringEqual( a->Value(), b->Value() ) ) {
+				return false;
+			}
+		}	
+		if ( a || b ) {
+			// different count
+			return false;
+		}
+		return true;
+	}
+	return false;
+}
+
+
 bool XMLElement::Accept( XMLVisitor* visitor ) const
 {
 	if ( visitor->VisitEnter( *this, rootAttribute ) ) 
@@ -1114,9 +1246,9 @@ bool XMLElement::Accept( XMLVisitor* visitor ) const
 		}
 	}
 	return visitor->VisitExit( *this );
-
 }
 
+
 // --------- XMLDocument ----------- //
 XMLDocument::XMLDocument() :
 	XMLNode( 0 ),
@@ -1185,15 +1317,37 @@ XMLText* XMLDocument::NewText( const char* str )
 }
 
 
+XMLDeclaration* XMLDocument::NewDeclaration( const char* str )
+{
+	XMLDeclaration* dec = new (commentPool.Alloc()) XMLDeclaration( this );
+	dec->memPool = &commentPool;
+	dec->SetValue( str );
+	return dec;
+}
+
+
+XMLUnknown* XMLDocument::NewUnknown( const char* str )
+{
+	XMLUnknown* unk = new (commentPool.Alloc()) XMLUnknown( this );
+	unk->memPool = &commentPool;
+	unk->SetValue( str );
+	return unk;
+}
+
+
 int XMLDocument::LoadFile( const char* filename )
 {
 	DeleteChildren();
 	InitDocument();
 
+#if defined(_MSC_VER)
 #pragma warning ( push )
 #pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
+#endif
 	FILE* fp = fopen( filename, "rb" );
+#if defined(_MSC_VER)
 #pragma warning ( pop )
+#endif
 	if ( !fp ) {
 		SetError( ERROR_FILE_NOT_FOUND, filename, 0 );
 		return errorID;
@@ -1236,10 +1390,14 @@ int XMLDocument::LoadFile( FILE* fp )
 
 void XMLDocument::SaveFile( const char* filename )
 {
+#if defined(_MSC_VER)
 #pragma warning ( push )
 #pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
+#endif
 	FILE* fp = fopen( filename, "w" );
+#if defined(_MSC_VER)
 #pragma warning ( pop )
+#endif
 	XMLPrinter stream( fp );
 	Print( &stream );
 	fclose( fp );
@@ -1452,6 +1610,38 @@ void XMLPrinter::PushAttribute( const char* name, const char* value )
 }
 
 
+void XMLPrinter::PushAttribute( const char* name, int v )
+{
+	char buf[BUF_SIZE];
+	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v );	
+	PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, unsigned v )
+{
+	char buf[BUF_SIZE];
+	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%u", v );	
+	PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, bool v )
+{
+	char buf[BUF_SIZE];
+	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%d", v ? 1 : 0 );	
+	PushAttribute( name, buf );
+}
+
+
+void XMLPrinter::PushAttribute( const char* name, double v )
+{
+	char buf[BUF_SIZE];
+	TIXML_SNPRINTF( buf, BUF_SIZE-1, "%f", v );	
+	PushAttribute( name, buf );
+}
+
+
 void XMLPrinter::CloseElement()
 {
 	--depth;

+ 74 - 22
tinyxml2.h

@@ -21,7 +21,7 @@ must not be misrepresented as being the original software.
 distribution.
 */
 
-#ifndef TINYXML_INCLUDED
+#ifndef TINYXML2_INCLUDED
 #define TINYXML2_INCLUDED
 
 
@@ -30,8 +30,9 @@ distribution.
 #include <stdio.h>
 #include <memory.h>
 
-/* TODO: create main page description.
+/* 
    TODO: add 'lastAttribute' for faster parsing.
+   TODO: intern strings instead of allocation.
 */
 /*
 	gcc: g++ -Wall tinyxml2.cpp xmltest.cpp -o gccxmltest.exe
@@ -482,16 +483,16 @@ public:
 	XMLNode*	PreviousSibling()							{ return prev; }
 
 	/// Get the previous (left) sibling element of this node, with an opitionally supplied name.
-	const XMLNode*	PreviousSiblingElement( const char* value=0 ) const ;
-	XMLNode*	PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
+	const XMLElement*	PreviousSiblingElement( const char* value=0 ) const ;
+	XMLElement*	PreviousSiblingElement( const char* value=0 ) { return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->PreviousSiblingElement( value ) ); }
 	
 	/// Get the next (right) sibling node of this node.
 	const XMLNode*	NextSibling() const						{ return next; }
 	XMLNode*	NextSibling()								{ return next; }
 		
 	/// Get the next (right) sibling element of this node, with an opitionally supplied name.
-	const XMLNode*	NextSiblingElement( const char* value=0 ) const;
- 	XMLNode*	NextSiblingElement( const char* value=0 )	{ return const_cast<XMLNode*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
+	const XMLElement*	NextSiblingElement( const char* value=0 ) const;
+ 	XMLElement*	NextSiblingElement( const char* value=0 )	{ return const_cast<XMLElement*>(const_cast<const XMLNode*>(this)->NextSiblingElement( value ) ); }
 
 	/**
 		Add a child node as the last (right) child.
@@ -516,6 +517,25 @@ public:
 	*/
 	void DeleteChild( XMLNode* node );
 
+	/**
+		Make a copy of this node, but not its children.
+		You may pass in a Document pointer that will be
+		the owner of the new Node. If the 'document' is 
+		null, then the node returned will be allocated
+		from the current Document. (this->GetDocument())
+
+		Note: if called on a XMLDocument, this will return null.
+	*/
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const = 0;
+
+	/**
+		Test if 2 nodes are the same, but don't test children.
+		The 2 nodes do not need to be in the same Document.
+
+		Note: if called on a XMLDocument, this will return false.
+	*/
+	virtual bool ShallowEqual( const XMLNode* compare ) const = 0;
+
 	/** Accept a hierchical visit the nodes in the TinyXML DOM. Every node in the 
 		XML tree will be conditionally visited and the host will be called back
 		via the TiXmlVisitor interface.
@@ -593,6 +613,9 @@ public:
 	bool CData() const						{ return isCData; }
 
 	char* ParseDeep( char*, StrPair* endTag );
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+	virtual bool ShallowEqual( const XMLNode* compare ) const;
+
 
 protected:
 	XMLText( XMLDocument* doc )	: XMLNode( doc ), isCData( false )	{}
@@ -616,6 +639,8 @@ public:
 	virtual bool Accept( XMLVisitor* visitor ) const;
 
 	char* ParseDeep( char*, StrPair* endTag );
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+	virtual bool ShallowEqual( const XMLNode* compare ) const;
 
 protected:
 	XMLComment( XMLDocument* doc );
@@ -648,6 +673,8 @@ public:
 	virtual bool Accept( XMLVisitor* visitor ) const;
 
 	char* ParseDeep( char*, StrPair* endTag );
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+	virtual bool ShallowEqual( const XMLNode* compare ) const;
 
 protected:
 	XMLDeclaration( XMLDocument* doc );
@@ -674,6 +701,8 @@ public:
 	virtual bool Accept( XMLVisitor* visitor ) const;
 
 	char* ParseDeep( char*, StrPair* endTag );
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+	virtual bool ShallowEqual( const XMLNode* compare ) const;
 
 protected:
 	XMLUnknown( XMLDocument* doc );
@@ -685,6 +714,7 @@ protected:
 
 enum {
 	XML_NO_ERROR = 0,
+	XML_SUCCESS = 0,
 
 	NO_ATTRIBUTE,
 	WRONG_ATTRIBUTE_TYPE,
@@ -723,29 +753,29 @@ public:
 	    If the value isn't an integer, 0 will be returned. There is no error checking;
 		use QueryIntAttribute() if you need error checking.
 	*/
-	int		 IntAttribute() const				{ int i=0;		QueryIntAttribute( &i );		return i; }
+	int		 IntValue() const				{ int i=0;		QueryIntValue( &i );		return i; }
 	/// Query as an unsigned integer. See IntAttribute()
-	unsigned UnsignedAttribute() const			{ unsigned i=0; QueryUnsignedAttribute( &i );	return i; }
+	unsigned UnsignedValue() const			{ unsigned i=0; QueryUnsignedValue( &i );	return i; }
 	/// Query as a boolean. See IntAttribute()
-	bool	 BoolAttribute() const				{ bool b=false; QueryBoolAttribute( &b );		return b; }
+	bool	 BoolValue() const				{ bool b=false; QueryBoolValue( &b );		return b; }
 	/// Query as a double. See IntAttribute()
-	double 	 DoubleAttribute() const			{ double d=0;	QueryDoubleAttribute( &d );		return d; }
+	double 	 DoubleValue() const			{ double d=0;	QueryDoubleValue( &d );		return d; }
 	/// Query as a float. See IntAttribute()
-	float	 FloatAttribute() const				{ float f=0;	QueryFloatAttribute( &f );		return f; }
+	float	 FloatValue() const				{ float f=0;	QueryFloatValue( &f );		return f; }
 
 	/** QueryIntAttribute interprets the attribute as an integer, and returns the value
 		in the provided paremeter. The function will return XML_NO_ERROR on success,
 		and WRONG_ATTRIBUTE_TYPE if the conversion is not successful.
 	*/
-	int QueryIntAttribute( int* value ) const;
+	int QueryIntValue( int* value ) const;
 	/// See QueryIntAttribute
-	int QueryUnsignedAttribute( unsigned int* value ) const;
+	int QueryUnsignedValue( unsigned int* value ) const;
 	/// See QueryIntAttribute
-	int QueryBoolAttribute( bool* value ) const;
+	int QueryBoolValue( bool* value ) const;
 	/// See QueryIntAttribute
-	int QueryDoubleAttribute( double* value ) const;
+	int QueryDoubleValue( double* value ) const;
 	/// See QueryIntAttribute
-	int QueryFloatAttribute( float* value ) const;
+	int QueryFloatValue( float* value ) const;
 
 	/// Set the attribute to a string value.
 	void SetAttribute( const char* value );
@@ -829,15 +859,15 @@ public:
 		QueryIntAttribute( "foo", &value );		// if "foo" isn't found, value will still be 10
 		@endverbatim
 	*/
-	int QueryIntAttribute( const char* name, int* value ) const					{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntAttribute( value ); } 
+	int QueryIntAttribute( const char* name, int* value ) const					{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryIntValue( value ); } 
 	/// See QueryIntAttribute()
-	int QueryUnsignedAttribute( const char* name, unsigned int* value ) const	{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedAttribute( value ); }
+	int QueryUnsignedAttribute( const char* name, unsigned int* value ) const	{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryUnsignedValue( value ); }
 	/// See QueryIntAttribute()
-	int QueryBoolAttribute( const char* name, bool* value ) const				{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolAttribute( value ); }
+	int QueryBoolAttribute( const char* name, bool* value ) const				{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryBoolValue( value ); }
 	/// See QueryIntAttribute()
-	int QueryDoubleAttribute( const char* name, double* value ) const			{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleAttribute( value ); }
+	int QueryDoubleAttribute( const char* name, double* value ) const			{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryDoubleValue( value ); }
 	/// See QueryIntAttribute()
-	int QueryFloatAttribute( const char* name, float* value ) const				{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatAttribute( value ); }
+	int QueryFloatAttribute( const char* name, float* value ) const				{ const XMLAttribute* a = FindAttribute( name ); if ( !a ) return NO_ATTRIBUTE; return a->QueryFloatValue( value ); }
 
 	/// Sets the named attribute to value.
 	void SetAttribute( const char* name, const char* value )	{ XMLAttribute* a = FindOrCreateAttribute( name ); a->SetAttribute( value ); }
@@ -898,6 +928,8 @@ public:
 	};
 	int ClosingType() const { return closingType; }
 	char* ParseDeep( char* p, StrPair* endTag );
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const;
+	virtual bool ShallowEqual( const XMLNode* compare ) const;
 
 private:
 	XMLElement( XMLDocument* doc );
@@ -999,6 +1031,18 @@ public:
 		is managed by the Document.
 	*/
 	XMLText* NewText( const char* text );
+	/**
+		Create a new Declaration associated with
+		this Document. The memory for the object
+		is managed by the Document.
+	*/
+	XMLDeclaration* NewDeclaration( const char* text );
+	/**
+		Create a new Unknown associated with
+		this Document. The memory for the object
+		is managed by the Document.
+	*/
+	XMLUnknown* NewUnknown( const char* text );
 
 	/**
 		Delete a node associated with this documented.
@@ -1022,6 +1066,9 @@ public:
 	// internal
 	char* Identify( char* p, XMLNode** node );
 
+	virtual XMLNode* ShallowClone( XMLDocument* document ) const	{ return 0; }
+	virtual bool ShallowEqual( const XMLNode* compare ) const	{ return false; }
+
 private:
 	XMLDocument( const XMLDocument& );	// not supported
 	void operator=( const XMLDocument& );	// not supported
@@ -1101,6 +1148,10 @@ public:
 	void OpenElement( const char* name );
 	/// If streaming, add an attribute to an open element.
 	void PushAttribute( const char* name, const char* value );
+	void PushAttribute( const char* name, int value );
+	void PushAttribute( const char* name, unsigned value );
+	void PushAttribute( const char* name, bool value );
+	void PushAttribute( const char* name, double value );
 	/// If streaming, close the Element.
 	void CloseElement();
 
@@ -1142,7 +1193,8 @@ private:
 	int textDepth;
 
 	enum {
-		ENTITY_RANGE = 64
+		ENTITY_RANGE = 64,
+		BUF_SIZE = 200
 	};
 	bool entityFlag[ENTITY_RANGE];
 	bool restrictedEntityFlag[ENTITY_RANGE];

+ 34 - 0
xmltest.cpp

@@ -302,11 +302,15 @@ int main( int /*argc*/, const char* /*argv*/ )
 		int okay = 0;
 
 
+#if defined(_MSC_VER)
 #pragma warning ( push )
 #pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
+#endif
 		FILE* saved  = fopen( "utf8testout.xml", "r" );
 		FILE* verify = fopen( "utf8testverify.xml", "r" );
+#if defined(_MSC_VER)
 #pragma warning ( pop )
+#endif
 
 		if ( saved && verify )
 		{
@@ -419,20 +423,28 @@ int main( int /*argc*/, const char* /*argv*/ )
 
 		XMLTest( "Entity transformation: read. ", expected, context, true );
 
+#if defined(_MSC_VER)
 #pragma warning ( push )
 #pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
+#endif
 		FILE* textfile = fopen( "textfile.txt", "w" );
+#if defined(_MSC_VER)
 #pragma warning ( pop )
+#endif
 		if ( textfile )
 		{
 			XMLPrinter streamer( textfile );
 			psg->Accept( &streamer );
 			fclose( textfile );
 		}
+#if defined(_MSC_VER)
 #pragma warning ( push )
 #pragma warning ( disable : 4996 )		// Fail to see a compelling reason why this should be deprecated.
+#endif
 		textfile = fopen( "textfile.txt", "r" );
+#if defined(_MSC_VER)
 #pragma warning ( pop )
+#endif
 		TIXMLASSERT( textfile );
 		if ( textfile )
 		{
@@ -618,6 +630,28 @@ int main( int /*argc*/, const char* /*argv*/ )
 		XMLTest( "Infinite loop test.", true, true );
 	}
 #endif
+	{
+		const char* pub = "<?xml version='1.0'?> <element><sub/></element> <!--comment--> <!DOCTYPE>";
+		XMLDocument doc;
+		doc.Parse( pub );
+
+		XMLDocument clone;
+		for( const XMLNode* node=doc.FirstChild(); node; node=node->NextSibling() ) {
+			XMLNode* copy = node->ShallowClone( &clone );
+			clone.InsertEndChild( copy );
+		}
+
+		clone.Print();
+
+		int count=0;
+		const XMLNode* a=clone.FirstChild();
+		const XMLNode* b=doc.FirstChild();
+		for( ; a && b; a=a->NextSibling(), b=b->NextSibling() ) {
+			++count;
+			XMLTest( "Clone and Equal", true, a->ShallowEqual( b ));
+		}
+		XMLTest( "Clone and Equal", 4, count );
+	}
 
 	#if defined( _MSC_VER )
 		_CrtMemCheckpoint( &endMemState );