diff --git a/tinyxml2.cpp b/tinyxml2.cpp index c721a61..bb491de 100644 --- a/tinyxml2.cpp +++ b/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; diff --git a/tinyxml2.h b/tinyxml2.h index d0d0a83..81f1ddd 100644 --- a/tinyxml2.h +++ b/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 #include -/* 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(const_cast(this)->PreviousSiblingElement( value ) ); } + const XMLElement* PreviousSiblingElement( const char* value=0 ) const ; + XMLElement* PreviousSiblingElement( const char* value=0 ) { return const_cast(const_cast(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(const_cast(this)->NextSiblingElement( value ) ); } + const XMLElement* NextSiblingElement( const char* value=0 ) const; + XMLElement* NextSiblingElement( const char* value=0 ) { return const_cast(const_cast(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]; diff --git a/xmltest.cpp b/xmltest.cpp index 9f61a6b..b3ffc2f 100644 --- a/xmltest.cpp +++ b/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 = " "; + 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 );