Patching up incorrect boilerplate code. Added clone/equal methods.
diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index c721a61..bb491de 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -402,12 +402,15 @@
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::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 @@
}
+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 @@
}
+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 @@
}
+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 @@
}
+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 @@
}
-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::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::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::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::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 @@
}
+
+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 @@
}
}
return visitor->VisitExit( *this );
-
}
+
// --------- XMLDocument ----------- //
XMLDocument::XMLDocument() :
XMLNode( 0 ),
@@ -1185,15 +1317,37 @@
}
+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 @@
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, 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;
diff --git a/tinyxml2.h b/tinyxml2.h
index d0d0a83..81f1ddd 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -21,7 +21,7 @@
distribution.
*/
-#ifndef TINYXML_INCLUDED
+#ifndef TINYXML2_INCLUDED
#define TINYXML2_INCLUDED
@@ -30,8 +30,9 @@
#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 @@
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 @@
*/
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 @@
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 @@
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 @@
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 @@
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 @@
enum {
XML_NO_ERROR = 0,
+ XML_SUCCESS = 0,
NO_ATTRIBUTE,
WRONG_ATTRIBUTE_TYPE,
@@ -723,29 +753,29 @@
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 @@
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 @@
};
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 @@
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 @@
// 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 @@
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 @@
int textDepth;
enum {
- ENTITY_RANGE = 64
+ ENTITY_RANGE = 64,
+ BUF_SIZE = 200
};
bool entityFlag[ENTITY_RANGE];
bool restrictedEntityFlag[ENTITY_RANGE];
diff --git a/xmltest.cpp b/xmltest.cpp
index 9f61a6b..b3ffc2f 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -302,11 +302,15 @@
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 @@
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 @@
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 );