Upgrade to tinyxml2 7.0.1 (2018-11-17)
Test: builds, boots, tinyxml2 tests pass
Change-Id: Ia4ca2327925f9a678cbae6febdb5341151a1ec10
diff --git a/xmltest.cpp b/xmltest.cpp
index 91494ec..a0aaee7 100644
--- a/xmltest.cpp
+++ b/xmltest.cpp
@@ -34,7 +34,7 @@
pass = true;
else if ( !expected || !found )
pass = false;
- else
+ else
pass = !strcmp( expected, found );
if ( pass )
printf ("[pass]");
@@ -82,8 +82,15 @@
if ( !echo )
printf (" %s\n", testString);
- else
- printf (" %s [%d][%d]\n", testString, static_cast<int>(expected), static_cast<int>(found) );
+ else {
+ char expectedAsString[64];
+ XMLUtil::ToStr(expected, expectedAsString, sizeof(expectedAsString));
+
+ char foundAsString[64];
+ XMLUtil::ToStr(found, foundAsString, sizeof(foundAsString));
+
+ printf (" %s [%s][%s]\n", testString, expectedAsString, foundAsString );
+ }
if ( pass )
++gPass;
@@ -112,7 +119,7 @@
return doc.ErrorID();
}
-/** @page Example-1 Load an XML File
+/** @page Example_1 Load an XML File
* @dontinclude ./xmltest.cpp
* Basic XML file loading.
* The basic syntax to load an XML file from
@@ -121,7 +128,7 @@
* @skip example_1()
* @until }
*/
-
+
int example_2()
{
@@ -131,7 +138,7 @@
return doc.ErrorID();
}
-/** @page Example-2 Parse an XML from char buffer
+/** @page Example_2 Parse an XML from char buffer
* @dontinclude ./xmltest.cpp
* Basic XML string parsing.
* The basic syntax to parse an XML for
@@ -164,7 +171,7 @@
return doc.ErrorID();
}
-/** @page Example-3 Get information out of XML
+/** @page Example_3 Get information out of XML
@dontinclude ./xmltest.cpp
In this example, we navigate a simple XML
file, and read some interesting text. Note
@@ -172,8 +179,8 @@
checking; working code should check for null
pointers when walking an XML tree, or use
XMLHandle.
-
- (The XML is an excerpt from "dream.xml").
+
+ (The XML is an excerpt from "dream.xml").
@skip example_3()
@until </PLAY>";
@@ -192,7 +199,7 @@
</ul>
</ul>
- For this example, we want to print out the
+ For this example, we want to print out the
title of the play. The text of the title (what
we want) is child of the "TITLE" element which
is a child of the "PLAY" element.
@@ -212,8 +219,8 @@
Text is just another Node in the XML DOM. And in
fact you should be a little cautious with it, as
- text nodes can contain elements.
-
+ text nodes can contain elements.
+
@verbatim
Consider: A Midsummer Night's <b>Dream</b>
@endverbatim
@@ -225,7 +232,7 @@
Noting that here we use FirstChild() since we are
looking for XMLText, not an element, and ToText()
- is a cast from a Node to a XMLText.
+ is a cast from a Node to a XMLText.
*/
@@ -255,7 +262,7 @@
return !doc.Error() && ( v0 == v1 );
}
-/** @page Example-4 Read attributes and text information.
+/** @page Example_4 Read attributes and text information.
@dontinclude ./xmltest.cpp
There are fundamentally 2 ways of writing a key-value
@@ -269,7 +276,7 @@
@skip example_4()
@until "</information>";
- TinyXML-2 has accessors for both approaches.
+ TinyXML-2 has accessors for both approaches.
When using an attribute, you navigate to the XMLElement
with that attribute and use the QueryIntAttribute()
@@ -292,7 +299,7 @@
int main( int argc, const char ** argv )
{
- #if defined( _MSC_VER ) && defined( DEBUG )
+ #if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
_CrtMemCheckpoint( &startMemState );
// Enable MS Visual C++ debug heap memory leaks dump on exit
_CrtSetDbgFlag(_CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);
@@ -338,10 +345,10 @@
}
fclose( fp );
- XMLTest( "Example-1", 0, example_1() );
- XMLTest( "Example-2", 0, example_2() );
- XMLTest( "Example-3", 0, example_3() );
- XMLTest( "Example-4", true, example_4() );
+ XMLTest( "Example_1", 0, example_1() );
+ XMLTest( "Example_2", 0, example_2() );
+ XMLTest( "Example_3", 0, example_3() );
+ XMLTest( "Example_4", true, example_4() );
/* ------ Example 2: Lookup information. ---- */
@@ -535,7 +542,7 @@
XMLTest( "Dream", "xml version=\"1.0\"",
doc.FirstChild()->ToDeclaration()->Value() );
- XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() ? true : false );
+ XMLTest( "Dream", true, doc.FirstChild()->NextSibling()->ToUnknown() != 0 );
XMLTest( "Dream", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
doc.FirstChild()->NextSibling()->ToUnknown()->Value() );
XMLTest( "Dream", "And Robin shall restore amends.",
@@ -548,7 +555,7 @@
XMLTest( "Load dreamout.xml", false, doc2.Error() );
XMLTest( "Dream-out", "xml version=\"1.0\"",
doc2.FirstChild()->ToDeclaration()->Value() );
- XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() ? true : false );
+ XMLTest( "Dream-out", true, doc2.FirstChild()->NextSibling()->ToUnknown() != 0 );
XMLTest( "Dream-out", "DOCTYPE PLAY SYSTEM \"play.dtd\"",
doc2.FirstChild()->NextSibling()->ToUnknown()->Value() );
XMLTest( "Dream-out", "And Robin shall restore amends.",
@@ -567,6 +574,10 @@
XMLDocument doc;
doc.Parse( error );
XMLTest( "Bad XML", XML_ERROR_PARSING_ATTRIBUTE, doc.ErrorID() );
+ const char* errorStr = doc.ErrorStr();
+ XMLTest("Formatted error string",
+ "Error=XML_ERROR_PARSING_ATTRIBUTE ErrorID=7 (0x7) Line number=3: XMLElement name=wrong",
+ errorStr);
}
{
@@ -647,7 +658,7 @@
XMLTest( "Alternate query", true, iVal == iVal2 );
XMLTest( "Alternate query", true, dVal == dVal2 );
XMLTest( "Alternate query", true, iVal == ele->IntAttribute("int") );
- XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
+ XMLTest( "Alternate query", true, dVal == ele->DoubleAttribute("double") );
}
{
@@ -762,7 +773,7 @@
doc.Parse( str );
XMLTest( "Text in nested element", false, doc.Error() );
element = doc.RootElement();
-
+
element->SetText("wolves");
XMLTest( "SetText() prefix to nested non-text children.", "wolves", element->GetText() );
@@ -770,7 +781,7 @@
doc.Parse( str );
XMLTest( "Empty self-closed element round 2", false, doc.Error() );
element = doc.RootElement();
-
+
element->SetText( "str" );
XMLTest( "SetText types", "str", element->GetText() );
@@ -827,6 +838,14 @@
XMLTest("Attribute: unsigned", (int)XML_SUCCESS, queryResult, true);
XMLTest("Attribute: unsigned", unsigned(100), v, true);
}
+ {
+ const char* v = "failed";
+ XMLError queryResult = element->QueryStringAttribute("not-attrib", &v);
+ XMLTest("Attribute: string default", false, queryResult == XML_SUCCESS);
+ queryResult = element->QueryStringAttribute("attrib", &v);
+ XMLTest("Attribute: string", XML_SUCCESS, queryResult, true);
+ XMLTest("Attribute: string", "100", v);
+ }
XMLTest("Attribute: unsigned", unsigned(100), element->UnsignedAttribute("attrib"), true);
}
{
@@ -1160,6 +1179,12 @@
XMLDocument doc;
doc.Parse( str );
XMLTest( "Empty document error", XML_ERROR_EMPTY_DOCUMENT, doc.ErrorID() );
+
+ // But be sure there is an error string!
+ const char* errorStr = doc.ErrorStr();
+ XMLTest("Error string should be set",
+ "Error=XML_ERROR_EMPTY_DOCUMENT ErrorID=13 (0xd) Line number=0",
+ errorStr);
}
{
@@ -1452,28 +1477,31 @@
static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
XMLDocument doc;
doc.Parse( xml );
- XMLTest( "Parse element with attribute and nested element round 1", false, doc.Error() );
+ XMLTest( "Handle, parse element with attribute and nested element", false, doc.Error() );
- XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
- XMLTest( "Handle, success, mutable", "sub", ele->Value() );
+ {
+ XMLElement* ele = XMLHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
+ XMLTest( "Handle, non-const, element is found", true, ele != 0 );
+ XMLTest( "Handle, non-const, element name matches", "sub", ele->Value() );
+ }
- XMLHandle docH( doc );
- ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
- XMLTest( "Handle, dne, mutable", true, ele == 0 );
- }
+ {
+ XMLHandle docH( doc );
+ XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
+ XMLTest( "Handle, non-const, element not found", true, ele == 0 );
+ }
- {
- static const char* xml = "<element attrib='bar'><sub>Text</sub></element>";
- XMLDocument doc;
- doc.Parse( xml );
- XMLTest( "Parse element with attribute and nested element round 2", false, doc.Error() );
- XMLConstHandle docH( doc );
+ {
+ const XMLElement* ele = XMLConstHandle( doc ).FirstChildElement( "element" ).FirstChild().ToElement();
+ XMLTest( "Handle, const, element is found", true, ele != 0 );
+ XMLTest( "Handle, const, element name matches", "sub", ele->Value() );
+ }
- const XMLElement* ele = docH.FirstChildElement( "element" ).FirstChild().ToElement();
- XMLTest( "Handle, success, const", "sub", ele->Value() );
-
- ele = docH.FirstChildElement( "none" ).FirstChildElement( "element" ).ToElement();
- XMLTest( "Handle, dne, const", true, ele == 0 );
+ {
+ XMLConstHandle docH( doc );
+ const XMLElement* ele = docH.FirstChildElement( "noSuchElement" ).FirstChildElement( "element" ).ToElement();
+ XMLTest( "Handle, const, element not found", true, ele == 0 );
+ }
}
{
// Default Declaration & BOM
@@ -1546,14 +1574,14 @@
doc.Parse( xml );
XMLTest( "Non-alpha element lead letter parses.", false, doc.Error() );
}
-
+
{
const char* xml = "<element _attr1=\"foo\" :attr2=\"bar\"></element>";
XMLDocument doc;
doc.Parse( xml );
XMLTest("Non-alpha attribute lead character parses.", false, doc.Error());
}
-
+
{
const char* xml = "<3lement></3lement>";
XMLDocument doc;
@@ -1589,7 +1617,7 @@
doc.Clear();
XMLTest( "No error after Clear()", false, doc.Error() );
}
-
+
// ----------- Whitespace ------------
{
const char* xml = "<element>"
@@ -1761,6 +1789,7 @@
XMLTest( "Insertion with removal parse round 4", false, doc.Error() );
subtree = doc.RootElement()->FirstChildElement("one")->FirstChildElement("subtree");
two = doc.RootElement()->FirstChildElement("two");
+ XMLTest("<two> is the last child at root level", true, two == doc.RootElement()->LastChildElement());
doc.RootElement()->InsertEndChild(subtree);
XMLPrinter printer4(0, true);
acceptResult = doc.Accept(&printer4);
@@ -1788,7 +1817,7 @@
}
#if 1
- // the question being explored is what kind of print to use:
+ // the question being explored is what kind of print to use:
// https://github.com/leethomason/tinyxml2/issues/63
{
//const char* xml = "<element attrA='123456789.123456789' attrB='1.001e9' attrC='1.0e-10' attrD='1001000000.000000' attrE='0.1234567890123456789'/>";
@@ -1815,14 +1844,14 @@
/* The result of this test is platform, compiler, and library version dependent. :("
XMLPrinter printer;
doc.Print( &printer );
- XMLTest( "Float and double formatting.",
+ XMLTest( "Float and double formatting.",
"<element attrA-f64=\"123456789.12345679\" attrB-f64=\"1001000000\" attrC-f64=\"1e+20\" attrD-f64=\"0.123456789\" attrA-f32=\"1.2345679e+08\" attrB-f32=\"1.001e+09\" attrC-f32=\"1e+20\" attrD-f32=\"0.12345679\"/>\n",
- printer.CStr(),
+ printer.CStr(),
true );
*/
}
#endif
-
+
{
// Issue #184
// If it doesn't assert, it passes. Caused by objects
@@ -1841,9 +1870,9 @@
doc.Clear();
}
}
-
+
{
- // If this doesn't assert in DEBUG, all is well.
+ // If this doesn't assert in TINYXML2_DEBUG, all is well.
tinyxml2::XMLDocument doc;
tinyxml2::XMLElement *pRoot = doc.NewElement("Root");
doc.DeleteNode(pRoot);
@@ -1858,7 +1887,7 @@
}
{
- // If this doesn't assert in DEBUG, all is well.
+ // If this doesn't assert in TINYXML2_DEBUG, all is well.
XMLDocument doc;
XMLElement* unlinkedRoot = doc.NewElement( "Root" );
XMLElement* linkedRoot = doc.NewElement( "Root" );
@@ -1868,7 +1897,7 @@
}
{
- // Should not assert in DEBUG
+ // Should not assert in TINYXML2_DEBUG
XMLPrinter printer;
}
@@ -1883,7 +1912,7 @@
doc.Print( &printer );
}
{
- // Issue 299. Can print elements that are not linked in.
+ // Issue 299. Can print elements that are not linked in.
// Will crash if issue not fixed.
XMLDocument doc;
XMLElement* newElement = doc.NewElement( "printme" );
@@ -1936,7 +1965,7 @@
doc.Parse(xml1);
XMLTest("Test that the second declaration is allowed", false, doc.Error() );
doc.Parse(xml2);
- XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
+ XMLTest("Test that declaration after self-closed child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
doc.Parse(xml3);
XMLTest("Test that declaration after a child is not allowed", XML_ERROR_PARSING_DECLARATION, doc.ErrorID() );
doc.Parse(xml4);
@@ -1946,7 +1975,7 @@
{
// No matter - before or after successfully parsing a text -
// calling XMLDocument::Value() used to cause an assert in debug.
- // Null must be retured.
+ // Null must be returned.
const char* validXml = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
"<first />"
"<second />";
@@ -1963,13 +1992,30 @@
for( int i = 0; i < XML_ERROR_COUNT; i++ ) {
const XMLError error = static_cast<XMLError>(i);
const char* name = XMLDocument::ErrorIDToName(error);
- XMLTest( "ErrorName() after ClearError()", true, name != 0 );
- XMLTest( "ErrorName() after ClearError()", true, strlen(name) > 0 );
+ XMLTest( "ErrorName() not null after ClearError()", true, name != 0 );
+ if( name == 0 ) {
+ // passing null pointer into strlen() is undefined behavior, so
+ // compiler is allowed to optimise away the null test above if it's
+ // as reachable as the strlen() call
+ continue;
+ }
+ XMLTest( "ErrorName() not empty after ClearError()", true, strlen(name) > 0 );
}
}
{
- // Evil memory leaks.
+ const char* html("<!DOCTYPE html><html><body><p>test</p><p><br/></p></body></html>");
+ XMLDocument doc(false);
+ doc.Parse(html);
+
+ XMLPrinter printer(0, true);
+ doc.Print(&printer);
+
+ XMLTest(html, html, printer.CStr());
+ }
+
+ {
+ // Evil memory leaks.
// If an XMLElement (etc) is allocated via NewElement() (etc.)
// and NOT added to the XMLDocument, what happens?
//
@@ -1999,6 +2045,32 @@
}
{
+ // Bad bad crash. Parsing error results in stack overflow, if uncaught.
+ const char* TESTS[] = {
+ "./resources/xmltest-5330.xml",
+ "./resources/xmltest-4636783552757760.xml",
+ "./resources/xmltest-5720541257269248.xml",
+ 0
+ };
+ for (int i=0; TESTS[i]; ++i) {
+ XMLDocument doc;
+ doc.LoadFile(TESTS[i]);
+ XMLTest("Stack overflow prevented.", XML_ELEMENT_DEPTH_EXCEEDED, doc.ErrorID());
+ }
+ }
+ {
+ const char* TESTS[] = {
+ "./resources/xmltest-5662204197076992.xml", // Security-level performance issue.
+ 0
+ };
+ for (int i = 0; TESTS[i]; ++i) {
+ XMLDocument doc;
+ doc.LoadFile(TESTS[i]);
+ // Need only not crash / lock up.
+ XMLTest("Fuzz attack prevented.", true, true);
+ }
+ }
+ {
// Crashing reported via email.
const char* xml =
"<playlist id='playlist1'>"
@@ -2052,7 +2124,7 @@
XMLTest("Crash bug parsing - Accept()", true, acceptResult);
printf("%s\n", printer.CStr());
- // No test; it only need to not crash.
+ // No test; it only need to not crash.
// Still, wrap it up with a sanity check
int nProperty = 0;
for (const XMLElement* p = playlist->FirstChildElement("property"); p; p = p->NextSiblingElement("property")) {
@@ -2248,7 +2320,7 @@
delete[] mem;
static const char* note =
-#ifdef DEBUG
+#ifdef TINYXML2_DEBUG
"DEBUG";
#else
"Release";
@@ -2262,7 +2334,7 @@
printf("\nParsing dream.xml (%s): %.3f milli-seconds\n", note, duration);
}
-#if defined( _MSC_VER ) && defined( DEBUG )
+#if defined( _MSC_VER ) && defined( TINYXML2_DEBUG )
{
_CrtMemCheckpoint( &endMemState );