diff --git a/tinyxml2.cpp b/tinyxml2.cpp
index 8a4fa95..1d68cb0 100644
--- a/tinyxml2.cpp
+++ b/tinyxml2.cpp
@@ -592,8 +592,11 @@ char* XMLNode::ParseDeep( char* p )
p = document->Identify( p, &node );
if ( p && node ) {
p = node->ParseDeep( p );
- // FIXME: is it the correct closing element?
+
if ( node->IsClosingElement() ) {
+ if ( !XMLUtil::StringEqual( Value(), node->Value() )) {
+ document->SetError( ERROR_MISMATCHED_ELEMENT, Value(), 0 );
+ }
DELETE_NODE( node );
return p;
}
@@ -953,7 +956,7 @@ char* XMLElement::ParseAttributes( char* p, bool* closedElement )
attrib->memPool = &document->attributePool;
p = attrib->ParseDeep( p );
- if ( !p ) {
+ if ( !p || Attribute( attrib->Name() ) ) {
DELETE_ATTRIBUTE( attrib );
document->SetError( ERROR_PARSING_ATTRIBUTE, start, p );
return 0;
@@ -1134,7 +1137,8 @@ int XMLDocument::LoadFile( FILE* fp )
p = XMLUtil::SkipWhiteSpace( p );
p = XMLUtil::ReadBOM( p, &writeBOM );
if ( !p || !*p ) {
- return 0; // correctly parse an empty string?
+ SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return errorID;
}
ParseDeep( charBuffer + (p-charBuffer) );
@@ -1157,12 +1161,14 @@ int XMLDocument::Parse( const char* p )
InitDocument();
if ( !p || !*p ) {
- return true; // correctly parse an empty string?
+ SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return errorID;
}
p = XMLUtil::SkipWhiteSpace( p );
p = XMLUtil::ReadBOM( p, &writeBOM );
if ( !p || !*p ) {
- return true; // correctly parse an empty string?
+ SetError( ERROR_EMPTY_DOCUMENT, 0, 0 );
+ return errorID;
}
size_t len = strlen( p );
@@ -1180,9 +1186,6 @@ void XMLDocument::Print( XMLStreamer* streamer )
XMLStreamer stdStreamer( stdout );
if ( !streamer )
streamer = &stdStreamer;
- //for( XMLNode* node = firstChild; node; node=node->next ) {
- // node->Print( streamer );
- //}
Accept( streamer );
}
@@ -1477,7 +1480,7 @@ bool XMLStreamer::VisitExit( const XMLElement& element )
bool XMLStreamer::Visit( const XMLText& text )
{
- PushText( text.Value() );
+ PushText( text.Value(), text.CData() );
return true;
}
diff --git a/tinyxml2.h b/tinyxml2.h
index a1f7603..7185472 100644
--- a/tinyxml2.h
+++ b/tinyxml2.h
@@ -375,8 +375,8 @@ public:
static const char* ReadBOM( const char* p, bool* hasBOM );
// p is the starting location,
// the UTF-8 value of the entity will be placed in value, and length filled in.
- static const char* GetCharacterRef( const char* p, char* value, int* length );
- static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
+ static const char* GetCharacterRef( const char* p, char* value, int* length );
+ static void ConvertUTF32ToUTF8( unsigned long input, char* output, int* length );
};
@@ -587,7 +587,9 @@ enum {
ERROR_PARSING_CDATA,
ERROR_PARSING_COMMENT,
ERROR_PARSING_DECLARATION,
- ERROR_PARSING_UNKNOWN
+ ERROR_PARSING_UNKNOWN,
+ ERROR_EMPTY_DOCUMENT,
+ ERROR_MISMATCHED_ELEMENT
};
@@ -714,6 +716,8 @@ public:
void SaveFile( const char* filename );
bool HasBOM() const { return writeBOM; }
+ XMLElement* RootElement() { return FirstChildElement(); }
+ const XMLElement* RootElement() const { return FirstChildElement(); }
void Print( XMLStreamer* streamer=0 );
virtual bool Accept( XMLVisitor* visitor ) const;
diff --git a/xmltest.cpp b/xmltest.cpp
index 95f9738..d244efa 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -103,21 +103,7 @@ int main( int argc, const char* argv )
#if defined( WIN32 )
_CrtMemCheckpoint( &startMemState );
#endif
-#ifndef DREAM_ONLY
-#if 0
- {
- static const char* test = "";
- XMLDocument doc;
- doc.Parse( test );
- doc.Print();
- }
-#endif
-#if 0
{
static const char* test[] = { "",
"",
@@ -143,8 +129,19 @@ int main( int argc, const char* argv )
printf( "----------------------------------------------\n" );
}
}
-#endif
-#if 0
+
+ {
+ static const char* test = "";
+
+ XMLDocument doc;
+ doc.Parse( test );
+ doc.Print();
+ }
+
{
static const char* test = "Text before.";
XMLDocument doc;
@@ -160,9 +157,7 @@ int main( int argc, const char* argv )
doc->Parse( test );
delete doc;
}
-#endif
{
-#if 0
// Test: Programmatic DOM
// Build:
//
@@ -211,11 +206,8 @@ int main( int argc, const char* argv )
printf( "%s", streamer.CStr() );
delete doc;
-#endif
}
-#endif
{
-#if 0
// Test: Dream
// XML1 : 1,187,569 bytes in 31,209 allocations
// XML2 : 469,073 bytes in 323 allocations
@@ -246,11 +238,8 @@ int main( int argc, const char* argv )
XMLTest( "Dream-out", "And Robin shall restore amends.",
doc2.LastChild()->LastChild()->LastChild()->LastChild()->LastChildElement()->GetText() );
-#endif
//gNewTotal = gNew - newStart;
}
-
-#if 0
{
const char* error = "\n"
"\n"
@@ -311,7 +300,6 @@ int main( int argc, const char* argv )
XMLTest( "Attribute round trip. double.", -1, (int)dVal );
}
-#endif
{
XMLDocument doc;
doc.LoadFile( "utf8test.xml" );
@@ -370,8 +358,284 @@ int main( int argc, const char* argv )
XMLTest( "UTF-8: Verified multi-language round trip.", 1, okay );
}
+ // --------GetText()-----------
+ {
+ const char* str = "This is text";
+ XMLDocument doc;
+ doc.Parse( str );
+ const XMLElement* element = doc.RootElement();
+
+ XMLTest( "GetText() normal use.", "This is text", element->GetText() );
+
+ str = "This is text";
+ doc.Parse( str );
+ element = doc.RootElement();
+
+ XMLTest( "GetText() contained element.", element->GetText() == 0, true );
+ }
-#if defined( WIN32 )
+
+ // ---------- CDATA ---------------
+ {
+ const char* str = ""
+ " the rules!\n"
+ "...since I make symbolic puns"
+ "]]>"
+ "";
+ XMLDocument doc;
+ doc.Parse( str );
+ doc.Print();
+
+ XMLTest( "CDATA parse.", doc.FirstChildElement()->FirstChild()->Value(),
+ "I am > the rules!\n...since I make symbolic puns",
+ false );
+ }
+
+ // ----------- CDATA -------------
+ {
+ const char* str = ""
+ "I am > the rules!\n"
+ "...since I make symbolic puns"
+ "]]>"
+ "";
+ XMLDocument doc;
+ doc.Parse( str );
+ doc.Print();
+
+ XMLTest( "CDATA parse. [ tixml1:1480107 ]", doc.FirstChildElement()->FirstChild()->Value(),
+ "I am > the rules!\n...since I make symbolic puns",
+ false );
+ }
+
+ // InsertAfterChild causes crash.
+ {
+ // InsertBeforeChild and InsertAfterChild causes crash.
+ XMLDocument doc;
+ XMLElement* parent = doc.NewElement( "Parent" );
+ doc.InsertFirstChild( parent );
+
+ XMLElement* childText0 = doc.NewElement( "childText0" );
+ XMLElement* childText1 = doc.NewElement( "childText1" );
+
+ XMLNode* childNode0 = parent->InsertEndChild( childText0 );
+ XMLNode* childNode1 = parent->InsertAfterChild( childNode0, childText1 );
+
+ XMLTest( "Test InsertAfterChild on empty node. ", ( childNode1 == parent->LastChild() ), true );
+ }
+
+ {
+ // Entities not being written correctly.
+ // From Lynn Allen
+
+ const char* passages =
+ ""
+ ""
+ " "
+ "";
+
+ XMLDocument doc;
+ doc.Parse( passages );
+ XMLElement* psg = doc.RootElement()->FirstChildElement();
+ const char* context = psg->Attribute( "context" );
+ const char* expected = "Line 5 has \"quotation marks\" and 'apostrophe marks'. It also has <, >, and &, as well as a fake copyright \xC2\xA9.";
+
+ XMLTest( "Entity transformation: read. ", expected, context, true );
+
+ FILE* textfile = fopen( "textfile.txt", "w" );
+ if ( textfile )
+ {
+ XMLStreamer streamer( textfile );
+ psg->Accept( &streamer );
+ fclose( textfile );
+ }
+ textfile = fopen( "textfile.txt", "r" );
+ TIXMLASSERT( textfile );
+ if ( textfile )
+ {
+ char buf[ 1024 ];
+ fgets( buf, 1024, textfile );
+ XMLTest( "Entity transformation: write. ",
+ "\n",
+ buf, false );
+ }
+ fclose( textfile );
+ }
+
+ {
+ const char* test = "";
+
+ XMLDocument doc;
+ doc.Parse( test );
+ XMLTest( "dot in names", doc.Error(), 0);
+ XMLTest( "dot in names", doc.FirstChildElement()->Name(), "a.elem" );
+ XMLTest( "dot in names", doc.FirstChildElement()->Attribute( "xmi.version" ), "2.0" );
+ }
+
+ {
+ const char* test = "1.1 Start easy ignore fin thickness
";
+
+ XMLDocument doc;
+ doc.Parse( test );
+
+ XMLText* text = doc.FirstChildElement()->FirstChildElement()->FirstChild()->ToText();
+ XMLTest( "Entity with one digit.",
+ text->Value(), "1.1 Start easy ignore fin thickness\n",
+ false );
+ }
+
+ {
+ // DOCTYPE not preserved (950171)
+ //
+ const char* doctype =
+ ""
+ ""
+ ""
+ ""
+ "";
+
+ XMLDocument doc;
+ doc.Parse( doctype );
+ doc.SaveFile( "test7.xml" );
+ doc.DeleteChild( doc.RootElement() );
+ doc.LoadFile( "test7.xml" );
+ doc.Print();
+
+ const XMLUnknown* decl = doc.FirstChild()->NextSibling()->ToUnknown();
+ XMLTest( "Correct value of unknown.", "DOCTYPE PLAY SYSTEM 'play.dtd'", decl->Value() );
+
+ }
+
+ {
+ // Comments do not stream out correctly.
+ const char* doctype =
+ "";
+ XMLDocument doc;
+ doc.Parse( doctype );
+
+ XMLComment* comment = doc.FirstChild()->ToComment();
+
+ XMLTest( "Comment formatting.", " Somewhat ", comment->Value() );
+ }
+ {
+ // Double attributes
+ const char* doctype = "";
+
+ XMLDocument doc;
+ doc.Parse( doctype );
+
+ XMLTest( "Parsing repeated attributes.", ERROR_PARSING_ATTRIBUTE, doc.ErrorID() ); // is an error to tinyxml (didn't use to be, but caused issues)
+ }
+
+ {
+ // Embedded null in stream.
+ const char* doctype = "";
+
+ XMLDocument doc;
+ doc.Parse( doctype );
+ XMLTest( "Embedded null throws error.", true, doc.Error() );
+ }
+
+ {
+ // Empty documents should return TIXML_ERROR_PARSING_EMPTY, bug 1070717
+ const char* str = " ";
+ XMLDocument doc;
+ doc.Parse( str );
+ XMLTest( "Empty document error", ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
+ }
+
+ {
+ // Low entities
+ XMLDocument doc;
+ doc.Parse( "" );
+ const char result[] = { 0x0e, 0 };
+ XMLTest( "Low entities.", doc.FirstChildElement()->GetText(), result );
+ doc.Print();
+ }
+
+ {
+ // Attribute values with trailing quotes not handled correctly
+ XMLDocument doc;
+ doc.Parse( "" );
+ XMLTest( "Throw error with bad end quotes.", doc.Error(), true );
+ }
+
+ {
+ // [ 1663758 ] Failure to report error on bad XML
+ XMLDocument xml;
+ xml.Parse("");
+ XMLTest("Missing end tag at end of input", xml.Error(), true);
+ xml.Parse(" ");
+ XMLTest("Missing end tag with trailing whitespace", xml.Error(), true);
+ xml.Parse("");
+ XMLTest("Mismatched tags", xml.ErrorID(), ERROR_MISMATCHED_ELEMENT);
+ }
+
+
+ {
+ // [ 1475201 ] TinyXML parses entities in comments
+ XMLDocument xml;
+ xml.Parse(""
+ "" );
+
+ XMLNode* e0 = xml.FirstChild();
+ XMLNode* e1 = e0->NextSibling();
+ XMLComment* c0 = e0->ToComment();
+ XMLComment* c1 = e1->ToComment();
+
+ XMLTest( "Comments ignore entities.", " declarations for & ", c0->Value(), true );
+ XMLTest( "Comments ignore entities.", " far & away ", c1->Value(), true );
+ }
+
+ {
+ XMLDocument xml;
+ xml.Parse( ""
+ ""
+ ""
+ ""
+ "" );
+ int count = 0;
+
+ for( XMLNode* ele = xml.FirstChildElement( "Parent" )->FirstChild();
+ ele;
+ ele = ele->NextSibling() )
+ {
+ ++count;
+ }
+
+ XMLTest( "Comments iterate correctly.", 3, count );
+ }
+
+ {
+ // trying to repro ]1874301]. If it doesn't go into an infinite loop, all is well.
+ unsigned char buf[] = " " );
+ XMLTest( "Handle end tag whitespace", false, xml.Error() );
+ }
+
+ {
+ // This one must not result in an infinite loop
+ XMLDocument xml;
+ xml.Parse( "loop" );
+ XMLTest( "Infinite loop test.", true, true );
+ }
+
+ #if defined( WIN32 )
_CrtMemCheckpoint( &endMemState );
//_CrtMemDumpStatistics( &endMemState );